summaryrefslogtreecommitdiff
path: root/src/player.c
blob: 92cbd5a2981a150b70131587bc308cc122b3e08a (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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
NAME(player);

static const i32 grace = 10;
static const i32 jumpBuffer = 6;
static const f32 maxSpeed = 1.f;
static const f32 groundAcceleration = .4f;
static const f32 groundFriction = (groundAcceleration / maxSpeed);
static const f32 airAcceleration = .2f;
static const f32 airFriction = (airAcceleration / maxSpeed);
static const f32 airResistance = .01f;
static const f32 jumpSpeed = -2.f;
static const f32 gravity = .05f;

enum AirState {
	AirState_NEUTRAL,
	AirState_RISING,
	AirState_BREAKING
};

INIT {
	DIM.x = DIM.y = 6;
	this->reverseGravity = false;
	this->grace = 0;
	this->djump = false;
	this->air = AirState_NEUTRAL;
}

INIT_POST {
	while (!collide_solid(v2(0, 1)))
		POS.y += 1;
}

UPDATE {
	if (input_pressed("reset")) {
		g->room_restart = 1;
		return;
	}
	if (this->dead) {
		this->tick += 1;
		return;
	}

	const bool reverse_gravity = this->reverseGravity;
	if (reverse_gravity) VEL.y *= -1;

	const bool on_ground = collide_solid(v2(0, reverse_gravity ? -1 : 1));
	if (input_axis("move x"))
		this->flip_x = (input_axis("move x") < 0);
	if (input_pressed("jump"))
		this->jump_buffer = jumpBuffer;
	else if (this->jump_buffer > 0)
		this->jump_buffer -= 1;
	if (on_ground) {
		this->grace = grace;
		this->djump = true;
	} else if (this->grace > 0)
		this->grace -= 1;
	const bool can_jump = this->grace || this->djump;

	if (on_ground) {
		VEL.x *= 1 - groundFriction;
		VEL.x += input_axis("move x") * groundAcceleration;
	} else {
		VEL.x *= 1 - airFriction;
		VEL.x += input_axis("move x") * airAcceleration;
	}

	if (this->air == AirState_RISING && !input_down("jump"))
		this->air = AirState_BREAKING;
	if (this->air == AirState_BREAKING && VEL.y > gravity * grace / 2)
		this->air = AirState_NEUTRAL;

	VEL.y *= 1.f - airResistance;
	if (can_jump && this->jump_buffer) {
		this->jump_buffer = 0;
		if (this->grace) {
			g->ev.jump = true;
			this->grace = 0;
		} else {
			g->ev.djump = true;
			this->djump = false;
		}
		VEL.y = jumpSpeed;
		REM.y = 0;
		this->air = AirState_RISING;
	} else if (!on_ground) {
		if (this->air == AirState_BREAKING)
			VEL.y += gravity * 6;
		else
			VEL.y += gravity;
	}

	if (reverse_gravity) VEL.y *= -1;
	vec2 vel = move(VEL);
	if (collide_spike(v2_zero())) {
		g->ev.death = true;
		this->dead = true;
	}
	VEL = vel;
}

DRAW {
	TZR_DrawSetColor(1, 1, 1);
	if (this->dead && this->tick / 4 % 2 == 0)
		return;
	TZR_DrawImage(TZR_RES("res/player.bmp"), v2_unpack(POS), .center=true);
}

DRAW_END {
	if (!this->dead || this->tick / 32 % 2 == 1)
		return;
	font_center(cfg.display_width/2, cfg.display_height/2 - cfg.tile_height/2,
	            "game over");
	font_center(cfg.display_width/2, cfg.display_height/2 + cfg.tile_height/2,
	            "press r");
}