1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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;
}
}
|