diff options
| author | KonAki <konaki@anokonaki.org> | 2026-10-12 03:25:20 +0800 |
|---|---|---|
| committer | KonAki <konaki@anokonaki.org> | 2026-10-12 03:25:20 +0800 |
| commit | ca1f5cd724644aee01d01b4d12d52f8893e01e54 (patch) | |
| tree | 676cc0d8d3a32f3192c6d6397860e7597d5cb8d9 | |
| parent | dbe7d0e0eeeabf6a4df16ef98d0a1f8d53b62d8b (diff) | |
split platformer out of 2d so 2d is only camera and animation
| -rw-r--r-- | README.md | 3 | ||||
| -rwxr-xr-x | build.sh | 6 | ||||
| -rw-r--r-- | examples/platform.c | 7 | ||||
| -rw-r--r-- | kon/kon2d.c | 66 | ||||
| -rw-r--r-- | kon/kon2d.h | 37 | ||||
| -rw-r--r-- | kon/konplatformer.c | 92 | ||||
| -rw-r--r-- | kon/konplatformer.h | 67 |
7 files changed, 168 insertions, 110 deletions
@@ -31,7 +31,8 @@ The engine modules are a `.h` and a `.c` pair, they depend on each other a bit, | font | konfont | | toml | kontoml | | tile | tilemaps and sprite sheets | -| 2d | platformer body with coyote time and jump buffering, a scrolling camera, frame animation (adds tile) | +| 2d | what any 2D game needs: a scrolling camera, frame animation, drawing frames of a sprite sheet | +| platformer | a box that runs and jumps through a tilemap, with coyote time and jump buffering (adds tile) | | 3d | first person kit: mouse look body, walls from a tilemap, editable hill terrain (adds tile) | | sector | maps made of rooms (vertices, floors, ceilings, walls) with entities like doors and buttons, in a text format | | world | one place to move bodies through sector maps, terrain, tilemaps and your own boxes, cylinders, spheres and planes (needs 3d, sector) | @@ -12,7 +12,7 @@ developer=0 usage() { echo "usage: build.sh [-d] [-D] [-p platform] [-m module,...] [-o objdir] [target ...]" - echo "modules: font toml tile pack ui debug assets image audio mic model 2d 3d sector world" + echo "modules: font toml tile pack ui debug assets image audio mic model 2d platformer 3d sector world" echo "platforms: native linux bsd windows" echo "targets: all run clean tools pack examples" exit 1 @@ -77,7 +77,7 @@ addobj() for m in $modules; do DEFS="$DEFS -DKON_MODULE_$(echo "$m" | tr 'a-z' 'A-Z')" case $m in - font|toml|tile|pack|ui|debug|2d|3d|sector|world) addobj "kon$m" ;; + font|toml|tile|pack|ui|debug|2d|platformer|3d|sector|world) addobj "kon$m" ;; assets) addobj konassets ;; model) addobj konmodel; addobj konassets ;; image) addobj stb_image ;; @@ -106,7 +106,7 @@ need() case " $modules " in *" debug "*) need font; need assets ;; esac case " $modules " in *" ui "*) need font ;; esac case " $modules " in *" world "*) need 3d; need sector; need tile ;; esac -case " $modules " in *" 2d "*) need tile ;; esac +case " $modules " in *" platformer "*) need tile ;; esac case " $modules " in *" 3d "*) need tile ;; esac case " $modules " in *" model "*) need assets ;; esac case " $DEFS " in *" -DKON_MODULE_ASSETS "*) need pack ;; esac diff --git a/examples/platform.c b/examples/platform.c index 1ac48fb..b6f65ea 100644 --- a/examples/platform.c +++ b/examples/platform.c @@ -1,7 +1,7 @@ /* * platform: a box that runs and jumps around a tilemap with a camera that follows it, and a ray that follows the mouse * - * build: ./build.sh -d -m 2d,font obj/platform + * build: ./build.sh -d -m 2d,platformer,font obj/platform * run: obj/platform * * left and right or a and d run, space or up jumps. the line from the box to the mouse stops at the first solid tile @@ -14,9 +14,10 @@ #include "konprogram.h" #include "kontile.h" #include "kon2d.h" +#include "konplatformer.h" -#if !defined(KON_MODULE_2D) || !defined(KON_MODULE_TILE) || !defined(KON_MODULE_FONT) -#error "build with: ./build.sh -d -m 2d,font obj/platform" +#if !defined(KON_MODULE_2D) || !defined(KON_MODULE_PLATFORMER) || !defined(KON_MODULE_TILE) || !defined(KON_MODULE_FONT) +#error "build with: ./build.sh -d -m 2d,platformer,font obj/platform" #endif #define TILE 16 diff --git a/kon/kon2d.c b/kon/kon2d.c index 2cc9fdd..8ce56d8 100644 --- a/kon/kon2d.c +++ b/kon/kon2d.c @@ -27,72 +27,6 @@ #include <math.h> -#define STEP (1.0 / 120.0) -#define MAX_FRAME 0.25 - -/*** platformer ***/ - -void kon_platformerInit(kon_platformer_t *p, kon_box2_t box) -{ - kon_platformer_t zero = {0}; - - *p = zero; - p->box = box; - p->runSpeed = 120.0f; - p->groundAccel = 18.0f; - p->airAccel = 8.0f; - p->gravity = 700.0f; - p->jumpSpeed = 260.0f; - p->jumpCut = 60.0f; - p->maxFall = 400.0f; - p->coyoteTime = 0.08f; - p->bufferTime = 0.1f; -} - -int kon_platformerStep(kon_platformer_t *p, const kon_tilemap_t *map, const uint8_t *solid, int solidCount, float dt) -{ - float run = (float)p->moveX * p->runSpeed; - float ease = (p->onGround ? p->groundAccel : p->airAccel) * dt; - int flags; - - if (ease > 1.0f) ease = 1.0f; - p->velocity.x += (run - p->velocity.x) * ease; - p->velocity.y += p->gravity * dt; - if (p->velocity.y > p->maxFall) p->velocity.y = p->maxFall; - - if (p->jumpHeld && !p->jumpWas) p->buffer = p->bufferTime; - p->jumpWas = p->jumpHeld; - if (p->buffer > 0.0f) p->buffer -= dt; - if (p->coyote > 0.0f) p->coyote -= dt; - - if (p->buffer > 0.0f && p->coyote > 0.0f) { - p->velocity.y = -p->jumpSpeed; - p->buffer = 0.0f; - p->coyote = 0.0f; - } - if (!p->jumpHeld && p->velocity.y < -p->jumpCut) p->velocity.y = -p->jumpCut; - - flags = kon_tilemapMove(map, &p->box, p->velocity.x * dt, p->velocity.y * dt, solid, solidCount); - - if (flags & (KON_HIT_LEFT | KON_HIT_RIGHT)) p->velocity.x = 0.0f; - if (flags & (KON_HIT_UP | KON_HIT_DOWN)) p->velocity.y = 0.0f; - p->onGround = (flags & KON_HIT_DOWN) != 0; - if (p->onGround) p->coyote = p->coyoteTime; - return flags; -} - -void kon_platformerUpdate(kon_platformer_t *p, const kon_tilemap_t *map, const uint8_t *solid, int solidCount, double dt) -{ - if (!(dt > 0.0)) return; - if (dt > MAX_FRAME) dt = MAX_FRAME; - - p->leftover += (float)dt; - while (p->leftover >= (float)STEP) { - kon_platformerStep(p, map, solid, solidCount, (float)STEP); - p->leftover -= (float)STEP; - } -} - /*** camera ***/ static float clampAxis(float value, float view, float bounds) diff --git a/kon/kon2d.h b/kon/kon2d.h index 7a58dc6..fce4bb2 100644 --- a/kon/kon2d.h +++ b/kon/kon2d.h @@ -27,43 +27,6 @@ #define KON2D_H #include "konsofren.h" -#include "koncollide.h" -#include "kontile.h" - -/*** platformer ***/ - -/* a box that runs and jumps through a tilemap. the game sets moveX and jumpHeld every frame, calls kon_platformerUpdate and reads - box, velocity and onGround back. everything is in map pixels and seconds. kon_platformerInit fills in the tuning values, - change them afterwards as you like */ -typedef struct kon_platformer { - kon_box2_t box; - kon_vec2_t velocity; - int onGround; - - int moveX; /* -1 left, 0 stand, 1 right */ - int jumpHeld; - - float runSpeed; - float groundAccel, airAccel; /* how fast velocity.x closes in on the run speed, per second */ - float gravity; - float jumpSpeed; - float jumpCut; /* letting go of jump early slows the rise to this speed */ - float maxFall; - float coyoteTime; /* seconds after leaving a ledge a jump still works */ - float bufferTime; /* seconds before landing a jump press is remembered */ - - /* private */ - float coyote, buffer, leftover; - int jumpWas; -} kon_platformer_t; - -void kon_platformerInit(kon_platformer_t *p, kon_box2_t box); - -/* one step of dt seconds, dt should be small and steady. returns the KON_HIT_ flags of the move */ -int kon_platformerStep(kon_platformer_t *p, const kon_tilemap_t *map, const uint8_t *solid, int solidCount, float dt); - -/* takes the frame time and runs steps of 1/120 of a second, so the jump feels the same at any frame rate */ -void kon_platformerUpdate(kon_platformer_t *p, const kon_tilemap_t *map, const uint8_t *solid, int solidCount, double dt); /*** camera ***/ diff --git a/kon/konplatformer.c b/kon/konplatformer.c new file mode 100644 index 0000000..9d22c67 --- /dev/null +++ b/kon/konplatformer.c @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: MIT */ +/* + * konplatformer.c + * + * Copyright (c) 2026 KonAki + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "konplatformer.h" + +#define STEP (1.0 / 120.0) +#define MAX_FRAME 0.25 + +/*** platformer ***/ + +void kon_platformerInit(kon_platformer_t *p, kon_box2_t box) +{ + kon_platformer_t zero = {0}; + + *p = zero; + p->box = box; + p->runSpeed = 120.0f; + p->groundAccel = 18.0f; + p->airAccel = 8.0f; + p->gravity = 700.0f; + p->jumpSpeed = 260.0f; + p->jumpCut = 60.0f; + p->maxFall = 400.0f; + p->coyoteTime = 0.08f; + p->bufferTime = 0.1f; +} + +int kon_platformerStep(kon_platformer_t *p, const kon_tilemap_t *map, const uint8_t *solid, int solidCount, float dt) +{ + float run = (float)p->moveX * p->runSpeed; + float ease = (p->onGround ? p->groundAccel : p->airAccel) * dt; + int flags; + + if (ease > 1.0f) ease = 1.0f; + p->velocity.x += (run - p->velocity.x) * ease; + p->velocity.y += p->gravity * dt; + if (p->velocity.y > p->maxFall) p->velocity.y = p->maxFall; + + if (p->jumpHeld && !p->jumpWas) p->buffer = p->bufferTime; + p->jumpWas = p->jumpHeld; + if (p->buffer > 0.0f) p->buffer -= dt; + if (p->coyote > 0.0f) p->coyote -= dt; + + if (p->buffer > 0.0f && p->coyote > 0.0f) { + p->velocity.y = -p->jumpSpeed; + p->buffer = 0.0f; + p->coyote = 0.0f; + } + if (!p->jumpHeld && p->velocity.y < -p->jumpCut) p->velocity.y = -p->jumpCut; + + flags = kon_tilemapMove(map, &p->box, p->velocity.x * dt, p->velocity.y * dt, solid, solidCount); + + if (flags & (KON_HIT_LEFT | KON_HIT_RIGHT)) p->velocity.x = 0.0f; + if (flags & (KON_HIT_UP | KON_HIT_DOWN)) p->velocity.y = 0.0f; + p->onGround = (flags & KON_HIT_DOWN) != 0; + if (p->onGround) p->coyote = p->coyoteTime; + return flags; +} + +void kon_platformerUpdate(kon_platformer_t *p, const kon_tilemap_t *map, const uint8_t *solid, int solidCount, double dt) +{ + if (!(dt > 0.0)) return; + if (dt > MAX_FRAME) dt = MAX_FRAME; + + p->leftover += (float)dt; + while (p->leftover >= (float)STEP) { + kon_platformerStep(p, map, solid, solidCount, (float)STEP); + p->leftover -= (float)STEP; + } +} diff --git a/kon/konplatformer.h b/kon/konplatformer.h new file mode 100644 index 0000000..710f0e0 --- /dev/null +++ b/kon/konplatformer.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: MIT */ +/* + * konplatformer.h + * + * Copyright (c) 2026 KonAki + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef KONPLATFORMER_H +#define KONPLATFORMER_H + +#include "koncollide.h" +#include "kontile.h" + +/*** platformer ***/ + +/* a box that runs and jumps through a tilemap. the game sets moveX and jumpHeld every frame, calls kon_platformerUpdate and reads + box, velocity and onGround back. everything is in map pixels and seconds. kon_platformerInit fills in the tuning values, + change them afterwards as you like */ +typedef struct kon_platformer { + kon_box2_t box; + kon_vec2_t velocity; + int onGround; + + int moveX; /* -1 left, 0 stand, 1 right */ + int jumpHeld; + + float runSpeed; + float groundAccel, airAccel; /* how fast velocity.x closes in on the run speed, per second */ + float gravity; + float jumpSpeed; + float jumpCut; /* letting go of jump early slows the rise to this speed */ + float maxFall; + float coyoteTime; /* seconds after leaving a ledge a jump still works */ + float bufferTime; /* seconds before landing a jump press is remembered */ + + /* private */ + float coyote, buffer, leftover; + int jumpWas; +} kon_platformer_t; + +void kon_platformerInit(kon_platformer_t *p, kon_box2_t box); + +/* one step of dt seconds, dt should be small and steady. returns the KON_HIT_ flags of the move */ +int kon_platformerStep(kon_platformer_t *p, const kon_tilemap_t *map, const uint8_t *solid, int solidCount, float dt); + +/* takes the frame time and runs steps of 1/120 of a second, so the jump feels the same at any frame rate */ +void kon_platformerUpdate(kon_platformer_t *p, const kon_tilemap_t *map, const uint8_t *solid, int solidCount, double dt); + +#endif |
