summaryrefslogtreecommitdiff
path: root/kon/konplatformer.c
blob: 9d22c6732ccdfefef9f1a18925647bc77bbd61cc (plain)
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;
	}
}