/* 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; } }