summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkdx <kikoodx@paranoici.org>2023-03-26 18:59:06 +0200
committerkdx <kikoodx@paranoici.org>2023-03-26 18:59:06 +0200
commitccc24cda99a6972bdd92d2674da1273e499a3844 (patch)
tree476a994676d75116abb3c43959e34ab4836aa9e9
parent49fe8dd96d673c4ff63590c169815c4340bc67b0 (diff)
download006-ccc24cda99a6972bdd92d2674da1273e499a3844.tar.gz
base done
-rw-r--r--Makefile2
-rw-r--r--map/brulez.tmj65
-rw-r--r--map/tmj2c.h32
-rw-r--r--src/entity.c100
-rw-r--r--src/entity.h25
-rw-r--r--src/entityimpl.h30
-rw-r--r--src/entitytag.c4
-rw-r--r--src/entitytag.h10
-rw-r--r--src/game.c94
-rw-r--r--src/game.h19
-rw-r--r--src/main.c27
-rw-r--r--src/map.c54
-rw-r--r--src/map.h10
-rw-r--r--src/player.c17
14 files changed, 470 insertions, 19 deletions
diff --git a/Makefile b/Makefile
index 7d80fd7..74b3a51 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
CC := gcc
LD := $(CC)
WINCC := x86_64-w64-mingw32-gcc
-CFLAGS := -Os -std=c2x -Wall -Wextra -Imap -DLZR_DISABLE_DEVMODE=
+CFLAGS := -g -Os -std=c2x -Wall -Wextra -DLZR_DISABLE_DEVMODE=
LDFLAGS := -lm -lSDL2 -lSDL2_image -lSDL2_mixer -lSDL2_gfx
NAME := jambase
SRC := $(wildcard src/*.c)
diff --git a/map/brulez.tmj b/map/brulez.tmj
index 1497182..d5997f7 100644
--- a/map/brulez.tmj
+++ b/map/brulez.tmj
@@ -3,20 +3,20 @@
"infinite":false,
"layers":[
{
- "data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 5, 5, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 1, 1, 1,
- 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 1, 1,
- 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 0, 1, 1,
- 1, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 5, 5, 0, 1, 1,
- 1, 0, 0, 5, 5, 5, 0, 0, 0, 1, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 5, 0, 1, 1,
- 1, 0, 4, 5, 0, 5, 5, 0, 0, 5, 5, 1, 5, 5, 1, 0, 0, 0, 0, 0, 0, 5, 5, 0, 1,
- 1, 0, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 1, 0, 0, 0, 0, 0, 0, 5, 5, 1,
- 1, 0, 5, 0, 1, 1, 0, 5, 5, 0, 5, 5, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 5, 1,
- 1, 5, 5, 0, 1, 0, 0, 5, 0, 1, 0, 5, 0, 1, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 1,
- 1, 5, 0, 1, 1, 0, 5, 5, 0, 1, 0, 5, 0, 0, 5, 5, 0, 5, 5, 1, 0, 0, 2, 0, 1,
- 1, 0, 1, 1, 0, 5, 5, 0, 1, 1, 0, 5, 5, 5, 5, 0, 1, 0, 5, 5, 0, 1, 0, 0, 1,
- 1, 1, 1, 1, 0, 5, 0, 1, 1, 1, 1, 0, 5, 5, 0, 1, 1, 1, 0, 5, 5, 5, 5, 5, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
+ "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"height":14,
"id":1,
"name":"Tile Layer 1",
@@ -26,9 +26,42 @@
"width":25,
"x":0,
"y":0
+ },
+ {
+ "draworder":"topdown",
+ "id":2,
+ "name":"Object Layer 1",
+ "objects":[
+ {
+ "height":16,
+ "id":1,
+ "name":"player",
+ "rotation":0,
+ "type":"",
+ "visible":true,
+ "width":16,
+ "x":144,
+ "y":96
+ },
+ {
+ "height":32,
+ "id":2,
+ "name":"player",
+ "rotation":0,
+ "type":"",
+ "visible":true,
+ "width":32,
+ "x":256,
+ "y":144
+ }],
+ "opacity":1,
+ "type":"objectgroup",
+ "visible":true,
+ "x":0,
+ "y":0
}],
- "nextlayerid":2,
- "nextobjectid":1,
+ "nextlayerid":3,
+ "nextobjectid":3,
"orientation":"orthogonal",
"renderorder":"right-down",
"tiledversion":"1.10.0",
diff --git a/map/tmj2c.h b/map/tmj2c.h
new file mode 100644
index 0000000..ff5baba
--- /dev/null
+++ b/map/tmj2c.h
@@ -0,0 +1,32 @@
+#pragma once
+
+typedef struct {
+ const char *name;
+ double opacity;
+ unsigned int visible;
+ const unsigned int *data;
+} Tmj2cLayer;
+
+typedef struct {
+ const char *name;
+ const char *type;
+ unsigned int id;
+ double x;
+ double y;
+ double width;
+ double height;
+ double rotation;
+ unsigned int visible;
+} Tmj2cObject;
+
+typedef struct {
+ const char *path;
+ unsigned int width;
+ unsigned int height;
+ unsigned int tilewidth;
+ unsigned int tileheight;
+ unsigned int numlayers;
+ const Tmj2cLayer *layers;
+ unsigned int numobjects;
+ const Tmj2cObject *objects;
+} Tmj2cMap;
diff --git a/src/entity.c b/src/entity.c
new file mode 100644
index 0000000..75ad7ec
--- /dev/null
+++ b/src/entity.c
@@ -0,0 +1,100 @@
+#include "entity.h"
+#include "entitytag.h"
+#include "map.h"
+#include "game.h"
+#include <stdio.h>
+#include <string.h>
+
+static void
+_points(Entity *this, int ox, int oy, int *x0, int *x1, int *y0, int *y1)
+{
+ *x0 = this->pos[0] - this->width / 2 + ox;
+ *y0 = this->pos[1] - this->width / 2 + oy;
+ *x1 = *x0 + this->width - 1;
+ *y1 = *y0 + this->height - 1;
+}
+
+unsigned int
+entity_type(const char *typename)
+{
+ for (unsigned i = 0; i < num_entitytags; i++)
+ if (strcmp(typename, entitytags[i].name) == 0)
+ return i + 1;
+ printf("unknown type '%s'\n", typename);
+ return 0;
+}
+
+bool
+entity_collide(Entity *this, int ox, int oy)
+{
+ int x0, y0, x1, y1;
+ _points(this, ox, oy, &x0, &x1, &y0, &y1);
+ return (map_get_px(x0, y0) == 1 || map_get_px(x0, y1) == 1 ||
+ map_get_px(x1, y0) == 1 || map_get_px(x1, y1) == 1);
+}
+
+bool
+entity_meet(Entity *this, Entity *other)
+{
+ int tx0, ty0, tx1, ty1;
+ int ox0, oy0, ox1, oy1;
+ _points(this, 0, 0, &tx0, &tx1, &ty0, &ty1);
+ _points(other, 0, 0, &ox0, &ox1, &oy0, &oy1);
+ return (tx0 < ox1 && tx1 > ox0 && ty0 < oy1 && ty1 > oy0);
+}
+
+Entity *
+entity_place_meeting(Entity *this, struct Game *g, unsigned int type)
+{
+ for (__auto_type i = 0; i < MAX_ENTITIES; i++)
+ if (this != &g->entities[i] && g->entities[i].type == type &&
+ entity_meet(this, &g->entities[i]))
+ return &g->entities[i];
+ return NULL;
+}
+
+void
+entity_move(Entity *this, [[maybe_unused]] struct Game *g)
+{
+ if (this->ignore_solids) {
+ for (int a = 0; a < 2; a++) {
+ const double sum = this->vel[a] + this->rem[a];
+ int spd = (int)sum;
+ this->rem[a] = sum - spd;
+ this->pos[a] += spd;
+ }
+ return;
+ }
+ if (entity_collide(this, 0, 0)) {
+ this->vel[0] = 0.0;
+ this->vel[1] = 0.0;
+ this->rem[0] = 0.0;
+ this->rem[1] = 0.0;
+ return;
+ }
+ for (int a = 0; a < 2; a++) {
+ const double sum = this->vel[a] + this->rem[a];
+ int spd = (int)sum;
+ this->rem[a] = sum - spd;
+ const int sign = (spd > 0) - (spd < 0);
+ if (sign == 0)
+ continue;
+ while (spd != 0) {
+ this->pos[a] += sign;
+ if (entity_collide(this, 0, 0)) {
+ this->pos[a] -= sign;
+ this->rem[a] = 0.0;
+ this->vel[a] = 0.0;
+ break;
+ }
+ spd -= sign;
+ }
+ }
+}
+
+Entity *
+entity_init(Entity *this, unsigned int type, int x, int y)
+{
+ entitytags[type - 1].init(this, x, y);
+ return this;
+}
diff --git a/src/entity.h b/src/entity.h
new file mode 100644
index 0000000..01230d5
--- /dev/null
+++ b/src/entity.h
@@ -0,0 +1,25 @@
+#pragma once
+#include <stdbool.h>
+
+struct Game;
+
+typedef struct Entity Entity;
+struct Entity {
+ unsigned long uuid;
+ void (*update)(Entity *this, struct Game *g);
+ void (*draw)(Entity *this, struct Game *g);
+ unsigned int type;
+ int pos[2];
+ double vel[2];
+ double rem[2];
+ int width;
+ int height;
+ bool ignore_solids;
+};
+
+unsigned int entity_type(const char *typename);
+bool entity_collide(Entity *this, int ox, int oy);
+bool entity_meet(Entity *this, Entity *other);
+Entity *entity_place_meeting(Entity *this, struct Game *g, unsigned int type);
+void entity_move(Entity *this, struct Game *g);
+Entity *entity_init(Entity *this, unsigned int type, int x, int y);
diff --git a/src/entityimpl.h b/src/entityimpl.h
new file mode 100644
index 0000000..afc9dc2
--- /dev/null
+++ b/src/entityimpl.h
@@ -0,0 +1,30 @@
+#pragma once
+#include "game.h"
+#include "cfg.h"
+#include "lzr.h"
+#include "entitytag.h"
+#include <string.h>
+
+//[[maybe_unused]] static void *_draw;
+//[[maybe_unused]] static void *_update;
+
+#define IMPL(X) static void X(Entity *this, Game *g); \
+static void X([[maybe_unused]] Entity *this, [[maybe_unused]] Game *g)
+/*__attribute__((constructor)) static void init_##X() { _##X = X; } \ */
+
+#define IMPL_INIT(X) static void init(Entity *this, int x, int y); \
+__attribute__((constructor)) static void init_tag() { \
+ entitytags[num_entitytags].init = init; \
+ entitytags[num_entitytags++].name = #X; \
+} \
+static void _init(Entity *this); \
+static void init(Entity *this, int x, int y) { \
+ memset(this, 0, sizeof(*this)); \
+ this->update = update; \
+ this->draw = draw; \
+ this->pos[0] = x; \
+ this->pos[1] = y; \
+ this->type = entity_type(#X); \
+ _init(this); \
+} \
+static void _init([[maybe_unused]] Entity *this)
diff --git a/src/entitytag.c b/src/entitytag.c
new file mode 100644
index 0000000..de56455
--- /dev/null
+++ b/src/entitytag.c
@@ -0,0 +1,4 @@
+#include "entitytag.h"
+
+unsigned int num_entitytags = 0;
+EntityTag entitytags[256] = {};
diff --git a/src/entitytag.h b/src/entitytag.h
new file mode 100644
index 0000000..154023c
--- /dev/null
+++ b/src/entitytag.h
@@ -0,0 +1,10 @@
+#pragma once
+#include "entity.h"
+
+typedef struct {
+ const char *name;
+ void (*init)(Entity *this, int x, int y);
+} EntityTag;
+
+extern unsigned int num_entitytags;
+extern EntityTag entitytags[256];
diff --git a/src/game.c b/src/game.c
new file mode 100644
index 0000000..4cd9728
--- /dev/null
+++ b/src/game.c
@@ -0,0 +1,94 @@
+#include "game.h"
+#include "cfg.h"
+#include "entity.h"
+#include "map.h"
+#include <stdio.h>
+#include <string.h>
+
+void
+game_init(Game *this)
+{
+ memset(this, 0, sizeof(*this));
+ game_restart_scene(this);
+}
+
+void
+game_update(Game *this)
+{
+ if (this->queue_next_scene) {
+ if (--this->queue_next_scene == 0) {
+ this->queue_restart_scene = 0;
+ map_next();
+ game_restart_scene(this);
+ return;
+ }
+ }
+ if (this->queue_restart_scene) {
+ if (--this->queue_restart_scene == 0)
+ game_restart_scene(this);
+ }
+ for (__auto_type i = 0; i < MAX_ENTITIES; i++) {
+ const __auto_type e = &this->entities[i];
+ if (e->type != 0 && e->update != NULL)
+ e->update(e, this);
+ }
+}
+
+void
+game_draw(Game *this)
+{
+ map_draw();
+ for (int i = 0; i < MAX_ENTITIES; i++) {
+ const __auto_type e = &this->entities[i];
+ if (e->type != 0 && e->draw != NULL)
+ e->draw(e, this);
+ }
+}
+
+void
+game_restart_scene(Game *this)
+{
+ memset(this->entities, 0, sizeof(this->entities));
+ unsigned int size;
+ const __auto_type objects = map_objects(&size);
+ for (__auto_type i = 0u; i < size; i++) {
+ const __auto_type object = &objects[i];
+ const __auto_type type = entity_type(object->name);
+ if (type == 0)
+ continue;
+ const __auto_type x = object->x + object->width / 2;
+ const __auto_type y = object->y + object->height / 2;
+ entity_init(game_create_entity(this), type, x, y);
+ }
+}
+
+Entity *
+game_create_entity(Game *this)
+{
+ __auto_type e = &this->entities[MAX_ENTITIES - 1];
+ for (__auto_type i = 0; i < MAX_ENTITIES; i++)
+ if (this->entities[i].type == 0) {
+ e = &this->entities[i];
+ break;
+ }
+ e->uuid = this->uuid++;
+ return e;
+}
+
+int
+game_entity_count(Game *this, unsigned int type)
+{
+ int count = 0;
+ for (__auto_type i = 0; i < MAX_ENTITIES; i++)
+ count += (this->entities[i].type == type);
+ return count;
+}
+
+Entity *
+game_get_entity(Game *this, unsigned int type)
+{
+ for (__auto_type i = 0; i < MAX_ENTITIES; i++)
+ if (this->entities[i].type == type)
+ return &this->entities[i];
+ return NULL;
+}
diff --git a/src/game.h b/src/game.h
new file mode 100644
index 0000000..2d563f0
--- /dev/null
+++ b/src/game.h
@@ -0,0 +1,19 @@
+#pragma once
+#include "entity.h"
+
+enum { MAX_ENTITIES = 128 };
+
+typedef struct Game {
+ unsigned long uuid;
+ int queue_next_scene;
+ int queue_restart_scene;
+ Entity entities[MAX_ENTITIES];
+} Game;
+
+void game_init(Game *this);
+void game_update(Game *this);
+void game_draw(Game *this);
+void game_restart_scene(Game *this);
+Entity *game_create_entity(Game *this);
+int game_entity_count(Game *this, unsigned int type);
+Entity *game_get_entity(Game *this, unsigned int type);
diff --git a/src/main.c b/src/main.c
index a8db2b1..ff51bb3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,7 +1,13 @@
#include "lzr.h"
#include "cfg.h"
+#include "game.h"
+#include <stdio.h>
#include <stdlib.h>
+static Game *game = NULL;
+
+static void deinit(void);
+
int
main([[maybe_unused]] int argc, [[maybe_unused]] char **argv)
{
@@ -10,18 +16,35 @@ main([[maybe_unused]] int argc, [[maybe_unused]] char **argv)
return 1;
}
- if (atexit(LZR_Quit)) {
- LZR_Quit();
+ if (atexit(deinit)) {
+ perror("main:atexit");
+ deinit();
return 1;
}
+ if ((game = malloc(sizeof(*game))) == NULL) {
+ perror("main:malloc");
+ return 1;
+ }
+ game_init(game);
+
while (!LZR_ShouldQuit()) {
LZR_CycleEvents();
+ game_update(game);
LZR_DrawBegin();
LZR_DrawSetColor(0, 0, 0, 0);
LZR_DrawClear();
+ game_draw(game);
LZR_DrawEnd();
}
return 0;
}
+
+static void
+deinit(void)
+{
+ if (game != NULL)
+ free(game);
+ LZR_Quit();
+}
diff --git a/src/map.c b/src/map.c
new file mode 100644
index 0000000..e3fc6d2
--- /dev/null
+++ b/src/map.c
@@ -0,0 +1,54 @@
+#include "map.h"
+#include "cfg.h"
+#include "../map/maps.h"
+#include <stddef.h>
+
+static unsigned int map_id = 0;
+
+void
+map_next(void)
+{
+ if (tmj2c_maps[map_id + 1] != NULL)
+ map_id += 1;
+}
+
+int
+map_width(void)
+{
+ return tmj2c_maps[map_id]->width;
+}
+
+int
+map_height(void)
+{
+ return tmj2c_maps[map_id]->height;
+}
+
+int
+map_get(int x, int y)
+{
+ if (x < 0 || y < 0 || x >= map_width() || y >= map_height())
+ return 1;
+ return tmj2c_maps[map_id]->layers[0].data[x + y * map_width()];
+}
+
+int
+map_get_px(int x, int y)
+{
+ if (x < 0 || y < 0)
+ return 1;
+ return map_get(x / TSIZE, y / TSIZE);
+}
+
+void
+map_draw(void)
+{
+}
+
+const Tmj2cObject *
+map_objects(unsigned int *size)
+{
+ if (size != NULL)
+ *size = tmj2c_maps[map_id]->numobjects;
+ return tmj2c_maps[map_id]->objects;
+}
diff --git a/src/map.h b/src/map.h
new file mode 100644
index 0000000..325b3bc
--- /dev/null
+++ b/src/map.h
@@ -0,0 +1,10 @@
+#pragma once
+#include "../map/tmj2c.h"
+
+void map_next(void);
+int map_width(void);
+int map_height(void);
+int map_get(int x, int y);
+int map_get_px(int x, int y);
+void map_draw(void);
+const Tmj2cObject *map_objects(unsigned int *size);
diff --git a/src/player.c b/src/player.c
new file mode 100644
index 0000000..b51572b
--- /dev/null
+++ b/src/player.c
@@ -0,0 +1,17 @@
+#include "entityimpl.h"
+
+IMPL(draw) {
+ LZR_DrawSetColor(1, 1, 1, 1);
+ LZR_DrawRectangle(true, this->pos[0] - this->width / 2,
+ this->pos[1] - this->height / 2,
+ this->width, this->height);
+}
+
+IMPL(update) {
+ this->vel[0] = LZR_BUTTON(RIGHT) - LZR_BUTTON(LEFT);
+ entity_move(this, g);
+}
+
+IMPL_INIT(player) {
+ this->height = this->width = 12;
+}