From 3422a87bdb087b6d927203e266beb71027779dbe Mon Sep 17 00:00:00 2001 From: "Dobbertin, Niclas" Date: Sat, 24 Jun 2023 23:04:23 +0200 Subject: init code --- Makefile | 27 +++++ characters.h | 20 +++ config.mk | 14 +++ data/characters.txt | 0 input.c | 61 ++++++++++ input.h | 22 ++++ main.c | 268 +++++++++++++++++++++++++++++++++++++++++ main.h | 11 ++ player.c | 54 +++++++++ player.h | 26 ++++ render.h | 6 + resources/OpenSans-Regular.ttf | Bin 0 -> 217276 bytes 12 files changed, 509 insertions(+) create mode 100644 Makefile create mode 100644 characters.h create mode 100644 config.mk create mode 100644 data/characters.txt create mode 100644 input.c create mode 100644 input.h create mode 100644 main.c create mode 100644 main.h create mode 100644 player.c create mode 100644 player.h create mode 100644 render.h create mode 100644 resources/OpenSans-Regular.ttf diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..abf6b40 --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ +# mouse move + +include config.mk + +SRC = main.c player.c input.c +OBJ = ${SRC:.c=.o} + +all: main + +.c.o: + ${CC} -c ${CFLAGS} $< + +# ${OBJ}: + +main: ${OBJ} + ${CC} -o $@ ${OBJ} ${LDFLAGS} + +clean: + rm -f main ${OBJ} + +debug: clean debug_compile + +debug_compile: CFLAGS += -g -pg + # LDFLAGS += -g -pg +debug_compile: main + +.PHONY: all clean debug diff --git a/characters.h b/characters.h new file mode 100644 index 0000000..ba1ffb2 --- /dev/null +++ b/characters.h @@ -0,0 +1,20 @@ +#ifndef CHARACTERS_H_ +#define CHARACTERS_H_ + +#include "player.h" + +const struct Player TEMPLATE_1 = { + 100, // pos x + 100, // pos y + 100, // vel x + 100, // vel y + 0, // accel x + 0, // accel y + 100, // max vel x + 100, // max vel y + 100, // hp + 0, // geometry + 0 // geometry len +}; + +#endif // CHARACTERS_H_ diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..f219d91 --- /dev/null +++ b/config.mk @@ -0,0 +1,14 @@ +# Initial Version +VERSION = 0.1 + +PKGS = sdl2 SDL2_gfx + +INCS = `pkg-config --cflags $(PKGS)` +LIBS = `pkg-config --libs $(PKGS)` -lSDL2_ttf -lm + +# flags +CFLAGS = -pedantic -Wall -Wextra -Werror -O3 ${INCS} +LDFLAGS = ${LIBS} + +# compiler and linker +CC = gcc diff --git a/data/characters.txt b/data/characters.txt new file mode 100644 index 0000000..e69de29 diff --git a/input.c b/input.c new file mode 100644 index 0000000..5318279 --- /dev/null +++ b/input.c @@ -0,0 +1,61 @@ +#include "input.h" + +#include + +void handleKeyboardEvent(int *action_states, SDL_Event event) +{ + if (event.key.repeat != 0) + return; + switch (event.type) { + case SDL_QUIT: + action_states[ACTION_QUIT] = 1; + break; + case SDL_KEYDOWN: + switch (event.key.keysym.sym) { + case SDLK_q: + action_states[ACTION_QUIT] = 1; + break; + case SDLK_w: + action_states[ACTION_MOVE_UP] = 1; + break; + case SDLK_s: + action_states[ACTION_MOVE_DOWN] = 1; + break; + case SDLK_a: + action_states[ACTION_MOVE_LEFT] = 1; + break; + case SDLK_d: + action_states[ACTION_MOVE_RIGHT] = 1; + break; + } + break; + case SDL_KEYUP: + switch (event.key.keysym.sym) { + case SDLK_w: + action_states[ACTION_MOVE_UP] = 0; + break; + case SDLK_s: + action_states[ACTION_MOVE_DOWN] = 0; + break; + case SDLK_a: + action_states[ACTION_MOVE_LEFT] = 0; + break; + case SDLK_d: + action_states[ACTION_MOVE_RIGHT] = 0; + break; + } + break; + } +} + +/* int action_status(enum Actions action) */ +/* { */ +/* return actions_state[action]; */ +/* } */ + +/* void action_toggle(enum Actions action) */ +/* { */ +/* printf("%d", actions_state[action]); */ +/* actions_state[action] = 1; */ +/* printf("%d", actions_state[action]); */ +/* } */ diff --git a/input.h b/input.h new file mode 100644 index 0000000..716f48c --- /dev/null +++ b/input.h @@ -0,0 +1,22 @@ +#ifndef INPUT_H_ +#define INPUT_H_ + +#include + +enum Actions { + ACTION_QUIT, + ACTION_MOVE_UP, + ACTION_MOVE_DOWN, + ACTION_MOVE_LEFT, + ACTION_MOVE_RIGHT, + + ACTION_STATE_COUNT +}; + +void handleKeyboardEvent(int *action_states, SDL_Event event); + +/* int action_status(enum Actions action); */ + +/* void action_toggle(enum Actions action); */ + +#endif // INPUT_H_ diff --git a/main.c b/main.c new file mode 100644 index 0000000..53afb18 --- /dev/null +++ b/main.c @@ -0,0 +1,268 @@ +#include "main.h" +#include +#include +#include +#include +#include + +#include "player.h" +#include "input.h" +#include "characters.h" + +#define DEFAULT_SCREEN_WIDTH 800 +#define DEFAULT_SCREEN_HEIGHT 600 + +#define SCREEN_FPS 60 +#define DELTA_TIME_SEC (1.0f / SCREEN_FPS) +#define DELTA_TIME_MS ((Uint32)floorf(DELTA_TIME_SEC * 1000.0f)) +#define SIMULATION_STEP_MS 10 + +#define RENDER_ENABLED 1 +#define SHOW_FPS 1 + +int main() +{ + SDL_Window *window; + SDL_Renderer *renderer; + /* SDL_Texture *fps_texture; */ + TTF_Font *Sans; + + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + fprintf(stderr, "SDL ERROR: %s\n", SDL_GetError()); + exit(1); + } + window = + SDL_CreateWindow("Space Battle", 100, 100, DEFAULT_SCREEN_WIDTH, + DEFAULT_SCREEN_HEIGHT, SDL_WINDOW_RESIZABLE); + + if (window == NULL) { + fprintf(stderr, "COULD NOT CREATE SDL WINDOW: %s\n", + SDL_GetError()); + exit(1); + } + + if (RENDER_ENABLED) { + renderer = SDL_CreateRenderer(window, -1, + SDL_RENDERER_ACCELERATED); + + if (renderer == NULL) { + fprintf(stderr, "COULD NOT CREATE SDL RENDERER: %s\n", + SDL_GetError()); + exit(1); + } + TTF_Init(); + Sans = TTF_OpenFont("resources/OpenSans-Regular.ttf", 12); + if (!Sans) { + fprintf(stderr, "COULD NOT OPEN FONT: %s\n", + SDL_GetError()); + exit(1); + } + } + + // TODO: outsource shape definitions + SDL_Vertex vert[3]; + + // center + vert[0].position.x = 400; + vert[0].position.y = 0; + vert[0].color.r = 255; + vert[0].color.g = 0; + vert[0].color.b = 0; + vert[0].color.a = 255; + + // left + vert[1].position.x = 200; + vert[1].position.y = 450; + vert[1].color.r = 0; + vert[1].color.g = 0; + vert[1].color.b = 255; + vert[1].color.a = 255; + + // right + vert[2].position.x = 600; + vert[2].position.y = 450; + vert[2].color.r = 0; + vert[2].color.g = 255; + vert[2].color.b = 0; + vert[2].color.a = 255; + + struct Player player_1 = TEMPLATE_1; + player_1.geometry = vert; + player_1.geometry_len = 3; + + + int action_states[ACTION_STATE_COUNT]; + for (int i = 0; i < ACTION_STATE_COUNT; i++) { + action_states[i] = 0; + } + + int win_x = DEFAULT_SCREEN_WIDTH; + int win_y = DEFAULT_SCREEN_HEIGHT; + int quit = 0; + + // based on: + // https://gafferongames.com/post/fix_your_timestep/ + // doesn't include state-interpolation (yet?) + double physics_total_time = 0.0; + const double physics_timestep = 1 / 60.0; + const double render_timestep = 1 / 60.0; + double current_time = current_sdl_time_in_seconds(); + double physics_time_accumulator = 0.0; + double render_time_accumulator = 0.0; + + float fps = 0.0f; + char fps_text[123] = "start"; + + while (!quit) { + double new_time = current_sdl_time_in_seconds(); + double frame_time = new_time - current_time; + current_time = new_time; + + physics_time_accumulator += frame_time; + render_time_accumulator += frame_time; + + while (physics_time_accumulator >= physics_timestep) { + SDL_Event event; + while (!quit && SDL_PollEvent(&event)) { + /* // e.g. https://stackoverflow.com/a/1252996 */ + handleKeyboardEvent(action_states, event); + + if (action_states[ACTION_QUIT]) + quit = 1; + } + + execute_actions(&player_1, action_states, + physics_timestep); + /* player_move(&player_1, physics_timestep); */ + + physics_time_accumulator -= physics_timestep; + physics_total_time += physics_timestep; + } + + if (RENDER_ENABLED && + render_time_accumulator >= render_timestep) { + /* SDL_SetRenderDrawColor(renderer, HEX_COLOR(BACKGROUND_COLOR)); */ + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); + + SDL_RenderClear(renderer); + + /* render_my_stuff(renderer); */ + /* hexagon_draw(&hex, renderer); */ + + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + + /* SDL_Rect box = { player_1.pos_x, player_1.pos_y, */ + /* player_1.pos_x + 200, */ + /* player_1.pos_y + 200 }; */ + /* SDL_RenderFillRect(renderer, &box); */ + + /* SDL_RenderDrawLine(renderer, 0, 0, 1000, 1000); */ + + SDL_RenderGeometry(renderer, NULL, player_1.geometry, + player_1.geometry_len, NULL, 0); + + SDL_GetWindowSize(window, &win_x, &win_y); + + if (SHOW_FPS) { + fps = round(1.0f / render_time_accumulator); + sprintf(fps_text, "FPS:%.0f", fps); + + SDL_Rect fps_pos = { 0, 0, 0, 0 }; + render_text(fps_text, fps_pos, Sans, renderer); + + // show action states + if (action_states[ACTION_MOVE_UP]) { + SDL_Rect up_text = { 100, 600, 120, + 620 }; + render_text("UP", up_text, Sans, + renderer); + } + if (action_states[ACTION_MOVE_DOWN]) { + SDL_Rect up_text = { 100, 620, 120, + 640 }; + render_text("DOWN", up_text, Sans, + renderer); + } + if (action_states[ACTION_MOVE_LEFT]) { + SDL_Rect up_text = { 60, 620, 80, 640 }; + render_text("LEFT", up_text, Sans, + renderer); + } + if (action_states[ACTION_MOVE_RIGHT]) { + SDL_Rect up_text = { 140, 620, 160, + 640 }; + render_text("RIGHT", up_text, Sans, + renderer); + } + + // show player attributes + char x_speed_text[123]; + sprintf(x_speed_text, "x-speed: %f", + player_1.vel_x); + SDL_Rect x_speed_text_pos = { 900, 900, 910, + 910 }; + render_text(x_speed_text, x_speed_text_pos, + Sans, renderer); + + char y_speed_text[123]; + sprintf(y_speed_text, "y-speed: %f", + player_1.vel_y); + SDL_Rect y_speed_text_pos = { 900, 920, 910, + 930 }; + render_text(y_speed_text, y_speed_text_pos, + Sans, renderer); + } + + render_time_accumulator = 0; + SDL_RenderPresent(renderer); + } + } + + if (RENDER_ENABLED) { + TTF_CloseFont(Sans); + TTF_Quit(); + + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + } + SDL_Quit(); + return 0; +} + +void execute_actions(struct Player *player, int *action_states, float delta) +{ + if (action_states[ACTION_MOVE_UP]) { + player_move(player, UP, delta); + } + if (action_states[ACTION_MOVE_DOWN]) { + player_move(player, DOWN, delta); + } + if (action_states[ACTION_MOVE_LEFT]) { + player_move(player, LEFT, delta); + } + if (action_states[ACTION_MOVE_RIGHT]) { + player_move(player, RIGHT, delta); + } +} + +void render_text(char *text, SDL_Rect dest, TTF_Font *Sans, + SDL_Renderer *renderer) +{ + SDL_Color fps_color = { 0, 255, 0, 255 }; + SDL_Surface *surf = TTF_RenderText_Solid(Sans, text, fps_color); + + dest.w = surf->w; + dest.h = surf->h; + + SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surf); + SDL_RenderCopy(renderer, texture, NULL, &dest); + + SDL_DestroyTexture(texture); + SDL_FreeSurface(surf); +} + +double current_sdl_time_in_seconds() +{ + return ((double)SDL_GetPerformanceCounter() / + (double)SDL_GetPerformanceFrequency()); +} diff --git a/main.h b/main.h new file mode 100644 index 0000000..0a7ca75 --- /dev/null +++ b/main.h @@ -0,0 +1,11 @@ +#ifndef MAIN_H_ +#define MAIN_H_ + +#include "player.h" +#include + +void execute_actions(struct Player *player, int *action_states, float delta); +void render_text(char *text, SDL_Rect dest, TTF_Font *Sans, SDL_Renderer *renderer); +double current_sdl_time_in_seconds(); + +#endif // MAIN_H_ diff --git a/player.c b/player.c new file mode 100644 index 0000000..22e22f0 --- /dev/null +++ b/player.c @@ -0,0 +1,54 @@ +#include "player.h" +#include + +#include + +void player_accelerate(struct Player *player, int dir_x, int dir_y, float delta) +{ + double vel_x = player->vel_x + dir_x * delta * player->accel_x; + double vel_y = player->vel_y + dir_y * delta * player->accel_y; + + if (vel_x > player->max_vel_x) + vel_x = player->max_vel_x; + if (vel_x < -player->max_vel_x) + vel_x = -player->max_vel_x; + + if (vel_y > player->max_vel_y) + vel_y = player->max_vel_y; + if (vel_y < -player->max_vel_y) + vel_y = -player->max_vel_y; + + player->vel_x = vel_x; + player->vel_y = vel_y; + +} + +// TODO: field boundaries +void player_move(struct Player *player, enum Direction direction, float delta) +{ + if (direction == UP) { + player->pos_y -= player->vel_y * delta; + for (int i = 0; i < player->geometry_len; i++) { + player->geometry[i].position.y -= player->vel_y * delta; + } + } + if (direction == DOWN) { + player->pos_y += player->vel_y * delta; + for (int i = 0; i < player->geometry_len; i++) { + player->geometry[i].position.y += player->vel_y * delta; + } + } + if (direction == LEFT) { + player->pos_x -= player->vel_x * delta; + for (int i = 0; i < player->geometry_len; i++) { + player->geometry[i].position.x -= player->vel_x * delta; + } + } + if (direction == RIGHT) { + player->pos_x += player->vel_x * delta; + for (int i = 0; i < player->geometry_len; i++) { + player->geometry[i].position.x += player->vel_x * delta; + } + } + +} diff --git a/player.h b/player.h new file mode 100644 index 0000000..b250d0f --- /dev/null +++ b/player.h @@ -0,0 +1,26 @@ +#ifndef PLAYER_H_ +#define PLAYER_H_ + +#include + +struct Player { + float pos_x, pos_y; + double vel_x, vel_y; + int accel_x, accel_y; + int max_vel_x, max_vel_y; + int hp; + SDL_Vertex *geometry; + int geometry_len; +}; + +enum Direction { + UP, + DOWN, + LEFT, + RIGHT, +}; + +void player_accelerate(struct Player *player, int x, int y, float delta); +void player_move(struct Player *player, enum Direction direction, float delta); + +#endif // PLAYER_H_ diff --git a/render.h b/render.h new file mode 100644 index 0000000..e84cdfa --- /dev/null +++ b/render.h @@ -0,0 +1,6 @@ +#ifndef RENDER_H_ +#define RENDER_H_ + +void render_player(); + +#endif // RENDER_H_ diff --git a/resources/OpenSans-Regular.ttf b/resources/OpenSans-Regular.ttf new file mode 100644 index 0000000..2e31d02 Binary files /dev/null and b/resources/OpenSans-Regular.ttf differ -- cgit v1.2.3