From 9080d731d73b8ffbb1598f622e3bdd05e8f1938e Mon Sep 17 00:00:00 2001 From: P. J. McDermott Date: Sun, 08 Aug 2021 19:37:53 -0400 Subject: char: New "class", absorbing player --- (limited to 'src/char/char.c') diff --git a/src/char/char.c b/src/char/char.c new file mode 100644 index 0000000..09aa6bd --- /dev/null +++ b/src/char/char.c @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2021 P. J. McDermott + * + * This file is part of Maze Fight + * + * Maze Fight is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Maze Fight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Maze Fight. If not, see . + */ + +#include +#include +#include +#include +#include "../char.h" +#include "char.h" + +struct mf_char * +mf_char_new(size_t size) +{ + struct mf_char *c; + + c = calloc(1, size); + if (c == NULL) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Couldn't create character: %s", + strerror(errno)); + return NULL; + } + + return c; +} + +void +mf_char_get_vector(struct mf_char *c, int *x, int *y, int *travel, + int *dx, int *dy) +{ + *x = c->cur_x; + *y = c->cur_y; + *travel = c->travel; + switch (c->cur_dir) { + case MF_CHAR_DIR_U_: *dx = 0; *dy = -1; break; + case MF_CHAR_DIR_D_: *dx = 0; *dy = 1; break; + case MF_CHAR_DIR_L_: *dx = -1; *dy = 0; break; + case MF_CHAR_DIR_R_: *dx = 1; *dy = 0; break; + default: *dx = 0; *dy = 0; break; + } +} + +int +mf_char_update(struct mf_char *c) +{ + int dx; + int dy; + + if (c->travel > 0) { + /* Currently moving */ + c->travel += c->speed; + if (c->travel >= c->cell_width) { + /* Reached next cell */ + c->cur_x = c->new_x; + c->cur_y = c->new_y; + if (c->cur_dir == c->new_dir) { + /* Want to continue straight */ + c->travel -= c->cell_width; + } else { + /* Want to stop or turn */ + c->travel = 0; + } + } else { + /* Farther to go */ + goto end; + } + } + if (c->new_dir != MF_CHAR_DIR_N_ && c->cur_dir != c->new_dir) { + /* Want to turn */ + c->old_dir = c->cur_dir; + c->cur_dir = c->new_dir; + c->new_dir = MF_CHAR_DIR_N_; + c->turning = c->turn_time + 1; + } + if (c->turning > 0) { + /* Turning */ + --c->turning; + } + if (c->turning == 0) { + /* Done turning */ + if (c->new_dir != MF_CHAR_DIR_N_) { + /* Want to move */ + switch (c->new_dir) { + case MF_CHAR_DIR_U_: dx = 0; dy = -1; break; + case MF_CHAR_DIR_D_: dx = 0; dy = 1; break; + case MF_CHAR_DIR_L_: dx = -1; dy = 0; break; + case MF_CHAR_DIR_R_: dx = 1; dy = 0; break; + default: dx = 0; dy = 0; break; + } + c->new_dir = MF_CHAR_DIR_N_; + if (mf_maze_is_wall(c->maze, c->cur_x, c->cur_y, + dx, dy)) { + goto end; + } + c->new_x = c->cur_x + dx; + c->new_y = c->cur_y + dy; + c->travel += c->speed; + } + } + + end: + return c->update(c); +} + +int +mf_char_render(struct mf_char *c, SDL_Renderer *renderer) +{ + int e = 0; + int cx; + int cy; + double fx; + double ofx; + int r; + int x; + int y; + int i; + int oy; + int fr; + int hy; + int ox; + + cx = c->cur_x * c->cell_width + c->cell_width / 2; + cy = c->cur_y * c->cell_width + c->cell_width / 2; + switch (c->cur_dir) { + case MF_CHAR_DIR_U_: + cy -= c->travel; + if (c->old_dir == MF_CHAR_DIR_L_) { + fx = -2.0; + } else { + fx = 2.0; + } + break; + case MF_CHAR_DIR_D_: cy += c->travel; fx = 0.0; break; + case MF_CHAR_DIR_L_: cx -= c->travel; fx = -1.0; break; + case MF_CHAR_DIR_R_: cx += c->travel; fx = 1.0; break; + default: fx = 0.0; break; + } + switch (c->old_dir) { + case MF_CHAR_DIR_U_: + if (c->cur_dir == MF_CHAR_DIR_L_) { + ofx = -2.0; + } else { + ofx = 2.0; + } + break; + case MF_CHAR_DIR_D_: ofx = 0.0; break; + case MF_CHAR_DIR_L_: ofx = -1.0; break; + case MF_CHAR_DIR_R_: ofx = 1.0; break; + default: ofx = 0.0; break; + } + r = c->cell_width / 2 - c->padding; + fx = ofx + (fx - ofx) * (c->turn_time - c->turning) / c->turn_time; + fx *= r; + + /* + * Head + */ + + if (SDL_SetRenderDrawColor(renderer, + c->head_color.r, c->head_color.g, + c->head_color.b, c->head_color.a) < 0) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Couldn't render character: %s", + SDL_GetError()); + e = -1; + } + +#define _mf_char_px(X, Y) \ + do { \ + if (SDL_RenderDrawPoint(renderer, cx + X, cy + Y) < 0) { \ + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \ + "Couldn't render widget: %s", \ + SDL_GetError()); \ + e = -1; \ + } \ + } while (0) + + /* TODO: This is one pixel larger than it should be. */ + for (x = 0, y = r; y > x; ++x) { + y = round(sqrt((r-0.5)*(r-0.5) - (x-0.5)*(x-0.5)) + 0.5); + for (i = 0; i <= y; ++i) _mf_char_px( x, i); + for (i = 0; i >= 0-y; --i) _mf_char_px( x, i); + for (i = 0; i <= y; ++i) _mf_char_px(0-x, i); + for (i = 0; i >= 0-y; --i) _mf_char_px(0-x, i); + for (i = 0; i <= y; ++i) _mf_char_px( i, x); + for (i = 0; i <= y; ++i) _mf_char_px( i, 0-x); + for (i = 0; i >= 0-y; --i) _mf_char_px( i, x); + for (i = 0; i >= 0-y; --i) _mf_char_px( i, 0-x); + } + +#undef _mf_char_px + + /* + * Smile + */ + + if (SDL_SetRenderDrawColor(renderer, + c->smil_color.r, c->smil_color.g, + c->smil_color.b, c->smil_color.a) < 0) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Couldn't render character: %s", + SDL_GetError()); + e = -1; + } + + oy = r * c->smile_y; + fr = r * c->smile_r; + +#define _mf_char_px(X, Y) \ + do { \ + hy = round(sqrt((r-0.5)*(r-0.5) - \ + (X+fx-0.5)*(X+fx-0.5)) + 0.5); \ + if (Y + oy < 0-hy || Y + oy > hy) continue; \ + if (SDL_RenderDrawPoint(renderer, cx + fx + X, cy + oy + Y) \ + < 0) { \ + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \ + "Couldn't render widget: %s", \ + SDL_GetError()); \ + e = -1; \ + } \ + } while (0) + + for (x = 0, y = fr; y > x; ++x) { + y = round(sqrt((fr-0.5)*(fr-0.5) - (x-0.5)*(x-0.5)) + 0.5); + for (i = 0; i <= y; ++i) _mf_char_px( x, i); + for (i = 0; i <= y; ++i) _mf_char_px(0-x, i); + for (i = 0; i <= y; ++i) _mf_char_px( i, x); + for (i = 0; i >= 0-y; --i) _mf_char_px( i, x); + } + +#undef _mf_char_px + + /* + * Eyes + */ + + if (SDL_SetRenderDrawColor(renderer, + c->eyes_color.r, c->eyes_color.g, + c->eyes_color.b, c->eyes_color.a) < 0) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Couldn't render character: %s", + SDL_GetError()); + e = -1; + } + + ox = r * c->eye_x; + oy = r * c->eye_y; + fr = r * c->eye_r; + +#define _mf_char_px(X, Y) \ + do { \ + hy = round(sqrt((r-0.5)*(r-0.5) - \ + (X+fx-ox-0.5)*(X+fx-ox-0.5)) + 0.5); \ + if (Y - oy >= 0-hy && Y - oy <= hy) { \ + if (SDL_RenderDrawPoint(renderer, \ + cx + fx - ox + X, cy - oy + Y) \ + < 0) { \ + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \ + "Couldn't render widget: %s", \ + SDL_GetError()); \ + e = -1; \ + } \ + } \ + hy = round(sqrt((r-0.5)*(r-0.5) - \ + (X+fx+ox-0.5)*(X+fx+ox-0.5)) + 0.5); \ + if (Y - oy >= 0-hy && Y - oy <= hy) { \ + if (SDL_RenderDrawPoint(renderer, \ + cx + fx + ox + X, cy - oy + Y) \ + < 0) { \ + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \ + "Couldn't render widget: %s", \ + SDL_GetError()); \ + e = -1; \ + } \ + } \ + } while (0) + + for (x = 0, y = fr; y > x; ++x) { + y = round(sqrt((fr-0.5)*(fr-0.5) - (x-0.5)*(x-0.5)) + 0.5); + for (i = 0; i <= y; ++i) _mf_char_px( x, i); + for (i = 0; i >= 0-y; --i) _mf_char_px( x, i); + for (i = 0; i <= y; ++i) _mf_char_px(0-x, i); + for (i = 0; i >= 0-y; --i) _mf_char_px(0-x, i); + for (i = 0; i <= y; ++i) _mf_char_px( i, x); + for (i = 0; i <= y; ++i) _mf_char_px( i, 0-x); + for (i = 0; i >= 0-y; --i) _mf_char_px( i, x); + for (i = 0; i >= 0-y; --i) _mf_char_px( i, 0-x); + } + +#undef _mf_char_px + + if (e < 0) { + return e; + } + return c->render(c, renderer); +} + +void +mf_char_destroy(struct mf_char **c_p) +{ + struct mf_char *c; + + if (c_p == NULL || *c_p == NULL) { + return; + } + c = *c_p; + + c->destroy(c); + free(c); + c = NULL; +} -- cgit v0.9.1