Compare commits
10 Commits
2ca84ab2c3
...
5b7eabe96f
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b7eabe96f | |||
| df8d7164bb | |||
| 2f3cab6310 | |||
| 4b5c9d6711 | |||
| 68053b61b5 | |||
| 637e01646a | |||
| aee55d8d2c | |||
| 57395ff719 | |||
| fe5cd908f8 | |||
| f6688acfc7 |
5
Makefile
5
Makefile
@@ -1,4 +1,5 @@
|
|||||||
CC=clang
|
CC=clang
|
||||||
|
DFLAGS=
|
||||||
FLAGS=-Wall -Wextra -g
|
FLAGS=-Wall -Wextra -g
|
||||||
LIBS=-I/opt/homebrew/include -I/opt/homebrew/include/SDL2 -L/opt/homebrew/lib -lSDL2 -lSDL2_ttf
|
LIBS=-I/opt/homebrew/include -I/opt/homebrew/include/SDL2 -L/opt/homebrew/lib -lSDL2 -lSDL2_ttf
|
||||||
|
|
||||||
@@ -6,8 +7,8 @@ all: clean build
|
|||||||
|
|
||||||
build: pingpong
|
build: pingpong
|
||||||
|
|
||||||
pingpong: pingpong.c
|
pingpong: pingpong.c queue.c
|
||||||
${CC} ${FLAGS} ${LIBS} pingpong.c -o pingpong
|
${CC} ${FLAGS} ${DFLAGS} ${LIBS} pingpong.c queue.c -o pingpong
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf pingpong.dSYM pingpong
|
rm -rf pingpong.dSYM pingpong
|
||||||
|
|||||||
34
README.md
34
README.md
@@ -1,8 +1,38 @@
|
|||||||
|

