summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorKonAki <konaki@anokonaki.org>2026-10-11 16:44:20 +0800
committerKonAki <konaki@anokonaki.org>2026-10-11 16:44:20 +0800
commitefbccda65737e4b89a6526fe7ba5405016ee9983 (patch)
treed7f17b27cfacb42946c520e6135e6b408ca41ef0 /examples
parent22348718dfdc48e417f53d5b4b4d471b622846e2 (diff)
sectorview: walk with the world module, door collider, jump
Diffstat (limited to 'examples')
-rw-r--r--examples/maps/house.kmap2
-rw-r--r--examples/sectorview.c107
2 files changed, 55 insertions, 54 deletions
diff --git a/examples/maps/house.kmap b/examples/maps/house.kmap
index 45ee4a6..50912b6 100644
--- a/examples/maps/house.kmap
+++ b/examples/maps/house.kmap
@@ -39,7 +39,7 @@ edge 1 2 wallpaper
entity spawn 4 1.6 2 0
entity light 4 2.6 2 0 color=ffe0a0 radius=8
entity button 7.8 1.2 1 270 target=door1
-entity door 8 0 2 90 name=door1 speed=2
+entity door 8 0 2 90 name=door1 speed=2 width=4 height=2.6
# a picture placed by its four corners: bottom left, bottom right, top right, top left as seen from the front.
# this one stands in the garden and faces the window
diff --git a/examples/sectorview.c b/examples/sectorview.c
index 2816461..beafc36 100644
--- a/examples/sectorview.c
+++ b/examples/sectorview.c
@@ -1,10 +1,11 @@
/*
* sectorview: walk around a map made of rooms and picture quads
*
- * build: ./build.sh -d -m 3d,sector,font obj/sectorview
+ * build: ./build.sh -d -m 3d,sector,world,font obj/sectorview
* run: obj/sectorview (from the folder with examples/)
*
- * click to grab the mouse, tab lets go. w and s walk, a and d strafe, e presses a button close to you.
+ * click to grab the mouse, tab lets go. w and s walk, a and d strafe, space jumps, e presses a button close to you.
+ * the door is a box in the world that the program lifts, nothing else about it is built in
* the map is examples/maps/house.kmap, it is plain text so change it and run again. try moving the watcher
*/
@@ -16,9 +17,10 @@
#include "konprogram.h"
#include "kon3d.h"
#include "konsector.h"
+#include "konworld.h"
-#if !defined(KON_MODULE_3D) || !defined(KON_MODULE_SECTOR) || !defined(KON_MODULE_FONT)
-#error "build with: ./build.sh -d -m 3d,sector,font obj/sectorview"
+#if !defined(KON_MODULE_3D) || !defined(KON_MODULE_SECTOR) || !defined(KON_MODULE_WORLD) || !defined(KON_MODULE_FONT)
+#error "build with: ./build.sh -d -m 3d,sector,world,font obj/sectorview"
#endif
#define MAP_PATH "examples/maps/house.kmap"
@@ -26,7 +28,8 @@
#define MAX_ENTITIES 64
#define EYE 0.7f
#define RADIUS 0.2f
-#define STEP 0.35f
+#define HEIGHT 1.0f
+#define JUMP 6.0f
#define REACH 1.6f
#define COL_SKY 0xFF1B1826u
@@ -40,9 +43,11 @@ typedef struct state {
kon_material_t materials[MAX_TEXTURES];
kon_image *marker;
kon_fp_t input; /* only used for the mouse and keys, the position is ours */
+ kon_world_t world;
+ kon_body_t body;
kon_vec3_t eye;
- float feet;
- int sector;
+ float feet; /* what the eyes follow, it catches up with the body after a step */
+ int door[MAX_ENTITIES]; /* the collider of a door entity, -1 for the others */
float open[MAX_ENTITIES]; /* how far a door is open, 0 to 1 */
int opening[MAX_ENTITIES];
char note[64];
@@ -94,39 +99,16 @@ static kon_image *makeTexture(const char *name)
return makeChecker(palette[pick][0], palette[pick][1]);
}
-/*** moving ***/
+/*** doors ***/
-/* the point is fine to stand on when it is inside the map, the step up to it is small and there is room for the head */
-static int canStand(const state_t *state, float x, float z, float feet, int hint)
+/* a door is a box across its opening, facing the way the entity does. opening it lifts the box until it is over the head */
+static void doorShape(const kon_entity_t *e, kon_vec3_t *min, kon_vec3_t *max)
{
- int s = kon_sectorAt(state->map, x, z, hint);
+ float width = kon_entityFloat(e, "width", 1.2f) * 0.5f, height = kon_entityFloat(e, "height", 2.2f);
+ int alongZ = fabsf(sinf(e->angle)) > 0.7f;
- if (s < 0) return 0;
- if (state->map->sectors[s].floor > feet + STEP) return 0;
- return state->map->sectors[s].ceiling - state->map->sectors[s].floor > EYE + 0.2f;
-}
-
-static int canStandBody(const state_t *state, float x, float z)
-{
- static const float dx[4] = { -1, 1, 1, -1 }, dz[4] = { -1, -1, 1, 1 };
- int i;
-
- for (i = 0; i < 4; i++) {
- if (!canStand(state, x + dx[i] * RADIUS, z + dz[i] * RADIUS, state->feet, state->sector)) return 0;
- }
- return 1;
-}
-
-static void walk(state_t *state, float dx, float dz)
-{
- if (canStandBody(state, state->eye.x + dx, state->eye.z + dz)) {
- state->eye.x += dx;
- state->eye.z += dz;
- } else if (canStandBody(state, state->eye.x + dx, state->eye.z)) {
- state->eye.x += dx;
- } else if (canStandBody(state, state->eye.x, state->eye.z + dz)) {
- state->eye.z += dz;
- }
+ *min = KON_VEC3(e->position.x - (alongZ ? 0.1f : width), e->position.y, e->position.z - (alongZ ? width : 0.1f));
+ *max = KON_VEC3(e->position.x + (alongZ ? 0.1f : width), e->position.y + height, e->position.z + (alongZ ? width : 0.1f));
}
/*** program ***/
@@ -137,12 +119,16 @@ static int event(kon_program_t *program, const kon_event_t *ev, void *user)
int i, n, ids[8];
if (kon_fpEvent(&state->input, program, ev)) return 1;
+ if (ev->type == KON_EVENT_KEY_DOWN && ev->key == KON_KEY_SPACE) {
+ kon_bodyJump(&state->body, JUMP);
+ return 1;
+ }
if (ev->type != KON_EVENT_KEY_DOWN || ev->key != KON_KEY_E) return 0;
/* the map only says what is where, what a button does is decided here: it opens whatever it points at */
for (i = 0; i < state->map->entityCount && i < MAX_ENTITIES; i++) {
const kon_entity_t *button = &state->map->entities[i];
- float dx = button->position.x - state->eye.x, dz = button->position.z - state->eye.z;
+ float dx = button->position.x - state->body.position.x, dz = button->position.z - state->body.position.z;
if (strcmp(button->kind, "button") != 0 || dx * dx + dz * dz > REACH * REACH) continue;
n = kon_entityTargets(state->map, button->target, ids, 8);
@@ -163,26 +149,29 @@ static void update(kon_program_t *program, double dt, void *user)
float step = state->input.speed * (float)dt;
float dx = (fx * (float)state->input.forward - fz * (float)state->input.strafe) * step;
float dz = (fz * (float)state->input.forward + fx * (float)state->input.strafe) * step;
- int i, s;
+ int i;
state->time += dt;
if (kon_debugConsoleOpen(program->debug) && kon_isMouseCaptured(program->window)) kon_setMouseCapture(program->window, false);
state->input.yaw += (float)state->input.turn * state->input.turnSpeed * (float)dt;
- walk(state, dx, dz);
- s = kon_sectorAt(state->map, state->eye.x, state->eye.z, state->sector);
- if (s >= 0) {
- state->sector = s;
- state->feet += (state->map->sectors[s].floor - state->feet) * (1.0f - expf(-12.0f * (float)dt));
- }
- state->eye.y = state->feet + EYE;
-
for (i = 0; i < state->map->entityCount && i < MAX_ENTITIES; i++) {
float speed = kon_entityFloat(&state->map->entities[i], "speed", 1.0f) * (float)dt;
if (state->opening[i] && state->open[i] < 1.0f) state->open[i] = fminf(1.0f, state->open[i] + speed);
if (!state->opening[i] && state->open[i] > 0.0f) state->open[i] = fmaxf(0.0f, state->open[i] - speed);
+ if (state->door[i] >= 0) {
+ kon_collider_t *c = kon_worldCollider(&state->world, state->door[i]);
+ kon_vec3_t min, max;
+
+ doorShape(&state->map->entities[i], &min, &max);
+ c->min.y = min.y + state->open[i] * (max.y - min.y);
+ }
}
+
+ kon_worldMove(&state->world, &state->body, dx, dz, dt);
+ state->feet += (state->body.position.y - state->feet) * (1.0f - expf(-16.0f * (float)dt));
+ if (state->body.onGround == 0) state->feet = state->body.position.y;
}
static void draw(kon_program_t *program, kon_framebuffer_t *game, void *user)
@@ -194,6 +183,7 @@ static void draw(kon_program_t *program, kon_framebuffer_t *game, void *user)
char line[96];
int i;
+ state->eye = KON_VEC3(state->body.position.x, state->feet + EYE, state->body.position.z);
camera.position = state->eye;
camera.target = KON_VEC3(state->eye.x + sinf(state->input.yaw) * cosf(state->input.pitch), state->eye.y + sinf(state->input.pitch),
state->eye.z - cosf(state->input.yaw) * cosf(state->input.pitch));
@@ -219,7 +209,7 @@ static void draw(kon_program_t *program, kon_framebuffer_t *game, void *user)
kon_fillRectangle(game, game->width / 2 - 3, game->height / 2, 7, 1, COL_NOTE);
kon_fillRectangle(game, game->width / 2, game->height / 2 - 3, 1, 7, COL_NOTE);
if (program->font) {
- snprintf(line, sizeof(line), "room %d click to look, e presses buttons", state->sector);
+ snprintf(line, sizeof(line), "room %d click to look, e presses buttons, space jumps", state->body.sector);
kon_drawText(game, program->font, 8, 16, line, COL_DIM);
if (state->note[0]) kon_drawText(game, program->font, 8, 30, state->note, COL_NOTE);
}
@@ -258,16 +248,26 @@ static int init(kon_program_t *program, void *user)
break;
}
}
- state->sector = -1;
+ kon_worldInit(&state->world);
+ state->world.sectors = state->map;
+ for (i = 0; i < MAX_ENTITIES; i++) state->door[i] = -1;
+ for (i = 0; i < state->map->entityCount && i < MAX_ENTITIES; i++) {
+ kon_vec3_t min, max;
+
+ if (strcmp(state->map->entities[i].kind, "door") != 0) continue;
+ doorShape(&state->map->entities[i], &min, &max);
+ state->door[i] = kon_worldAdd(&state->world, kon_colliderBox(min, max));
+ }
+
+ kon_bodyInit(&state->body, 0, 0, 0, RADIUS, HEIGHT);
if (state->map->entityCount > 0) {
const kon_entity_t *e = &state->map->entities[spawn];
- state->eye = e->position;
+ state->body.position = KON_VEC3(e->position.x, e->position.y, e->position.z);
state->input.yaw = e->angle;
- state->sector = kon_sectorAt(state->map, e->position.x, e->position.z, -1);
}
- if (state->sector < 0) state->sector = 0;
- state->feet = state->map->sectors[state->sector].floor;
+ kon_worldPlace(&state->world, &state->body);
+ state->feet = state->body.position.y;
return 1;
}
@@ -280,6 +280,7 @@ static void shutdown(kon_program_t *program, void *user)
for (i = 0; i < state->map->textureCount; i++) kon_freeFramebuffer(state->images[i]);
kon_freeFramebuffer(state->marker);
kon_sectorMeshFree(state->mesh);
+ kon_worldFree(&state->world);
kon_sectorFree(state->map);
}