summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorzlago2024-10-06 19:54:24 +0200
committerzlago2024-10-06 21:23:44 +0200
commitd005a7756f6d15f67a7033a53bae23d00a58af69 (patch)
treedb6abbabdbfd1ca7d3c32756042623052c43a0ce /src
parenta887634f473b9e665c54f223e24080a1492c58fe (diff)
particles and projectiles
Diffstat (limited to 'src')
-rw-r--r--src/entity.h53
-rw-r--r--src/main.c66
-rw-r--r--src/main.h6
-rw-r--r--src/player.c114
-rw-r--r--src/warp.c4
5 files changed, 210 insertions, 33 deletions
diff --git a/src/entity.h b/src/entity.h
index fe76feb..0166bdc 100644
--- a/src/entity.h
+++ b/src/entity.h
@@ -5,23 +5,29 @@
#define from_fixed(a) (a / 16)
#define to_fixed(a) (a * 16)
+struct vec2 {
+ signed x, y;
+};
+
+struct hitbox {
+ unsigned left, right, top, bottom;
+};
+
+struct anim {
+ unsigned frame;
+ SDL_Rect rect;
+ unsigned length;
+};
+
struct entity {
int (*update)(struct entity *self);
int (*hurt)(struct entity *self, int damage);
int (*draw)(struct entity *self, int camx, int camy);
void (*free)(struct entity *self);
int x, y; // unsigned results in a bunch of weird edge cases
- struct velocity {
- signed x, y;
- } velocity;
- struct hitbox {
- unsigned left, right, top, bottom;
- } hitbox;
- struct anim {
- unsigned frame;
- SDL_Rect rect;
- unsigned length;
- } anim;
+ struct vec2 velocity;
+ struct hitbox hitbox;
+ struct anim anim;
unsigned state;
int hp;
int timer;
@@ -40,3 +46,28 @@ struct warp {
unsigned timer;
void *ext;
};
+
+struct projectile {
+ int (*update)(struct projectile *self);
+ int (*draw)(struct projectile *self, int camx, int camy);
+ void (*free)(struct projectile *self);
+ int x, y; // unsigned results in a bunch of weird edge cases
+ struct vec2 velocity;
+ struct hitbox hitbox;
+ struct anim anim;
+ unsigned state;
+ int hp;
+ int timer;
+ int iframes;
+ signed facing;
+ void *texture;
+ void *ext;
+};
+
+struct particle {
+ int x, y;
+ struct vec2 velocity;
+ struct vec2 acceleration;
+ SDL_Rect rect;
+ int hp;
+};
diff --git a/src/main.c b/src/main.c
index c48deef..d5f6504 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3,6 +3,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "input.h"
#include "loader.h"
@@ -22,11 +23,13 @@ SDL_Renderer *renderer = NULL;
enum game_state game_state = STATE_PLAYING;
char *game_next_level;
+static void *particle_tex = NULL;
+
#define WINDOW_WIDTH 160
#define WINDOW_HEIGHT 90
#define INIT_SUBSYSTEMS SDL_INIT_VIDEO
-unsigned input_now = 0;
+unsigned input_pressed = 0, input_held = 0;
SDL_Scancode keybinds[] = {
SDL_SCANCODE_UP,
SDL_SCANCODE_DOWN,
@@ -64,6 +67,8 @@ void entities_free(struct entities *entities) {
int entities_load(struct entities *entities, char *data, size_t size, size_t input_bytes) {
entities->enemies = 0;
entities->warps = 0;
+ entities->projectiles = 0;
+ entities->particles = 0;
data += input_bytes;
size -= input_bytes;
while (size) {
@@ -138,6 +143,31 @@ int game_update(void) {
entities.warp[i].update(entities.warp + i);
}
+ for (int i = 0, e = 0; i < 64 && e < entities.projectiles; i++) {
+ if (entities.projectile[i].state) {
+ e++;
+ if (entities.projectile[i].update(entities.projectile + i)) {
+ entities.projectiles--;
+ if (entities.projectile + i != entities.projectile + entities.projectiles) {
+ memcpy(entities.projectile + i, entities.projectile + entities.projectiles, sizeof (struct projectile));
+ }
+ continue;
+ }
+ }
+ }
+
+ for (int i = 0; i < entities.particles; i++) {
+ if (entities.particle[i].hp-- == 0) {
+ entities.particles--;
+ if (entities.particle + i != entities.particle + entities.particles) {
+ memcpy(entities.particle + i, entities.particle + entities.particles, sizeof (struct particle));
+ }
+ continue;
+ }
+ entities.particle[i].x += (entities.particle[i].velocity.x += entities.particle[i].acceleration.x);
+ entities.particle[i].y += (entities.particle[i].velocity.y += entities.particle[i].acceleration.y);
+ }
+
return 0;
}
@@ -151,8 +181,17 @@ void game_render(SDL_Texture *framebuffer, int x, int y) {
entities.enemy[i].draw(entities.enemy + i, x, y);
}
}
+ for (int i = 0, e = 0; i < 64 && e < entities.projectiles; i++) {
+ if (entities.projectile[i].state) {
+ e++;
+ entities.projectile[i].draw(entities.projectile + i, x, y);
+ }
+ }
+ for (int i = 0; i < entities.particles; i++) {
+ struct particle *self = entities.particle + i;
+ SDL_RenderCopy(renderer, particle_tex, &self->rect, &(SDL_Rect) {from_fixed(self->x) - x, from_fixed(self->y) - y, self->rect.w, self->rect.h});
+ }
tilemap_foreground(tilemap, x, y, WINDOW_WIDTH, WINDOW_HEIGHT);
- //SDL_RenderCopy(renderer, res_get_texture("meow").data, &(SDL_Rect) {0, 0, 128, 90}, &(SDL_Rect) {0, 0, 128, 90});
}
void game_render_flush(SDL_Texture *framebuffer) {
@@ -174,8 +213,8 @@ int main(int const argc, char *const *const argv) {
{"border", 2, NULL, 'b'},
{NULL, 0, NULL, 0 },
};
- int opt, li;
- unsigned scale = 0, flags = 0, error = 0;
+ int opt, li, scale = 0;
+ unsigned flags = 0, error = 0;
while ((opt = getopt_long(argc, argv, "h", opts, &li)) != -1) {
switch (opt) {
case 'h':
@@ -199,9 +238,9 @@ int main(int const argc, char *const *const argv) {
case 'f':
if (optarg == NULL || strcmp(optarg, "true") == 0) {
- flags |= SDL_WINDOW_FULLSCREEN;
+ flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
} else if (strcmp(optarg, "false") == 0) {
- flags &= ~SDL_WINDOW_FULLSCREEN;
+ flags &= ~SDL_WINDOW_FULLSCREEN_DESKTOP;
} else {
fprintf(stderr, "%s=%s -- expected 'true' or 'false'\n", opts[li].name, optarg);
error = 1;
@@ -243,7 +282,7 @@ int main(int const argc, char *const *const argv) {
return EXIT_FAILURE;
}
SDL_StopTextInput();
- if (scale == 0) {
+ if (scale <= 0) {
SDL_DisplayMode dm;
if (SDL_GetDesktopDisplayMode(0, &dm) != 0) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "couldnt get desktop size", SDL_GetError(), NULL);
@@ -299,6 +338,8 @@ int main(int const argc, char *const *const argv) {
optind++;
}
}
+
+ particle_tex = res_get_texture("particles").data;
struct blob blob = res_get_map("untitled");
next_tilemap = tilemap_load(blob.data, blob.size);
@@ -339,6 +380,7 @@ int main(int const argc, char *const *const argv) {
player_property(next_entities.player, "y", "64");
memcpy(&entities, &next_entities, sizeof (entities));
while (1) {
+ input_pressed = input_held;
SDL_Event evt;
while (SDL_PollEvent(&evt)) {
switch (evt.type) {
@@ -355,16 +397,16 @@ int main(int const argc, char *const *const argv) {
goto end;
}
- //static_assert(INPUT_LENGTH <= sizeof(input_now) * CHAR_BIT); // if this trips up, scope creep happened
+ //static_assert(INPUT_LENGTH <= sizeof(input_held) * CHAR_BIT); // if this trips up, scope creep happened
for (unsigned key = 0, bit = 1; key < INPUT_LENGTH; key++, bit <<= 1) {
if (evt.key.keysym.scancode == keybinds[key]) {
if (evt.key.state == SDL_PRESSED)
- input_now |= bit;
+ input_held |= bit;
else
- input_now &= ~bit;
+ input_held &= ~bit;
}
}
- //fprintf(stderr, "input: %0*b\n", INPUT_LENGTH, input_now);
+ //fprintf(stderr, "input: %0*b\n", INPUT_LENGTH, input_held);
break;
case SDL_MOUSEMOTION: // the cursor moves
//fprintf(stderr, "mouse at %4i %4i\n", evt.motion.x, evt.motion.y);
@@ -434,6 +476,8 @@ int main(int const argc, char *const *const argv) {
fprintf(stderr, "unknown event type %i\n", evt.type);
}
}
+ input_pressed = ~input_pressed & input_held;
+ //fprintf(stderr, "input: %0*b\n", INPUT_LENGTH, input_pressed);
switch (game_state) {
case STATE_PLAYING:
diff --git a/src/main.h b/src/main.h
index d743ce7..ef214bb 100644
--- a/src/main.h
+++ b/src/main.h
@@ -5,14 +5,18 @@
extern SDL_Window *window;
extern SDL_Renderer *renderer;
-extern unsigned input_now;
+extern unsigned input_pressed, input_held;
extern struct entities {
struct entity player[1];
struct entity enemy[64];
unsigned enemies;
+ struct projectile projectile[64];
+ unsigned projectiles;
struct warp warp[16];
unsigned warps;
+ struct particle particle[64];
+ unsigned particles;
} entities, next_entities;
extern enum game_state {
diff --git a/src/player.c b/src/player.c
index 0f0025e..a6fa86d 100644
--- a/src/player.c
+++ b/src/player.c
@@ -4,6 +4,7 @@
#include "input.h"
#include "tilemap.h"
#include <stdbool.h>
+#include <math.h>
#define SIZE 4
#define ACCELERATION 1
@@ -44,13 +45,50 @@ struct anim player_anims[] = {
{PLAYER_A_FALL2, {48, 0, 16, 16}, 15},
};
+static int slash_update(struct projectile *self) {
+ self->x += self->velocity.x;
+ self->y += self->velocity.y;
+ self->hp--;
+ #if 0
+ struct particle *part = entities.particle + entities.particles;
+ part->x = self->x + to_fixed(self->facing >= 0? sin(self->hp): -sin(self->hp)) * 6;
+ part->y = self->y - to_fixed(cos(self->hp)) * 4;
+ part->velocity = (struct vec2) {0, 0};
+ part->rect = (SDL_Rect) {0, 0, 4, 4};
+ part->acceleration = (struct vec2) {0, 0};
+ part->hp = 5;
+ entities.particles++;
+ #endif
+ if (self->hp == 0) {
+ return 1;
+ self->state = 0;
+ }
+ return 0;
+}
+
+static int slash_draw(struct projectile *self, int camX, int camY) {
+ //SDL_Rect rect = self->anim.rect;
+ //SDL_RenderCopy(renderer, self->texture, &rect, &(SDL_Rect) {from_fixed(self->x) - camX - 8, from_fixed(self->y) - camY - 12, 16, 16});
+ //SDL_RenderFillRect(renderer, &(SDL_Rect) {from_fixed(self->x) - camX - 8, from_fixed(self->y) - camY - 12, 16, 16});
+ int const x = from_fixed(self->x) - camX, y = from_fixed(self->y) - camY;
+ SDL_Vertex vertices[3] = {
+ {.position = {x + from_fixed(self->velocity.x) + ((self->facing >= 0)? sin(self->hp - 1): -sin(self->hp - 1)) * 8, y - cos(self->hp - 1) * 6}, .color = {255, 127, 0, 255}},
+ {.position = {x + ((self->facing >= 0)? sin(self->hp + 0): -sin(self->hp + 0)) * 8, y - cos(self->hp + 0) * 6}, .color = {255, 127, 0, 255}},
+ {.position = {x - from_fixed(self->velocity.x) + ((self->facing >= 0)? sin(self->hp + 1): -sin(self->hp + 1)) * 8, y - cos(self->hp + 1) * 6}, .color = {255, 127, 0, 255}},
+ };
+ SDL_RenderGeometry(renderer, NULL, vertices, 3, NULL, 0);
+ return 0;
+}
+
+static void slash_free(struct projectile *self) {}
+
static collision_T collide(struct entity *self) {
return tilemap_area(tilemap, from_fixed(self->x) - SIZE / 2, from_fixed(self->y) - SIZE, from_fixed(self->x) + SIZE / 2, from_fixed(self->y));
}
static int move(struct entity *self) {
int on_ground = false;
- int dx = (input_right(input_now) - input_left(input_now)) * ACCELERATION;
+ int dx = (input_right(input_held) - input_left(input_held)) * ACCELERATION;
self->velocity.x += dx;
// deaccel
if (dx == 0) {
@@ -114,6 +152,32 @@ static int move(struct entity *self) {
return on_ground;
}
+static void attack(struct entity *self) {
+ if (!input_s(input_pressed)) {
+ return;
+ }
+ entities.projectile[entities.projectiles] = (struct projectile) {
+ .update = slash_update,
+ .draw = slash_draw,
+ .free = slash_free,
+ .x = self->x + to_fixed(self->facing) * 4, .y = self->y - to_fixed(3),
+ .velocity = (struct vec2) {self->velocity.x, 0},
+ .hitbox = {
+ 0, 0, 0, 0,
+ },
+ .state = PLAYER_IDLE,
+ .hp = 4,
+ .timer = 0,
+ .facing = self->facing,
+ .iframes = 0,
+ .texture = NULL,
+ .ext = NULL,
+ };
+ //anim(entities->projectile + entities->projectiles, ENEMY_A_IDLE);
+ //entities->projectile[entities->projectiles].texture = res_get_texture("fywi").data;
+ entities.projectiles++;
+}
+
static void anim(struct entity *self, unsigned anim) {
self->anim = player_anims[anim];
}
@@ -130,36 +194,47 @@ static int player_update(struct entity *self) {
anim(self, PLAYER_A_FALL);
self->state = PLAYER_FALL;
}
- if (input_right(input_now) - input_left(input_now)) {
+ if (input_right(input_held) - input_left(input_held)) {
anim(self, PLAYER_A_WALK);
self->state = PLAYER_WALK;
}
- if (input_a(input_now)) {
+ if (input_a(input_held)) {
self->velocity.y = -JUMP;
anim(self, PLAYER_A_JUMP);
self->state = PLAYER_JUMP;
}
+ attack(self);
break;
- case PLAYER_WALK:
+ case PLAYER_WALK:;
+ struct particle *part = entities.particle + entities.particles;
+ part->x = self->x - to_fixed(self->facing) * 3 - to_fixed(1);
+ part->y = self->y - 2;
+ part->velocity = (struct vec2) {-self->velocity.x, -8};
+ part->rect = (SDL_Rect) {0, 0, 4, 4};
+ part->acceleration = (struct vec2) {0, 1};
+ part->hp = 5;
+ entities.particles++;
+
if (move(self) == false) {
self->velocity.y = 0;
anim(self, PLAYER_A_FALL);
self->state = PLAYER_FALL;
}
- if (!(input_right(input_now) - input_left(input_now))) {
+ if (!(input_right(input_held) - input_left(input_held))) {
anim(self, PLAYER_A_IDLE);
self->state = PLAYER_IDLE;
}
- if (input_a(input_now)) {
+ if (input_a(input_held)) {
self->velocity.y = -JUMP;
anim(self, PLAYER_A_JUMP);
self->state = PLAYER_JUMP;
}
+ attack(self);
break;
case PLAYER_JUMP:
- if (!input_a(input_now)) {
+ if (!input_a(input_held)) {
self->velocity.y /= 2;
anim(self, PLAYER_A_FALL);
self->state = PLAYER_FALL;
@@ -174,10 +249,21 @@ static int player_update(struct entity *self) {
}
break;
- case PLAYER_FALL:
+ case PLAYER_FALL:;
+ int yy = self->velocity.y;
if (move(self) == true) {
anim(self, PLAYER_A_IDLE);
self->state = PLAYER_IDLE;
+ for (int x = -2; x <= 2; x++) {
+ struct particle *part = entities.particle + entities.particles;
+ part->x = self->x;
+ part->y = self->y;
+ part->velocity = (struct vec2) {x * 5, -yy / 4 - 8};
+ part->rect = (SDL_Rect) {0, 0, 4, 4};
+ part->acceleration = (struct vec2) {0, 1};
+ part->hp = yy / 2;
+ entities.particles++;
+ }
}
break;
}
@@ -195,6 +281,18 @@ static int player_hurt(struct entity *self, int damage) {
if (self->iframes == 0) {
self->hp -= damage;
self->iframes = 60;
+ for (int x = -1; x <= 1; x += 2) {
+ for (int y = -1; y <= 1; y += 2) {
+ struct particle *part = entities.particle + entities.particles;
+ part->x = self->x;
+ part->y = self->y;
+ part->velocity = (struct vec2) {to_fixed(x), to_fixed(y) - 8};
+ part->rect = (SDL_Rect) {0, 0, 4, 4};
+ part->acceleration = (struct vec2) {0, 1};
+ part->hp = 30;
+ entities.particles++;
+ }
+ }
}
return 0;
}
diff --git a/src/warp.c b/src/warp.c
index f36b716..3556ef3 100644
--- a/src/warp.c
+++ b/src/warp.c
@@ -15,8 +15,8 @@ static int warp_update(struct warp *self) {
}
game_next_level = self->ext;
memcpy(next_entities.player, entities.player, sizeof (entities.player));
- next_entities.player[0].x = self->tox * 16;
- next_entities.player[0].y = self->toy * 16;
+ next_entities.player[0].x = to_fixed(self->tox);
+ next_entities.player[0].y = to_fixed(self->toy);
game_state = STATE_FADE_IN;
self->ext = NULL;
return 0;