Mirai's Miscellaneous Misadventures

M34 / core / physics.c

1// copyright 2022 zamfofex
2// license: AGPLv3 or later
3
4static unsigned char mimimi_ground_get(struct mimimi_ground *ground, int x, int y)
5{
6	if (x < 0) return 1;
7	if (y < 0) return 1;
8	if (x >= ground->width) return 1;
9	if (y >= ground->height) return 1;
10	return ground->tiles[x + y * ground->width];
11}
12
13static void mimimi_wall_physics(struct mimimi_physics_data *data)
14{
15	struct mimimi_ground *ground = data->ground;
16	struct mimimi_position *position = data->position;
17	struct mimimi_physics *physics = data->physics;
18	
19	int x0 = position->x;
20	int y0 = position->y;
21	int x1 = physics->width / 2;
22	int y1 = physics->height;
23	
24	int top = (y0 - y1) / 128;
25	int top2 = top - 1;
26	int bottom = (y0 - 127) / 128;
27	int bottom2 = bottom - 1;
28	int left = (x0 - x1) / 128;
29	int right = (x0 + x1) / 128;
30	
31	if (
32		mimimi_ground_get(ground, left, bottom) != 0 &&
33		mimimi_ground_get(ground, left, bottom2) != 0 ||
34		mimimi_ground_get(ground, left, top) != 0 &&
35		mimimi_ground_get(ground, left, top2) != 0
36	)
37	{
38		if (physics->dx < 0) physics->dx = 0;
39		position->x = (left + 1) * 128 + x1;
40	}
41	
42	if (
43		mimimi_ground_get(ground, right, bottom) != 0 &&
44		mimimi_ground_get(ground, right, bottom2) != 0 ||
45		mimimi_ground_get(ground, right, top) != 0 &&
46		mimimi_ground_get(ground, right, top2) != 0
47	)
48	{
49		if (physics->dx > 0) physics->dx = 0;
50		position->x = right * 128 - x1 - 1;
51	}
52}
53
54static void mimimi_slope_physics(struct mimimi_physics_data *data)
55{
56	struct mimimi_ground *ground = data->ground;
57	struct mimimi_position *position = data->position;
58	struct mimimi_physics *physics = data->physics;
59	
60	int x0 = position->x;
61	int y0 = position->y;
62	int x1 = physics->width / 2;
63	int y1 = physics->height;
64	
65	int top = (y0 - y1) / 128;
66	int bottom = (y0 - 127) / 128;
67	int left = (x0 - x1) / 128;
68	int right = (x0 + x1) / 128;
69	
70	if (mimimi_ground_get(ground, left, bottom) != 0)
71	if (mimimi_ground_get(ground, left, top) == 0)
72		position->y = bottom * 128;
73	if (mimimi_ground_get(ground, right, bottom) != 0)
74	if (mimimi_ground_get(ground, right, top) == 0)
75		position->y = bottom * 128;
76}
77
78static void mimimi_ceiling_physics(struct mimimi_physics_data *data)
79{
80	struct mimimi_ground *ground = data->ground;
81	struct mimimi_position *position = data->position;
82	struct mimimi_physics *physics = data->physics;
83	
84	if (physics->dy > 0) return;
85	
86	int x0 = position->x;
87	int y0 = position->y;
88	int x1 = physics->width / 2;
89	int y1 = physics->height;
90	
91	int top = (y0 - y1) / 128;
92	int top2 = top - 1;
93	int left = (x0 - x1) / 128;
94	int right = (x0 + x1) / 128;
95	
96	if (mimimi_ground_get(ground, left, top) != 0 && mimimi_ground_get(ground, right, top) != 0)
97	if (mimimi_ground_get(ground, left, top2) != 0 || mimimi_ground_get(ground, right, top2) != 0)
98	{
99		physics->dy = 0;
100		position->y = (top + 1) * 128 + y1;
101	}
102}
103
104static void mimimi_landing_physics(struct mimimi_physics_data *data)
105{
106	struct mimimi_ground *ground = data->ground;
107	struct mimimi_position *position = data->position;
108	struct mimimi_physics *physics = data->physics;
109	
110	int x0 = position->x;
111	int y0 = position->y;
112	int x1 = physics->width / 2;
113	
114	int bottom = y0 / 128;
115	int left = (x0 - x1) / 128;
116	int right = (x0 + x1) / 128;
117	
118	if (physics->dy < 0) return;
119	
120	if (mimimi_ground_get(ground, left, bottom) != 0 || mimimi_ground_get(ground, right, bottom) != 0)
121	{
122		physics->airborne = 0;
123		physics->dy = 0;
124		position->y = bottom * 128;
125	}
126}
127
128static void mimimi_fall_physics(struct mimimi_physics_data *data)
129{
130	struct mimimi_ground *ground = data->ground;
131	struct mimimi_position *position = data->position;
132	struct mimimi_physics *physics = data->physics;
133	
134	int x0 = position->x;
135	int y0 = position->y;
136	int x1 = physics->width / 2;
137	
138	int bottom = y0 / 128;
139	int center = x0 / 128;
140	int left = (x0 - x1) / 128;
141	int right = (x0 + x1) / 128;
142	
143	if (mimimi_ground_get(ground, left, bottom) == 0 && mimimi_ground_get(ground, right, bottom) == 0)
144	{
145		if (mimimi_ground_get(ground, center, (bottom + 1)) == 0)
146			// fall
147			physics->airborne = 1;
148		else
149			// step down
150			position->y = (bottom + 1) * 128;
151	}
152}
153
154static void mimimi_physics_dynamics(struct mimimi_physics_data *data)
155{
156	struct mimimi_position *position = data->position;
157	struct mimimi_physics *physics = data->physics;
158	
159	position->x += physics->dx;
160	position->y += physics->dy;
161}
162
163static void mimimi_ground_physics(struct mimimi_physics_data *data)
164{
165	struct mimimi_physics *physics = data->physics;
166	
167	physics->dx *= 5;
168	physics->dx /= 6;
169	physics->dy = 0;
170	
171	mimimi_physics_dynamics(data);
172	
173	mimimi_slope_physics(data);
174	mimimi_wall_physics(data);
175	mimimi_fall_physics(data);
176}
177
178static void mimimi_airborne_physics(struct mimimi_physics_data *data)
179{
180	struct mimimi_physics *physics = data->physics;
181	
182	physics->dx *= 17;
183	physics->dx /= 18;
184	physics->dy += physics->gravity;
185	
186	mimimi_physics_dynamics(data);
187	
188	mimimi_ceiling_physics(data);
189	mimimi_wall_physics(data);
190	mimimi_landing_physics(data);
191}