commit ea6ee34572d0f5103be1022f0ae4b6f3b27fe158
parent d928191f038dc512524523aab1d407d3871e198b
Author: beep <beep@wimdupont.com>
Date: Sat, 4 Apr 2026 17:07:17 +0000
Add slime sprite sheet and controls man page
Diffstat:
6 files changed, 65 insertions(+), 8 deletions(-)
diff --git a/Makefile b/Makefile
@@ -10,6 +10,8 @@ HERO_SRC = assets/vendor/base-character-16x16/Hero.png
HERO_BMP = $(OBJDIR)/assets/hero.bmp
ITEMS_SRC = assets/vendor/16x16-rpg-items/items.png
ITEMS_BMP = $(OBJDIR)/assets/items.bmp
+CRITTERS_SRC = assets/vendor/16x16-animated-critters/16x16babies.png
+CRITTERS_BMP = $(OBJDIR)/assets/critters.bmp
SRC = \
src/engine/world.c \
@@ -37,9 +39,9 @@ endif
.PHONY: all clean render-smoke smoke
-all: $(BIN) $(MAPBIN) $(TILESET_BMP) $(HERO_BMP) $(ITEMS_BMP)
+all: $(BIN) $(MAPBIN) $(TILESET_BMP) $(HERO_BMP) $(ITEMS_BMP) $(CRITTERS_BMP)
-$(BIN): $(OBJ) $(MAPBIN) $(TILESET_BMP) $(HERO_BMP) $(ITEMS_BMP)
+$(BIN): $(OBJ) $(MAPBIN) $(TILESET_BMP) $(HERO_BMP) $(ITEMS_BMP) $(CRITTERS_BMP)
@mkdir -p $(dir $@)
$(CC) $(OBJ) -o $@ $(LDLIBS)
@@ -67,6 +69,10 @@ $(ITEMS_BMP): $(ITEMS_SRC)
@mkdir -p $(dir $@)
magick $< BMP3:$@
+$(CRITTERS_BMP): $(CRITTERS_SRC)
+ @mkdir -p $(dir $@)
+ magick $< -alpha off BMP3:$@
+
smoke: $(BIN)
$(BIN) --smoke-test
diff --git a/README.adoc b/README.adoc
@@ -38,6 +38,13 @@ With SDL3 available, run the game normally:
./bin/phantasia
----
+Read the man page for controls:
+
+[source,sh]
+----
+man ./phantasia.6
+----
+
== Maps
Map source files live in `data/maps/*.txt`.
diff --git a/assets/vendor/16x16-animated-critters/16x16babies.png b/assets/vendor/16x16-animated-critters/16x16babies.png
Binary files differ.
diff --git a/assets/vendor/16x16-animated-critters/SOURCE.txt b/assets/vendor/16x16-animated-critters/SOURCE.txt
@@ -0,0 +1,4 @@
+16x16 Animated Critters
+Author: patvanmackelberg
+License: CC0
+Source: https://opengameart.org/content/16x16-animated-critters
diff --git a/phantasia.6 b/phantasia.6
@@ -0,0 +1,31 @@
+.Dd April 4, 2026
+.Dt PHANTASIA 6
+.Os
+.Sh NAME
+.Nm phantasia
+.Nd 2D SDL3 RPG prototype
+.Sh SYNOPSIS
+.Nm
+.Op Fl -smoke-test
+.Op Fl -render-smoke-test
+.Sh DESCRIPTION
+.Nm
+is a small top-down RPG prototype with map movement, item pickup, and visible
+in-world entities.
+.Sh KEYBINDINGS
+.Bl -tag -width "Arrow keys / WASD"
+.It Arrow keys / WASD
+Move the player.
+.It Space / E
+Interact and pick up nearby loot.
+.It Window close button
+Quit the game.
+.El
+.Sh OPTIONS
+.Bl -tag -width Ds
+.It Fl -smoke-test
+Run a headless world-update smoke test.
+.It Fl -render-smoke-test
+Run a headless software-render smoke test and save a frame dump to
+.Pa obj/render-smoke.bmp .
+.El
diff --git a/src/game/main.c b/src/game/main.c
@@ -27,12 +27,14 @@ enum {
#define PH_TILESET_PATH "obj/assets/overworld_tileset_grass.bmp"
#define PH_HERO_PATH "obj/assets/hero.bmp"
#define PH_ITEMS_PATH "obj/assets/items.bmp"
+#define PH_CRITTERS_PATH "obj/assets/critters.bmp"
#define PH_RENDER_SMOKE_PATH "obj/render-smoke.bmp"
enum {
PH_TILESET_COLUMNS = 12,
PH_HERO_COLUMNS = 8,
PH_ITEMS_COLUMNS = 8,
+ PH_CRITTERS_COLUMNS = 16,
PH_TILE_GRASS = 13,
PH_TILE_BLOCKED = 61,
};
@@ -42,6 +44,7 @@ typedef struct {
SDL_Texture *tileset;
SDL_Texture *hero;
SDL_Texture *items;
+ SDL_Texture *critters;
} PhAssets;
#endif
@@ -71,8 +74,8 @@ ph_make_world(PhWorld *world)
.name = "Mire Slime",
.max_hp = 12,
.move_speed = 45,
- .sprite_tile_x = -1,
- .sprite_tile_y = -1,
+ .sprite_tile_x = 12,
+ .sprite_tile_y = 0,
.kind = PH_ENTITY_MONSTER,
});
ph_world_add_item_def(world, (PhItemDef){
@@ -157,11 +160,13 @@ ph_load_assets(PhAssets *assets, SDL_Renderer *renderer)
assets->tileset = ph_load_sprite_sheet(renderer, PH_TILESET_PATH, 0, 0, 0);
assets->hero = ph_load_sprite_sheet(renderer, PH_HERO_PATH, 0, 0, 0);
assets->items = ph_load_sprite_sheet(renderer, PH_ITEMS_PATH, 111, 119, 109);
+ assets->critters = ph_load_sprite_sheet(renderer, PH_CRITTERS_PATH, 129, 255, 94);
- if (!assets->tileset || !assets->hero || !assets->items) {
+ if (!assets->tileset || !assets->hero || !assets->items || !assets->critters) {
SDL_DestroyTexture(assets->tileset);
SDL_DestroyTexture(assets->hero);
SDL_DestroyTexture(assets->items);
+ SDL_DestroyTexture(assets->critters);
memset(assets, 0, sizeof(*assets));
return -1;
}
@@ -174,6 +179,7 @@ ph_destroy_assets(PhAssets *assets)
SDL_DestroyTexture(assets->tileset);
SDL_DestroyTexture(assets->hero);
SDL_DestroyTexture(assets->items);
+ SDL_DestroyTexture(assets->critters);
memset(assets, 0, sizeof(*assets));
}
@@ -267,13 +273,16 @@ ph_draw_entities(SDL_Renderer *renderer, const PhAssets *assets, const PhWorld *
continue;
}
- if (def->kind == PH_ENTITY_PLAYER && def->sprite_tile_x >= 0 && def->sprite_tile_y >= 0) {
+ if (def->sprite_tile_x >= 0 && def->sprite_tile_y >= 0 &&
+ (def->kind == PH_ENTITY_PLAYER || def->kind == PH_ENTITY_MONSTER)) {
+ SDL_Texture *sheet = def->kind == PH_ENTITY_PLAYER ? assets->hero : assets->critters;
+ int columns = def->kind == PH_ENTITY_PLAYER ? PH_HERO_COLUMNS : PH_CRITTERS_COLUMNS;
+
rect.x = entity->pos.x - world->camera.pos.x - 8.0f;
rect.y = entity->pos.y - world->camera.pos.y - 12.0f;
rect.w = 16.0f;
rect.h = 16.0f;
- ph_draw_sprite(renderer, assets->hero, PH_HERO_COLUMNS,
- def->sprite_tile_x, def->sprite_tile_y, rect);
+ ph_draw_sprite(renderer, sheet, columns, def->sprite_tile_x, def->sprite_tile_y, rect);
} else {
rect.x = entity->pos.x - world->camera.pos.x - 7.0f;
rect.y = entity->pos.y - world->camera.pos.y - 12.0f;