Mirai's Miscellaneous Misadventures

M37 / core / physics.c

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