labyrinth

view src/level.c @ 5:c8826e5ebec1

- changed every data loading function to return dummy objects instead of failing - fixed mistake in AndroidManifest.xml
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 01 May 2015 05:58:41 +0300
parents d46f0947a96d
children
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <math.h>
6 #include "opengl.h"
7 #include "level.h"
9 #define C_WALL '#'
10 #define C_PILLAR 'o'
11 #define C_START 's'
12 #define C_GOLD 'x'
14 #define IS_SOLID(x) ((x) == C_WALL)
16 #define DEF_LVL_SZ 5
17 static const char def_lvl_cells[DEF_LVL_SZ][DEF_LVL_SZ] = {
18 "#####",
19 "##x##",
20 "#o o#",
21 "# s #",
22 "#####"
23 };
26 static int default_level(struct level *lvl);
29 void level_init(struct level *lvl)
30 {
31 memset(lvl, 0, sizeof *lvl);
32 lvl->cell_size = 3.0;
33 lvl->cell_height = 2.5;
34 lvl->floor_tex_scale = lvl->wall_tex_scale = lvl->ceil_tex_scale = 1.0;
35 }
37 static int default_level(struct level *lvl)
38 {
39 int i, j;
41 lvl->num_cells[0] = lvl->num_cells[1] = DEF_LVL_SZ;
43 for(i=0; i<DEF_LVL_SZ; i++) {
44 for(j=0; j<DEF_LVL_SZ; j++) {
45 char c = def_lvl_cells[i][j];
46 lvl->cells[i][j] = c;
47 if(c == 's') {
48 lvl->start_pos[0] = j;
49 lvl->start_pos[1] = i;
50 } else if(c == 'x') {
51 lvl->goal_pos[0] = j;
52 lvl->goal_pos[1] = i;
53 }
54 }
55 }
56 return 0;
57 }
59 static void clean_line(char *buf)
60 {
61 char *end = buf + strlen(buf) - 1;
63 if(end <= buf) return;
65 while(end >= buf && !isprint(*end)) {
66 *end-- = 0;
67 }
68 }
70 int level_load(struct level *lvl, const char *fname)
71 {
72 FILE *fp;
73 char buf[256];
74 int i, size[2], nlines;
76 if(!(fp = fopen(fname, "r"))) {
77 fprintf(stderr, "failed to open file: %s\n", fname);
78 return default_level(lvl);
79 }
81 if(!fgets(buf, sizeof buf, fp)) {
82 fprintf(stderr, "level file %s is empty\n", fname);
83 fclose(fp);
84 return default_level(lvl);
85 }
86 if(sscanf(buf, "s %dx%d", size, size + 1) != 2) {
87 fprintf(stderr, "level file %s doesn't start with size definition\n", fname);
88 fclose(fp);
89 return default_level(lvl);
90 }
91 if(size[0] > MAX_LEVEL_SIZE || size[1] > MAX_LEVEL_SIZE) {
92 fprintf(stderr, "level size %dx%d is larger than compile-time maximum (%d)\n", size[0], size[1], MAX_LEVEL_SIZE);
93 fclose(fp);
94 return default_level(lvl);
95 }
97 lvl->num_cells[0] = size[0];
98 lvl->num_cells[1] = size[1];
100 nlines = 0;
101 while(fgets(buf, sizeof buf, fp)) {
102 if(nlines >= size[0]) {
103 fprintf(stderr, "warning: level contains more lines than specified, ignoring the rest\n");
104 break;
105 }
106 clean_line(buf);
108 for(i=0; buf[i]; i++) {
109 if(i >= size[1]) {
110 fprintf(stderr, "warning: line %d is longer than the level size definition says. Skipping the rest.\n", nlines + 1);
111 break;
112 }
113 lvl->cells[nlines][i] = buf[i];
115 if(buf[i] == C_START) {
116 lvl->start_pos[0] = i;
117 lvl->start_pos[1] = nlines;
118 printf("start cell found (%d,%d)\n", lvl->start_pos[0], lvl->start_pos[1]);
119 }
120 if(buf[i] == C_GOLD) {
121 level_cell_to_pos(lvl, i, nlines, lvl->goal_pos, lvl->goal_pos + 1);
122 printf("gold cell found (%d, %d)\n", i, nlines);
123 }
124 }
125 nlines++;
126 }
128 fclose(fp);
129 return 0;
130 }
133 static int clamp(int x, int low, int high)
134 {
135 return x < low ? low : (x > high ? high : x);
136 }
138 void level_pos_to_cell(struct level *lvl, float x, float y, int *res_cx, int *res_cy)
139 {
140 int cx = (int)(x / lvl->cell_size + 0.5);
141 int cy = (int)(y / lvl->cell_size + 0.5);
143 *res_cx = clamp(cx, 0, lvl->num_cells[1] - 1);
144 *res_cy = clamp(cy, 0, lvl->num_cells[0] - 1);
145 }
147 void level_cell_to_pos(struct level *lvl, int cx, int cy, float *resx, float *resy)
148 {
149 cx = clamp(cx, 0, lvl->num_cells[1] - 1);
150 cy = clamp(cy, 0, lvl->num_cells[0] - 1);
152 *resx = (float)cx * lvl->cell_size;
153 *resy = (float)cy * lvl->cell_size;
154 }
156 int level_cell(struct level *lvl, int cx, int cy)
157 {
158 cx = clamp(cx, 0, lvl->num_cells[1] - 1);
159 cy = clamp(cy, 0, lvl->num_cells[0] - 1);
161 return lvl->cells[cy][cx];
162 }
164 int level_cell_at(struct level *lvl, float x, float y)
165 {
166 int cx, cy;
167 level_pos_to_cell(lvl, x, y, &cx, &cy);
168 return level_cell(lvl, cx, cy);
169 }
171 int level_obj_pos(struct level *lvl, int objname, float *resx, float *resy)
172 {
173 int i, j;
175 for(i=0; i<lvl->num_cells[0]; i++) {
176 for(j=0; j<lvl->num_cells[1]; j++) {
177 if(lvl->cells[i][j] == objname) {
178 level_cell_to_pos(lvl, j, i, resx, resy);
179 return 1;
180 }
181 }
182 }
183 return 0;
184 }
186 /* NOTE: this function could be simpler */
187 int level_collide(struct level *lvl, float rad, float x, float y, float *dxp, float *dyp)
188 {
189 int i, val, cxy[2], collided = 0;
190 float pos[2], dir[2], center[2], len;
191 int adj_cxy[2];
193 pos[0] = x;
194 pos[1] = y;
195 dir[0] = *dxp;
196 dir[1] = *dyp;
198 /* clamp the direction magnitude (manhattan) to the cell size */
199 for(i=0; i<2; i++) {
200 if(dir[i] > lvl->cell_size) dir[i] = lvl->cell_size;
201 if(dir[i] < -lvl->cell_size) dir[i] = -lvl->cell_size;
202 }
204 level_pos_to_cell(lvl, pos[0], pos[1], cxy, cxy + 1);
205 level_cell_to_pos(lvl, cxy[0], cxy[1], center, center + 1);
207 /* check collision and clamp dx/dy with each of the 4 directions */
208 for(i=0; i<4; i++) {
209 float wall_pos, dist;
210 int axis = (i & 2) >> 1;
211 int sign = (i & 1) ? -1 : 1;
213 adj_cxy[0] = cxy[0];
214 adj_cxy[1] = cxy[1];
215 adj_cxy[axis] += sign;
217 val = level_cell(lvl, adj_cxy[0], adj_cxy[1]);
219 if(!IS_SOLID(val)) continue;
221 wall_pos = center[axis] + (lvl->cell_size * 0.5 - rad) * (float)sign;
222 dist = fabs(wall_pos - pos[axis]);
224 if(dir[axis] * (float)sign > dist) {
225 dir[axis] = (float)sign * dist;
226 collided = 1;
227 }
228 }
230 /* finally to make sure we don't slip through cracks in corners, also check
231 * the destination cell
232 */
233 len = sqrt(dir[0] * dir[0] + dir[1] * dir[1]);
234 pos[0] += dir[0] + dir[0] / len * rad;
235 pos[1] += dir[1] + dir[1] / len * rad;
237 val = level_cell_at(lvl, pos[0], pos[1]);
238 if(IS_SOLID(val)) {
239 dir[0] = dir[1] = 0;
240 }
243 *dxp = dir[0];
244 *dyp = dir[1];
245 return collided;
246 }
248 static void wall_faces(float x, float y, float width, float height, float uscale, float vscale)
249 {
250 float u0 = 0.5 - 0.5 * uscale;
251 float u1 = 0.5 + 0.5 * uscale;
252 float v0 = 0.5 - 0.5 * vscale;
253 float v1 = 0.5 + 0.5 * vscale;
255 width /= 2.0;
257 glNormal3f(0, 0, 1);
258 glTexCoord2f(u0, v1); glVertex3f(x - width, 0, y + width);
259 glTexCoord2f(u1, v1); glVertex3f(x + width, 0, y + width);
260 glTexCoord2f(u1, v0); glVertex3f(x + width, height, y + width);
261 glTexCoord2f(u0, v0); glVertex3f(x - width, height, y + width);
262 glNormal3f(0, 0, -1);
263 glTexCoord2f(u0, v0); glVertex3f(x - width, height, y - width);
264 glTexCoord2f(u1, v0); glVertex3f(x + width, height, y - width);
265 glTexCoord2f(u1, v1); glVertex3f(x + width, 0, y - width);
266 glTexCoord2f(u0, v1); glVertex3f(x - width, 0, y - width);
267 glNormal3f(1, 0, 0);
268 glTexCoord2f(u0, v1); glVertex3f(x + width, 0, y + width);
269 glTexCoord2f(u1, v1); glVertex3f(x + width, 0, y - width);
270 glTexCoord2f(u1, v0); glVertex3f(x + width, height, y - width);
271 glTexCoord2f(u0, v0); glVertex3f(x + width, height, y + width);
272 glNormal3f(-1, 0, 0);
273 glTexCoord2f(u0, v0); glVertex3f(x - width, height, y + width);
274 glTexCoord2f(u1, v0); glVertex3f(x - width, height, y - width);
275 glTexCoord2f(u1, v1); glVertex3f(x - width, 0, y - width);
276 glTexCoord2f(u0, v1); glVertex3f(x - width, 0, y + width);
277 }
279 void level_draw(struct level *lvl)
280 {
281 static int first = 1;
282 int i, j, k;
284 set_mtl_diffuse(1, 1, 1, 1);
285 set_mtl_specular(0, 0, 0);
287 glMatrixMode(GL_TEXTURE);
288 glLoadIdentity();
289 glScalef(lvl->wall_tex_scale, lvl->wall_tex_scale, lvl->wall_tex_scale);
291 glEnable(GL_TEXTURE_2D);
293 /* draw walls */
294 glBindTexture(GL_TEXTURE_2D, lvl->wall_tex);
295 glBegin(GL_QUADS);
296 for(i=0; i<lvl->num_cells[0]; i++) {
297 int cy = i;
298 for(j=0; j<lvl->num_cells[1]; j++) {
299 float x, y;
300 int cx = j;
301 int c = level_cell(lvl, cx, cy);
303 level_cell_to_pos(lvl, cx, cy, &x, &y);
305 if(c == C_WALL) {
306 wall_faces(x, y, lvl->cell_size, lvl->cell_height, 1, 1);
307 } else if(c == C_PILLAR) {
308 wall_faces(x, y, 0.2, lvl->cell_height, 0.04, 1);
309 }
311 if(first) putchar(c);
312 }
313 if(first) putchar('\n');
314 }
315 glEnd();
317 /* draw floor & ceiling */
318 for(k=0; k<2; k++) {
319 int do_floor = k == 0;
320 float height, normy;
322 if(do_floor) {
323 glBindTexture(GL_TEXTURE_2D, lvl->floor_tex);
324 glScalef(lvl->floor_tex_scale, lvl->floor_tex_scale, lvl->floor_tex_scale);
325 height = 0;
326 normy = 1;
327 glFrontFace(GL_CCW);
328 } else {
329 glBindTexture(GL_TEXTURE_2D, lvl->ceil_tex);
330 glScalef(lvl->ceil_tex_scale, lvl->ceil_tex_scale, lvl->ceil_tex_scale);
331 height = lvl->cell_height;
332 normy = -1;
333 glFrontFace(GL_CW);
334 }
336 glBegin(GL_TRIANGLES);
337 for(i=0; i<lvl->num_cells[0]; i++) {
338 int cy = i;
339 for(j=0; j<lvl->num_cells[1]; j++) {
340 float x, y;
341 int cx = j;
342 int c = level_cell(lvl, cx, cy);
344 level_cell_to_pos(lvl, cx, cy, &x, &y);
346 if(c != C_WALL) {
347 float hsz = lvl->cell_size / 2.0f;
349 glNormal3f(0, normy, 0);
350 glTexCoord2f(0.5, 0.5); glVertex3f(x, height, y);
351 glTexCoord2f(0.0, 0.0); glVertex3f(x - hsz, height, y + hsz);
352 glTexCoord2f(1.0, 0.0); glVertex3f(x + hsz, height, y + hsz);
353 glTexCoord2f(0.5, 0.5); glVertex3f(x, height, y);
354 glTexCoord2f(1.0, 0.0); glVertex3f(x + hsz, height, y + hsz);
355 glTexCoord2f(1.0, 1.0); glVertex3f(x + hsz, height, y - hsz);
356 glTexCoord2f(0.5, 0.5); glVertex3f(x, height, y);
357 glTexCoord2f(1.0, 1.0); glVertex3f(x + hsz, height, y - hsz);
358 glTexCoord2f(0.0, 1.0); glVertex3f(x - hsz, height, y - hsz);
359 glTexCoord2f(0.5, 0.5); glVertex3f(x, height, y);
360 glTexCoord2f(0.0, 1.0); glVertex3f(x - hsz, height, y - hsz);
361 glTexCoord2f(0.0, 0.0); glVertex3f(x - hsz, height, y + hsz);
362 }
363 }
364 }
365 glEnd();
366 }
368 glFrontFace(GL_CCW); /* restore front-face mode */
369 glDisable(GL_TEXTURE_2D);
371 glLoadIdentity(); /* restore the texture matrix to identity */
372 glMatrixMode(GL_MODELVIEW);
374 /* draw other objects
375 for(i=0; i<lvl->num_cells[0]; i++) {
376 int cy = i;
377 for(j=0; j<lvl->num_cells[1]; j++) {
378 float x, y;
379 int cx = j;
380 int c = level_cell(lvl, cx, cy);
382 level_cell_to_pos(lvl, cx, cy, &x, &y);
384 switch(c) {
385 case C_PILLAR:
386 break;
387 }
388 }
389 }
390 */
392 first = 0;
393 }