|
||||||
|
|
||||||
# Build
|
# Build
|
||||||
For MacOS:
|
For MacOS:
|
||||||
`make`
|
|
||||||
|
|
||||||
|
```
|
||||||
|
make
|
||||||
|
```
|
||||||
For other platforms modify flags in the Makefile.
|
For other platforms modify flags in the Makefile.
|
||||||
|
|
||||||
|
# FPS
|
||||||
|
Cap FPS:
|
||||||
|
|
||||||
|
```
|
||||||
|
make DFLAGS="-D FPS=30"
|
||||||
|
```
|
||||||
|
|
||||||
|
Display FPS:
|
||||||
|
|
||||||
|
```
|
||||||
|
make DFLAGS="-D ENABLE_FPS=1"
|
||||||
|
```
|
||||||
|
|
||||||
|
# Embed Fonts
|
||||||
|
|
||||||
|
```
|
||||||
|
xxd -i iosevka-bold.ttf > iosevka_bold.h
|
||||||
|
make DFLAGS="-D EMBED_FONTS=1"
|
||||||
|
```
|
||||||
|
|
||||||
# Run
|
# Run
|
||||||
`./pingpong`
|
```
|
||||||
|
./pingpong
|
||||||
|
```
|
||||||
|
|
||||||
|
# Iosevka Font
|
||||||
|
[typeof.net/Iosevka](https://typeof.net/Iosevka/)
|
||||||
|
[LICENSE](https://github.com/be5invis/Iosevka/blob/main/LICENSE.md)
|
||||||
|
|||||||
424
pingpong.c
424
pingpong.c
@@ -1,114 +1,17 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#include <SDL_ttf.h>
|
#include <SDL_ttf.h>
|
||||||
|
|
||||||
#define TRUE 1
|
#include "types.h"
|
||||||
#define FALSE 0
|
#include "settings.h"
|
||||||
|
#include "queue.h"
|
||||||
|
|
||||||
#define WINDOW_WIDTH 800
|
#if EMBED_FONTS
|
||||||
#define WINDOW_HEIGHT 600
|
#include "iosevka_bold.h"
|
||||||
|
#endif
|
||||||
#define FPS 120
|
|
||||||
#define TARGET_FRAME_TIME (1000 / FPS)
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
float x;
|
|
||||||
float y;
|
|
||||||
} vector2;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
float r;
|
|
||||||
float g;
|
|
||||||
float b;
|
|
||||||
} vector3;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
float r;
|
|
||||||
float g;
|
|
||||||
float b;
|
|
||||||
float a;
|
|
||||||
} vector4;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
float w;
|
|
||||||
float h;
|
|
||||||
} rect;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
vector2 point;
|
|
||||||
vector2 velocity;
|
|
||||||
vector2 dimension;
|
|
||||||
vector4 color;
|
|
||||||
} particle;
|
|
||||||
|
|
||||||
struct node {
|
|
||||||
struct node *next;
|
|
||||||
particle data;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
struct node *first;
|
|
||||||
struct node *last;
|
|
||||||
} queue;
|
|
||||||
|
|
||||||
void qinit(queue *item)
|
|
||||||
{
|
|
||||||
item->first = NULL;
|
|
||||||
item->last = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void qput(queue *item, particle data)
|
|
||||||
{
|
|
||||||
if(!item->first) {
|
|
||||||
item->first = malloc(sizeof(struct node));
|
|
||||||
item->last = item->first;
|
|
||||||
} else {
|
|
||||||
item->last->next = malloc(sizeof(struct node));
|
|
||||||
item->last = item->last->next;
|
|
||||||
}
|
|
||||||
item->last->data = data;
|
|
||||||
item->last->next = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void qget(queue *item, particle *data)
|
|
||||||
{
|
|
||||||
if(data)
|
|
||||||
*data = item->first->data;
|
|
||||||
|
|
||||||
struct node *tmp = item->first;
|
|
||||||
item->first = item->first->next;
|
|
||||||
if(!item->first)
|
|
||||||
item->last = NULL;
|
|
||||||
free(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
int qempty(queue *item)
|
|
||||||
{
|
|
||||||
return !item->first;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int is_running;
|
|
||||||
int last_frame_time;
|
|
||||||
|
|
||||||
struct ball {
|
|
||||||
vector2 point;
|
|
||||||
vector2 velocity;
|
|
||||||
vector2 dimension;
|
|
||||||
} ball;
|
|
||||||
|
|
||||||
struct player {
|
|
||||||
vector2 point;
|
|
||||||
vector2 dimension;
|
|
||||||
float vy;
|
|
||||||
int score;
|
|
||||||
int up;
|
|
||||||
int down;
|
|
||||||
} player_one, player_two;
|
|
||||||
|
|
||||||
queue particles;
|
|
||||||
} game_state;
|
|
||||||
|
|
||||||
void exit_error(const char *error)
|
void exit_error(const char *error)
|
||||||
{
|
{
|
||||||
@@ -116,38 +19,55 @@ void exit_error(const char *error)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initialize_window(SDL_Window **window, SDL_Renderer **renderer)
|
void initialize_window(game_state *state)
|
||||||
{
|
{
|
||||||
int sdl;
|
int sdl;
|
||||||
sdl = SDL_Init(SDL_INIT_EVERYTHING);
|
sdl = SDL_Init(SDL_INIT_EVERYTHING);
|
||||||
if(sdl != 0)
|
if(sdl != 0)
|
||||||
exit_error("Error initializing SDL.");
|
exit_error("Error initializing SDL.");
|
||||||
|
|
||||||
*window = SDL_CreateWindow(
|
state->window = SDL_CreateWindow(
|
||||||
NULL,
|
NULL,
|
||||||
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||||
WINDOW_WIDTH, WINDOW_HEIGHT,
|
WINDOW_WIDTH, WINDOW_HEIGHT,
|
||||||
SDL_WINDOW_SHOWN);
|
SDL_WINDOW_SHOWN);
|
||||||
if(!window)
|
if(!state->window)
|
||||||
exit_error("Error creating SDL Window.");
|
exit_error("Error creating SDL Window.");
|
||||||
|
|
||||||
*renderer = SDL_CreateRenderer(*window, -1, 0);
|
state->renderer = SDL_CreateRenderer(state->window, -1, 0);
|
||||||
if(!renderer)
|
if(!state->renderer)
|
||||||
exit_error("Error creating SDL Renderer.");
|
exit_error("Error creating SDL Renderer.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void initialized_font(TTF_Font **font)
|
void initialize_font(game_state *state)
|
||||||
{
|
{
|
||||||
int ttf;
|
int ttf = TTF_Init();
|
||||||
ttf = TTF_Init();
|
|
||||||
if(ttf < 0)
|
if(ttf < 0)
|
||||||
exit_error("Error opening font.");
|
exit_error("Error opening font.");
|
||||||
|
|
||||||
*font = TTF_OpenFont("./iosevka-bold.ttf", 36);
|
#if EMBED_FONTS
|
||||||
if(!font)
|
SDL_RWops *font_mem = SDL_RWFromConstMem(iosevka_bold_ttf,
|
||||||
|
iosevka_bold_ttf_len);
|
||||||
|
if(!font_mem)
|
||||||
|
exit_error("Error creating font memory.");
|
||||||
|
|
||||||
|
state->font = TTF_OpenFontRW(font_mem, TRUE, 24);
|
||||||
|
if(!state->font)
|
||||||
|
exit_error("Error opening memory font.");
|
||||||
|
#else
|
||||||
|
state->font = TTF_OpenFont("./iosevka-bold.ttf", 24);
|
||||||
|
if(!state->font)
|
||||||
exit_error("Error opening font.");
|
exit_error("Error opening font.");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_FPS
|
||||||
|
int get_fps(game_state *state)
|
||||||
|
{
|
||||||
|
return (int)(1.0f / state->delta_time);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int rand_num(int m, int n)
|
int rand_num(int m, int n)
|
||||||
{
|
{
|
||||||
return m + rand() / (RAND_MAX / (n - m + 1) + 1);
|
return m + rand() / (RAND_MAX / (n - m + 1) + 1);
|
||||||
@@ -163,15 +83,27 @@ void collision_particles(game_state *state, vector3 color)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
particle fragment;
|
particle fragment;
|
||||||
for(i = 0; i < 50; i++) {
|
for(i = 0; i < 30; i++) {
|
||||||
fragment.point.x = state->ball.point.x;
|
if(state->ball.point.x < WINDOW_WIDTH / 2)
|
||||||
fragment.point.y = state->ball.point.y;
|
fragment.point.x = state->ball.point.x;
|
||||||
|
else
|
||||||
|
fragment.point.x = state->ball.point.x + state->ball.dimension.x;
|
||||||
|
|
||||||
|
if(state->ball.point.y < WINDOW_HEIGHT / 2)
|
||||||
|
fragment.point.y = state->ball.point.y;
|
||||||
|
else
|
||||||
|
fragment.point.y = state->ball.point.y + state->ball.dimension.y;
|
||||||
|
|
||||||
fragment.velocity.x =
|
fragment.velocity.x =
|
||||||
(float)rand_num(state->ball.velocity.x - 200, state->ball.velocity.x + 200) / 4.0f;
|
(float)rand_num((int)state->ball.velocity.x - 200,
|
||||||
|
(int)state->ball.velocity.x + 200) / 4.0f;
|
||||||
fragment.velocity.y =
|
fragment.velocity.y =
|
||||||
(float)rand_num(state->ball.velocity.y - 200, state->ball.velocity.y + 200) / 4.0f;
|
(float)rand_num((int)state->ball.velocity.y - 200,
|
||||||
fragment.dimension.x = 3.0f;
|
(int)state->ball.velocity.y + 200) / 4.0f;
|
||||||
fragment.dimension.y = 3.0f;
|
|
||||||
|
fragment.dimension.x = (float)rand_num(3, 5);
|
||||||
|
fragment.dimension.y = fragment.dimension.x;
|
||||||
|
|
||||||
fragment.color.r = color.r;
|
fragment.color.r = color.r;
|
||||||
fragment.color.g = color.g;
|
fragment.color.g = color.g;
|
||||||
fragment.color.b = color.b;
|
fragment.color.b = color.b;
|
||||||
@@ -180,7 +112,7 @@ void collision_particles(game_state *state, vector3 color)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_ball(game_state *state, float delta_time)
|
void handle_ball(game_state *state)
|
||||||
{
|
{
|
||||||
vector3 color;
|
vector3 color;
|
||||||
|
|
||||||
@@ -216,26 +148,18 @@ void handle_ball(game_state *state, float delta_time)
|
|||||||
|
|
||||||
if(state->ball.point.x <= 0) {
|
if(state->ball.point.x <= 0) {
|
||||||
state->ball.point.x = WINDOW_WIDTH / 2;
|
state->ball.point.x = WINDOW_WIDTH / 2;
|
||||||
state->ball.point.y = 0;
|
state->ball.point.y = 1;
|
||||||
state->player_two.score += 1;
|
state->player_two.score += 1;
|
||||||
if(state->player_two.score > 5) {
|
|
||||||
state->player_two.score = 1;
|
|
||||||
state->player_one.score = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(state->ball.point.x >= WINDOW_WIDTH - state->ball.dimension.x) {
|
if(state->ball.point.x >= WINDOW_WIDTH - state->ball.dimension.x) {
|
||||||
state->ball.point.x = WINDOW_WIDTH / 2;
|
state->ball.point.x = WINDOW_WIDTH / 2;
|
||||||
state->ball.point.y = 0;
|
state->ball.point.y = 1;
|
||||||
state->player_one.score += 1;
|
state->player_one.score += 1;
|
||||||
if(state->player_one.score > 5) {
|
|
||||||
state->player_one.score = 1;
|
|
||||||
state->player_two.score = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(state->ball.point.y < 0) {
|
if(state->ball.point.y < 0) {
|
||||||
state->ball.velocity.y *= -1;
|
state->ball.velocity.y *= -1;
|
||||||
state->ball.point.y = 0;
|
state->ball.point.y = 1;
|
||||||
|
|
||||||
color.r = 198.0f;
|
color.r = 198.0f;
|
||||||
color.g = 204.0f;
|
color.g = 204.0f;
|
||||||
@@ -252,77 +176,146 @@ void handle_ball(game_state *state, float delta_time)
|
|||||||
collision_particles(state, color);
|
collision_particles(state, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
state->ball.point.x += state->ball.velocity.x * delta_time;
|
state->ball.point.x += state->ball.velocity.x * state->delta_time;
|
||||||
state->ball.point.y += state->ball.velocity.y * delta_time;
|
state->ball.point.y += state->ball.velocity.y * state->delta_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_paddles(game_state *state, float delta_time)
|
void handle_paddles(game_state *state)
|
||||||
{
|
{
|
||||||
if(state->player_one.up)
|
if(state->player_one.up)
|
||||||
state->player_one.point.y -= state->player_one.vy * delta_time;
|
state->player_one.point.y -= state->player_one.vy * state->delta_time;
|
||||||
if(state->player_one.down)
|
if(state->player_one.down)
|
||||||
state->player_one.point.y += state->player_one.vy * delta_time;
|
state->player_one.point.y += state->player_one.vy * state->delta_time;
|
||||||
if(state->player_two.up)
|
if(state->player_two.up)
|
||||||
state->player_two.point.y -= state->player_one.vy * delta_time;
|
state->player_two.point.y -= state->player_one.vy * state->delta_time;
|
||||||
if(state->player_two.down)
|
if(state->player_two.down)
|
||||||
state->player_two.point.y += state->player_one.vy * delta_time;
|
state->player_two.point.y += state->player_one.vy * state->delta_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_particles(game_state *state, float delta_time)
|
void handle_particles(game_state *state)
|
||||||
{
|
{
|
||||||
if(!qempty(&state->particles)) {
|
if(!qempty(&state->particles)) {
|
||||||
struct node *tmp = state->particles.first;
|
struct node *tmp = state->particles.first;
|
||||||
while(tmp) {
|
while(tmp) {
|
||||||
tmp->data.color.a -= 2; /* TODO: Lock to delta time. */
|
tmp->data.color.a -= 300.0f * state->delta_time;
|
||||||
if(tmp->data.color.a < 0.0f) {
|
if(tmp->data.color.a < 0.0f) {
|
||||||
tmp = tmp->next;
|
tmp = tmp->next;
|
||||||
qget(&state->particles, NULL);
|
qget(&state->particles, NULL);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
tmp->data.point.x += tmp->data.velocity.x * delta_time;
|
tmp->data.point.x += tmp->data.velocity.x * state->delta_time;
|
||||||
tmp->data.point.y += tmp->data.velocity.y * delta_time;
|
tmp->data.point.y += tmp->data.velocity.y * state->delta_time;
|
||||||
|
|
||||||
tmp = tmp->next;
|
tmp = tmp->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void render_score(game_state *state, SDL_Renderer *renderer, TTF_Font *font)
|
void render_text_leading(game_state *state, const char *text, int fsize,
|
||||||
{
|
vector2 pos, vector4 color)
|
||||||
/* Build score string */
|
{
|
||||||
char *score;
|
|
||||||
score = malloc(3*sizeof(char));
|
|
||||||
score[0] = (char)(state->player_one.score + 48); /* FIX */
|
|
||||||
score[1] = ':';
|
|
||||||
score[2] = (char)(state->player_two.score + 48);
|
|
||||||
|
|
||||||
/* Render */
|
/* Render */
|
||||||
SDL_Surface *text;
|
TTF_SetFontSize(state->font, fsize);
|
||||||
SDL_Color color = { 198, 204, 215, 255 };
|
SDL_Surface *text_surface;
|
||||||
text = TTF_RenderText_Solid(font, score, color);
|
SDL_Color surface_color = {
|
||||||
if (!text)
|
(int)color.r, (int)color.g, (int)color.b, (int)color.a };
|
||||||
exit_error("Error initializing Text.");
|
text_surface = TTF_RenderText_Solid(state->font, text, surface_color);
|
||||||
|
if (!text_surface)
|
||||||
|
exit_error("Error initializing text surface.");
|
||||||
|
|
||||||
SDL_Texture *text_texture;
|
SDL_Texture *text_texture;
|
||||||
text_texture = SDL_CreateTextureFromSurface(renderer, text);
|
text_texture = SDL_CreateTextureFromSurface(state->renderer,
|
||||||
SDL_Rect dest = { WINDOW_WIDTH/2-20, 10, text->w, text->h };
|
text_surface);
|
||||||
SDL_RenderCopy(renderer, text_texture, NULL, &dest);
|
if (!text_texture)
|
||||||
|
exit_error("Error initializing text texture.");
|
||||||
|
|
||||||
|
SDL_Rect dest = { (int)pos.x, (int)pos.y, text_surface->w,
|
||||||
|
text_surface->h };
|
||||||
|
SDL_RenderCopy(state->renderer, text_texture, NULL, &dest);
|
||||||
|
|
||||||
/* free */
|
/* free */
|
||||||
SDL_DestroyTexture(text_texture);
|
SDL_DestroyTexture(text_texture);
|
||||||
SDL_FreeSurface(text);
|
SDL_FreeSurface(text_surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_text_centered(game_state *state, const char *text, int fsize,
|
||||||
|
vector2 pos, vector4 color)
|
||||||
|
{
|
||||||
|
/* Render */
|
||||||
|
TTF_SetFontSize(state->font, fsize);
|
||||||
|
SDL_Surface *text_surface;
|
||||||
|
SDL_Color surface_color = {
|
||||||
|
(int)color.r, (int)color.g, (int)color.b, (int)color.a };
|
||||||
|
text_surface = TTF_RenderText_Solid(state->font, text, surface_color);
|
||||||
|
if (!text_surface)
|
||||||
|
exit_error("Error initializing text surface.");
|
||||||
|
|
||||||
|
SDL_Texture *text_texture;
|
||||||
|
text_texture = SDL_CreateTextureFromSurface(state->renderer,
|
||||||
|
text_surface);
|
||||||
|
if (!text_texture)
|
||||||
|
exit_error("Error initializing text texture.");
|
||||||
|
|
||||||
|
SDL_Rect dest = { (int)(pos.x - (float)text_surface->w / 2), (int)pos.y,
|
||||||
|
text_surface->w, text_surface->h };
|
||||||
|
SDL_RenderCopy(state->renderer, text_texture, NULL, &dest);
|
||||||
|
|
||||||
|
/* free */
|
||||||
|
SDL_DestroyTexture(text_texture);
|
||||||
|
SDL_FreeSurface(text_surface);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_score(game_state *state)
|
||||||
|
{
|
||||||
|
/* Build score string */
|
||||||
|
char *score;
|
||||||
|
score = malloc(10*sizeof(char));
|
||||||
|
|
||||||
|
/* Render player one score */
|
||||||
|
sprintf(score, "%d", state->player_one.score);
|
||||||
|
vector2 pos = { (float)(WINDOW_WIDTH / 4), 10.0f };
|
||||||
|
vector4 color = { 198.0f, 204.0f, 215.0f, 255.0f };
|
||||||
|
render_text_centered(state, score, 30, pos, color);
|
||||||
|
|
||||||
|
/* Render player two score */
|
||||||
|
sprintf(score, "%d", state->player_two.score);
|
||||||
|
pos.x = WINDOW_WIDTH - pos.x;
|
||||||
|
render_text_centered(state, score, 30, pos, color);
|
||||||
|
sprintf(score, "%d", state->player_one.score);
|
||||||
|
|
||||||
|
/* free */
|
||||||
free(score);
|
free(score);
|
||||||
}
|
}
|
||||||
|
|
||||||
void render_ball(game_state *state, SDL_Renderer *renderer)
|
#if ENABLE_FPS
|
||||||
|
void render_fps(game_state *state)
|
||||||
|
{
|
||||||
|
/* Build score string */
|
||||||
|
char *fps;
|
||||||
|
fps = malloc(10*sizeof(char));
|
||||||
|
sprintf(fps, "%d", get_fps(state));
|
||||||
|
|
||||||
|
/* Render */
|
||||||
|
vector2 pos = { 10.0f, 10.0f };
|
||||||
|
vector4 color = { 198.0f, 204.0f, 215.0f, 255.0f };
|
||||||
|
render_text_leading(state, fps, 16, pos, color);
|
||||||
|
|
||||||
|
/* free */
|
||||||
|
free(fps);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void render_ball(game_state *state)
|
||||||
{
|
{
|
||||||
SDL_Rect ball_rect = { state->ball.point.x, state->ball.point.y,
|
SDL_Rect ball_rect = { state->ball.point.x, state->ball.point.y,
|
||||||
state->ball.dimension.x, state->ball.dimension.y };
|
state->ball.dimension.x, state->ball.dimension.y };
|
||||||
SDL_SetRenderDrawColor(renderer, 198, 204, 215, 255);
|
SDL_SetRenderDrawColor(state->renderer, 198, 204, 215, 255);
|
||||||
SDL_RenderFillRect(renderer, &ball_rect);
|
SDL_RenderFillRect(state->renderer, &ball_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void render_paddles(game_state *state, SDL_Renderer *renderer)
|
void render_paddles(game_state *state)
|
||||||
{
|
{
|
||||||
SDL_Rect player_one_rect = {
|
SDL_Rect player_one_rect = {
|
||||||
state->player_one.point.x, state->player_one.point.y,
|
state->player_one.point.x, state->player_one.point.y,
|
||||||
@@ -331,14 +324,14 @@ void render_paddles(game_state *state, SDL_Renderer *renderer)
|
|||||||
state->player_two.point.x, state->player_two.point.y,
|
state->player_two.point.x, state->player_two.point.y,
|
||||||
state->player_two.dimension.x, state->player_two.dimension.y };
|
state->player_two.dimension.x, state->player_two.dimension.y };
|
||||||
|
|
||||||
SDL_SetRenderDrawColor(renderer, 215, 78, 66, 255);
|
SDL_SetRenderDrawColor(state->renderer, 215, 78, 66, 255);
|
||||||
SDL_RenderFillRect(renderer, &player_one_rect);
|
SDL_RenderFillRect(state->renderer, &player_one_rect);
|
||||||
|
|
||||||
SDL_SetRenderDrawColor(renderer, 16, 133, 255, 255);
|
SDL_SetRenderDrawColor(state->renderer, 16, 133, 255, 255);
|
||||||
SDL_RenderFillRect(renderer, &player_two_rect);
|
SDL_RenderFillRect(state->renderer, &player_two_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void render_particles(game_state *state, SDL_Renderer *renderer)
|
void render_particles(game_state *state)
|
||||||
{
|
{
|
||||||
if(!qempty(&state->particles)) {
|
if(!qempty(&state->particles)) {
|
||||||
SDL_Rect particle_rect;
|
SDL_Rect particle_rect;
|
||||||
@@ -349,19 +342,36 @@ void render_particles(game_state *state, SDL_Renderer *renderer)
|
|||||||
particle_rect.w = tmp->data.dimension.x;
|
particle_rect.w = tmp->data.dimension.x;
|
||||||
particle_rect.h = tmp->data.dimension.y;
|
particle_rect.h = tmp->data.dimension.y;
|
||||||
|
|
||||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
SDL_SetRenderDrawBlendMode(state->renderer, SDL_BLENDMODE_BLEND);
|
||||||
SDL_SetRenderDrawColor(renderer,
|
SDL_SetRenderDrawColor(state->renderer,
|
||||||
(Uint8)tmp->data.color.r, (Uint8)tmp->data.color.g,
|
(Uint8)tmp->data.color.r, (Uint8)tmp->data.color.g,
|
||||||
(Uint8)tmp->data.color.b, (Uint8)tmp->data.color.a);
|
(Uint8)tmp->data.color.b, (Uint8)tmp->data.color.a);
|
||||||
SDL_RenderFillRect(renderer, &particle_rect);
|
SDL_RenderFillRect(state->renderer, &particle_rect);
|
||||||
|
|
||||||
tmp = tmp->next;
|
tmp = tmp->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: ??? */
|
||||||
|
void render_divider(game_state *state)
|
||||||
|
{
|
||||||
|
SDL_SetRenderDrawColor(state->renderer, 13, 17, 23, 255);
|
||||||
|
SDL_RenderDrawLine(state->renderer, (int)(WINDOW_WIDTH / 2), 0,
|
||||||
|
(int)(WINDOW_WIDTH / 2), WINDOW_HEIGHT);
|
||||||
|
SDL_RenderDrawLine(state->renderer, (int)(WINDOW_WIDTH / 2) - 1, 0,
|
||||||
|
(int)(WINDOW_WIDTH / 2) - 1, WINDOW_HEIGHT);
|
||||||
|
SDL_RenderDrawLine(state->renderer, (int)(WINDOW_WIDTH / 2) + 1, 0,
|
||||||
|
(int)(WINDOW_WIDTH / 2) + 1, WINDOW_HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
void setup(game_state *state)
|
void setup(game_state *state)
|
||||||
{
|
{
|
||||||
|
srand(time(NULL));
|
||||||
|
|
||||||
|
initialize_window(state);
|
||||||
|
initialize_font(state);
|
||||||
|
|
||||||
state->is_running = TRUE;
|
state->is_running = TRUE;
|
||||||
state->last_frame_time = 0;
|
state->last_frame_time = 0;
|
||||||
|
|
||||||
@@ -371,14 +381,14 @@ void setup(game_state *state)
|
|||||||
state->ball.point.y = 40;
|
state->ball.point.y = 40;
|
||||||
state->ball.dimension.x = 15;
|
state->ball.dimension.x = 15;
|
||||||
state->ball.dimension.y = 15;
|
state->ball.dimension.y = 15;
|
||||||
state->ball.velocity.x = 500;
|
state->ball.velocity.x = 700;
|
||||||
state->ball.velocity.y = 600;
|
state->ball.velocity.y = 400;
|
||||||
|
|
||||||
state->player_one.point.x = 10;
|
state->player_one.point.x = 10;
|
||||||
state->player_one.point.y = 10;
|
state->player_one.point.y = 10;
|
||||||
state->player_one.dimension.x = 10;
|
state->player_one.dimension.x = 10;
|
||||||
state->player_one.dimension.y = 100;
|
state->player_one.dimension.y = 100;
|
||||||
state->player_one.vy = 600;
|
state->player_one.vy = 800;
|
||||||
state->player_one.score = 0;
|
state->player_one.score = 0;
|
||||||
state->player_one.up = FALSE;
|
state->player_one.up = FALSE;
|
||||||
state->player_one.down = FALSE;
|
state->player_one.down = FALSE;
|
||||||
@@ -387,7 +397,7 @@ void setup(game_state *state)
|
|||||||
state->player_two.point.y = 10;
|
state->player_two.point.y = 10;
|
||||||
state->player_two.dimension.x = 10;
|
state->player_two.dimension.x = 10;
|
||||||
state->player_two.dimension.y = 100;
|
state->player_two.dimension.y = 100;
|
||||||
state->player_two.vy = 600;
|
state->player_two.vy = 800;
|
||||||
state->player_two.score = 0;
|
state->player_two.score = 0;
|
||||||
state->player_two.up = FALSE;
|
state->player_two.up = FALSE;
|
||||||
state->player_two.down = FALSE;
|
state->player_two.down = FALSE;
|
||||||
@@ -439,7 +449,6 @@ void process_input(game_state *state)
|
|||||||
void update(game_state *state)
|
void update(game_state *state)
|
||||||
{
|
{
|
||||||
int time_to_wait;
|
int time_to_wait;
|
||||||
float delta_time;
|
|
||||||
|
|
||||||
time_to_wait = TARGET_FRAME_TIME - (SDL_GetTicks() -
|
time_to_wait = TARGET_FRAME_TIME - (SDL_GetTicks() -
|
||||||
state->last_frame_time);
|
state->last_frame_time);
|
||||||
@@ -447,55 +456,60 @@ void update(game_state *state)
|
|||||||
if(time_to_wait > 0 && time_to_wait <= TARGET_FRAME_TIME)
|
if(time_to_wait > 0 && time_to_wait <= TARGET_FRAME_TIME)
|
||||||
SDL_Delay(time_to_wait);
|
SDL_Delay(time_to_wait);
|
||||||
|
|
||||||
delta_time = (SDL_GetTicks() - state->last_frame_time) / 1000.0f;
|
state->delta_time = (SDL_GetTicks() - state->last_frame_time) / 1000.0f;
|
||||||
|
|
||||||
state->last_frame_time = SDL_GetTicks();
|
state->last_frame_time = SDL_GetTicks();
|
||||||
|
|
||||||
handle_ball(state, delta_time);
|
handle_ball(state);
|
||||||
handle_paddles(state, delta_time);
|
handle_paddles(state);
|
||||||
handle_particles(state, delta_time);
|
handle_particles(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void render(game_state *state, SDL_Renderer *renderer, TTF_Font *font)
|
void render(game_state *state)
|
||||||
{
|
{
|
||||||
SDL_SetRenderDrawColor(renderer, 24, 26, 31, 255);
|
SDL_SetRenderDrawColor(state->renderer, 24, 26, 31, 255);
|
||||||
SDL_RenderClear(renderer);
|
SDL_RenderClear(state->renderer);
|
||||||
|
|
||||||
render_paddles(state, renderer);
|
render_divider(state);
|
||||||
render_ball(state, renderer);
|
|
||||||
render_score(state, renderer, font);
|
|
||||||
render_particles(state, renderer);
|
|
||||||
|
|
||||||
SDL_RenderPresent(renderer);
|
render_paddles(state);
|
||||||
|
render_ball(state);
|
||||||
|
render_particles(state);
|
||||||
|
|
||||||
|
render_score(state);
|
||||||
|
#if ENABLE_FPS
|
||||||
|
render_fps(state);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_RenderPresent(state->renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy_window(SDL_Window *window, SDL_Renderer *renderer)
|
void destroy_window(game_state *state)
|
||||||
{
|
{
|
||||||
SDL_DestroyRenderer(renderer);
|
SDL_DestroyRenderer(state->renderer);
|
||||||
SDL_DestroyWindow(window);
|
SDL_DestroyWindow(state->window);
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void destroy_font(game_state *state)
|
||||||
|
{
|
||||||
|
TTF_CloseFont(state->font);
|
||||||
|
TTF_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
srand(time(NULL));
|
|
||||||
|
|
||||||
game_state state;
|
game_state state;
|
||||||
SDL_Window *window = NULL;
|
|
||||||
SDL_Renderer *renderer = NULL;
|
|
||||||
TTF_Font *font;
|
|
||||||
|
|
||||||
initialize_window(&window, &renderer);
|
|
||||||
initialized_font(&font);
|
|
||||||
|
|
||||||
setup(&state);
|
setup(&state);
|
||||||
while(state.is_running) {
|
while(state.is_running) {
|
||||||
process_input(&state);
|
process_input(&state);
|
||||||
update(&state);
|
update(&state);
|
||||||
render(&state, renderer, font);
|
render(&state);
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy_window(window, renderer);
|
destroy_font(&state);
|
||||||
|
destroy_window(&state);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
37
queue.c
Normal file
37
queue.c
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#include "queue.h"
|
||||||
|
|
||||||
|
void qinit(queue *item)
|
||||||
|
{
|
||||||
|
item->first = NULL;
|
||||||
|
item->last = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qput(queue *item, particle data)
|
||||||
|
{
|
||||||
|
if(!item->first) {
|
||||||
|
item->first = malloc(sizeof(struct node));
|
||||||
|
item->last = item->first;
|
||||||
|
} else {
|
||||||
|
item->last->next = malloc(sizeof(struct node));
|
||||||
|
item->last = item->last->next;
|
||||||
|
}
|
||||||
|
item->last->data = data;
|
||||||
|
item->last->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qget(queue *item, particle *data)
|
||||||
|
{
|
||||||
|
if(data)
|
||||||
|
*data = item->first->data;
|
||||||
|
|
||||||
|
struct node *tmp = item->first;
|
||||||
|
item->first = item->first->next;
|
||||||
|
if(!item->first)
|
||||||
|
item->last = NULL;
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int qempty(queue *item)
|
||||||
|
{
|
||||||
|
return !item->first;
|
||||||
|
}
|
||||||
14
queue.h
Normal file
14
queue.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef QUEUE_H_SENTRY
|
||||||
|
#define QUEUE_H_SENTRY
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
void qinit(queue *item);
|
||||||
|
|
||||||
|
void qput(queue *item, particle data);
|
||||||
|
|
||||||
|
void qget(queue *item, particle *data);
|
||||||
|
|
||||||
|
int qempty(queue *item);
|
||||||
|
|
||||||
|
#endif
|
||||||
BIN
screenshot.png
Normal file
BIN
screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 436 KiB |
28
settings.h
Normal file
28
settings.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#ifndef SETTINGS_H_SENTRY
|
||||||
|
#define SETTINGS_H_SENTRY
|
||||||
|
|
||||||
|
#ifndef WINDOW_WIDTH
|
||||||
|
#define WINDOW_WIDTH 1000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WINDOW_HEIGHT
|
||||||
|
#define WINDOW_HEIGHT 650
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FPS
|
||||||
|
#define FPS 120
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TARGET_FRAME_TIME
|
||||||
|
#define TARGET_FRAME_TIME (1000 / FPS)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ENABLE_FPS
|
||||||
|
#define ENABLE_FPS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef EMBED_FONTS
|
||||||
|
#define EMBED_FONTS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
84
types.h
Normal file
84
types.h
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
#ifndef TYPES_H_SENTRY
|
||||||
|
#define TYPES_H_SENTRY
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <SDL_ttf.h>
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef TRUE
|
||||||
|
#define TRUE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FALSE
|
||||||
|
#define FALSE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
} vector2;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float r;
|
||||||
|
float g;
|
||||||
|
float b;
|
||||||
|
} vector3;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float r;
|
||||||
|
float g;
|
||||||
|
float b;
|
||||||
|
float a;
|
||||||
|
} vector4;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float w;
|
||||||
|
float h;
|
||||||
|
} rect;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
vector2 point;
|
||||||
|
vector2 velocity;
|
||||||
|
vector2 dimension;
|
||||||
|
vector4 color;
|
||||||
|
} particle;
|
||||||
|
|
||||||
|
struct node {
|
||||||
|
struct node *next;
|
||||||
|
particle data;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct node *first;
|
||||||
|
struct node *last;
|
||||||
|
} queue;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
SDL_Window *window;
|
||||||
|
SDL_Renderer *renderer;
|
||||||
|
TTF_Font *font;
|
||||||
|
|
||||||
|
int is_running;
|
||||||
|
int last_frame_time;
|
||||||
|
float delta_time;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
vector2 point;
|
||||||
|
vector2 velocity;
|
||||||
|
vector2 dimension;
|
||||||
|
} ball;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
vector2 point;
|
||||||
|
vector2 dimension;
|
||||||
|
float vy;
|
||||||
|
int score;
|
||||||
|
int up;
|
||||||
|
int down;
|
||||||
|
} player_one, player_two;
|
||||||
|
|
||||||
|
queue particles;
|
||||||
|
} game_state;
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user