View difference between Paste ID: iApiBywT and
SHOW:
|
|
- or go back to the newest paste.
1 | - | |
1 | + | /*=========================================== |
2 | GRRLIB (GX Version) | |
3 | - Template Code - | |
4 | ||
5 | Minimum Code To Use GRRLIB | |
6 | ============================================*/ | |
7 | #include <grrlib.h> | |
8 | ||
9 | #include <stdlib.h> | |
10 | #include <wiiuse/wpad.h> | |
11 | ||
12 | #include "custcolors.h" | |
13 | #include "objects.h" | |
14 | #include "font.h" | |
15 | #include "font.c" | |
16 | ||
17 | extern const unsigned char font[]; | |
18 | extern const int font_size; | |
19 | ||
20 | struct cursor | |
21 | { | |
22 | int x; | |
23 | int y; | |
24 | int rot; | |
25 | }; | |
26 | ||
27 | struct gametile | |
28 | { | |
29 | unsigned char chunk_id; | |
30 | GRRLIB_texImg *tile_bottom; // this is the backgrond tile | |
31 | GRRLIB_texImg *tile_top; // this is the foreground tile | |
32 | GRRLIB_texImg *tile_col; // this one will be used for collision | |
33 | }; | |
34 | ||
35 | /*---------------------------------------------------------------------- | |
36 | These level index collapse/uncollapse functions were provided by GerbilSoft from Sonic Retro, | |
37 | they're for turning 2d tile coordinates into a 1d level array value and vice-versa | |
38 | ----------------------------------------------------------------------*/ | |
39 | ||
40 | inline int rowcolToIdx(int row, int col) | |
41 | { | |
42 | return (col + (row * 256)); | |
43 | } | |
44 | ||
45 | inline int rowFromIdx(int idx) | |
46 | { | |
47 | return (idx >> 8); | |
48 | } | |
49 | ||
50 | inline int colFromIdx(int idx) | |
51 | { | |
52 | return (idx & 0xFF); | |
53 | } | |
54 | ||
55 | /*---------------------------------------------------------------------- | |
56 | LoadMap() is a direct hack from PieChart at the moment. Remember that the new level format | |
57 | is a series of horizontal tiles and wraps every 256 entries. It'll also probably need to be | |
58 | split somehow to load object layouts as well. tilearray[] is the series of u8 values for | |
59 | tileID's that make up the level. tuledata[] is the struct that holds all of the PNG images | |
60 | for each tile. | |
61 | -----------------------------------------------------------------------*/ | |
62 | ||
63 | struct gametile tiledata[256]; // This holds the tile structure data | |
64 | u8 tilearray[10][256]; | |
65 | ||
66 | bool LoadMap(u8 level) | |
67 | { | |
68 | u16 h; | |
69 | FILE *leveldata; | |
70 | //u8 levelarray[2560]; | |
71 | char levelpath[35]; | |
72 | char FG_path[35]; | |
73 | char BG_path[35]; | |
74 | char COL_path[35]; | |
75 | char sizemessage[30]; | |
76 | unsigned short filesize; | |
77 | GRRLIB_texImg *tex_load = GRRLIB_LoadTextureFromFile("images/loading.png"); | |
78 | GRRLIB_ttfFont *error_font = GRRLIB_LoadTTF(font, font_size); | |
79 | ||
80 | sprintf(levelpath,"sd:/apps/SonicWii/maps/%d/%d.bin", level, level); | |
81 | GRRLIB_FillScreen(GRRLIB_BLACK); | |
82 | GRRLIB_DrawImg(140, 300, tex_load, 0,1,1,GRRLIB_WHITE); | |
83 | GRRLIB_Render(); | |
84 | ||
85 | leveldata = fopen(levelpath, "rb"); | |
86 | ||
87 | if (leveldata == NULL) | |
88 | { | |
89 | while(1) | |
90 | { | |
91 | WPAD_ScanPads(); | |
92 | GRRLIB_FillScreen(GRRLIB_BLACK); | |
93 | GRRLIB_PrintfTTF(90,90, error_font, "Error Loading Map", 18, GRRLIB_WHITE); | |
94 | GRRLIB_PrintfTTF(90,110, error_font, levelpath, 18, GRRLIB_WHITE); | |
95 | GRRLIB_PrintfTTF(90,130, error_font, "Press [HOME] to exit.", 14, GRRLIB_WHITE); | |
96 | ||
97 | if (WPAD_ButtonsDown(0) & WIIMOTE_BUTTON_HOME) | |
98 | { | |
99 | GRRLIB_Exit(); | |
100 | exit(0); | |
101 | } | |
102 | GRRLIB_Render(); | |
103 | } | |
104 | return false; // error protection, file didn't load | |
105 | } | |
106 | ||
107 | /*if (false) // old tile debugging routine. Use for checking GRRLIB_LoadTextureFromFile | |
108 | { | |
109 | tile_error: | |
110 | while(1) | |
111 | { | |
112 | WPAD_ScanPads(); | |
113 | GRRLIB_FillScreen(GRRLIB_BLACK); | |
114 | GRRLIB_PrintfTTF(90,90, error_font, "Error Loading Tile", 18, GRRLIB_WHITE); | |
115 | GRRLIB_PrintfTTF(90,110, error_font, COL_path, 18, GRRLIB_WHITE); | |
116 | GRRLIB_PrintfTTF(90,130, error_font, "Press [HOME] to exit.", 14, GRRLIB_WHITE); | |
117 | ||
118 | if (WPAD_ButtonsDown(0) & WIIMOTE_BUTTON_HOME) | |
119 | { | |
120 | GRRLIB_Exit(); | |
121 | exit(0); | |
122 | } | |
123 | GRRLIB_Render(); | |
124 | } | |
125 | return false; // error protection, file didn't load | |
126 | }*/ | |
127 | ||
128 | fseek(leveldata, 0 , SEEK_END); | |
129 | filesize = ftell(leveldata); | |
130 | if (ftell(leveldata) != 0xa00) | |
131 | { | |
132 | sprintf(sizemessage,"filesize is %d, expected 2560", filesize); | |
133 | while(1) | |
134 | { | |
135 | WPAD_ScanPads(); | |
136 | GRRLIB_FillScreen(GRRLIB_BLACK); | |
137 | GRRLIB_PrintfTTF(90,90, error_font, "Error Loading Map: Size Mismatch", 18, GRRLIB_WHITE); | |
138 | GRRLIB_PrintfTTF(90,110, error_font, sizemessage, 18, GRRLIB_WHITE); | |
139 | GRRLIB_PrintfTTF(90,130, error_font, "Press [HOME] to exit.", 14, GRRLIB_WHITE); | |
140 | ||
141 | if (WPAD_ButtonsDown(0) & WIIMOTE_BUTTON_HOME) | |
142 | { | |
143 | GRRLIB_Exit(); | |
144 | exit(0); | |
145 | } | |
146 | GRRLIB_Render(); | |
147 | } | |
148 | return false; // error protection, file didn't load | |
149 | } | |
150 | ||
151 | rewind(leveldata); | |
152 | fread(&tilearray, 1,2560,leveldata); | |
153 | ||
154 | /*for(h=0;h < 2560;h++) | |
155 | { | |
156 | tilearray[h] = levelarray[h];// walk through file byte by byte and assign tile ID's accordingly | |
157 | }*/ | |
158 | ||
159 | for(h=0; h <= 255; h++) | |
160 | { | |
161 | sprintf(COL_path,"maps/%d/%02d.png", level, h); | |
162 | tiledata[h].chunk_id = h; | |
163 | if (GRRLIB_LoadTextureFromFile(COL_path) != NULL) | |
164 | { | |
165 | tiledata[h].tile_col = GRRLIB_LoadTextureFromFile(COL_path); | |
166 | //GRRLIB_InitTileSet(tiledata[h].tile_col, 256, 256, 0); | |
167 | } | |
168 | /*tiledata[h].tile_top = GRRLIB_CreateEmptyTexture(2,2); | |
169 | tiledata[h].tile_bottom = GRRLIB_CreateEmptyTexture(2,2);*/ | |
170 | } | |
171 | ||
172 | fclose(leveldata); | |
173 | return true; | |
174 | } | |
175 | ||
176 | /*------------------------------------------------------------------------------------------ | |
177 | ProcessPlayer() | |
178 | ---------------- | |
179 | All of the player's physics and collision calculations will be processed by this function. | |
180 | First, the player's state gets passed to a switch statement that decides wether to apply air | |
181 | physics, ground physics, etc. | |
182 | -------------------------------------------------------------------------------------------*/ | |
183 | ||
184 | void ProcessPlayer(struct PLAYEROBJ *player) | |
185 | { | |
186 | enum player_states playerstate; | |
187 | ||
188 | player->gnd_speed = player->x_speed + player->y_speed; | |
189 | ||
190 | switch(playerstate) | |
191 | { | |
192 | case(PLAYER_GROUND): // All ground physics/collision calcs go here. | |
193 | if ((WPAD_ButtonsUp(0) & WIIMOTE_BUTTON_UP) && (WPAD_ButtonsUp(0) & WIIMOTE_BUTTON_DOWN)) | |
194 | { | |
195 | // no D-Pad input, we need to apply surface friction value | |
196 | // We'll also need to add Collision checks here and at the D-Pad hold to make sure | |
197 | // sonic doesn't go out of bounds | |
198 | if (abs(player->x_speed) < FRICTION) player->x_speed = 0; | |
199 | else if (player->x_speed < 0) player->x_speed = player->x_speed += (FRICTION*-1); | |
200 | else if (player->x_speed > 0) player->x_speed = player->x_speed += (FRICTION*1); | |
201 | } | |
202 | ||
203 | if (WPAD_ButtonsHeld(0) & WIIMOTE_BUTTON_UP) | |
204 | { | |
205 | /* we're holding left on the D-Pad. First we'll need to check our ground speed is | |
206 | over the limit, then if it isn't, start adding acceleration to the x_speed value. | |
207 | We'll also want to branch out of this if collision to the left returns true.*/ | |
208 | if (abs(player->x_speed) > MAXSPEED) | |
209 | { | |
210 | if (player->x_speed > 0) player->x_speed = MAXSPEED; | |
211 | if (player->x_speed < 0) player->x_speed = NEG_MAXSPD; | |
212 | } | |
213 | ||
214 | if ((player->x_speed != MAXSPEED) && (player->x_speed != NEG_MAXSPD)) | |
215 | { | |
216 | if (player->x_speed > 0) player->x_speed += DECELERATION; | |
217 | if (player->x_speed < 0) player->x_speed -= ACCELERATION; | |
218 | } | |
219 | } else if (WPAD_ButtonsHeld(0) & WIIMOTE_BUTTON_DOWN) | |
220 | { | |
221 | /* we're holding right on the D-Pad. First we'll need to check our ground speed is | |
222 | over the limit, then if it isn't, start adding acceleration to the x_speed value. | |
223 | We'll also want to branch out of this if collision to the left returns true.*/ | |
224 | if (abs(player->x_speed) > MAXSPEED) | |
225 | { | |
226 | if (player->x_speed > 0) player->x_speed = MAXSPEED; | |
227 | if (player->x_speed < 0) player->x_speed = NEG_MAXSPD; | |
228 | } | |
229 | ||
230 | if ((player->x_speed != MAXSPEED) && (player->x_speed != NEG_MAXSPD)) | |
231 | { | |
232 | if (player->x_speed < 0) player->x_speed += DECELERATION; | |
233 | if (player->x_speed > 0) player->x_speed -= ACCELERATION; | |
234 | } | |
235 | } | |
236 | break; // Done with ground physics | |
237 | ||
238 | case(PLAYER_AIR): // All player air physics/collision goes here | |
239 | break; | |
240 | ||
241 | case(PLAYER_LEFT_WALL): // player left wall physics | |
242 | break; | |
243 | ||
244 | case(PLAYER_RIGHT_WALL): // player right wall physics | |
245 | break; | |
246 | ||
247 | case(PLAYER_CEILING): // player right wall physics | |
248 | break; | |
249 | ||
250 | default: // insert some error handling here, as this state is 'unreachable' | |
251 | break; | |
252 | } | |
253 | } | |
254 | ||
255 | /*--------------------------------------------------------------------------------- | |
256 | GameLoop() is where most of the real action happens, all of the game's runtime calculations | |
257 | occur here or are initiated here. Expect this function to change the most. The first thing | |
258 | we need to do is to load all of P1's graphics. Don't forget that the wii's screen real | |
259 | estate is 640x480, approximately double the Genesis' 320x244, with some black bars | |
260 | on top for proper aspect ratio keeping. | |
261 | -----------------------------------------------------------------------------------*/ | |
262 | void GameLoop() | |
263 | { | |
264 | ir_t ir; | |
265 | u8 level=1; | |
266 | ||
267 | // sonic | |
268 | GRRLIB_texImg *tex_sonic_walk = GRRLIB_LoadTextureFromFile("images/sonic/sonic_walk.png"); | |
269 | GRRLIB_texImg *tex_sonic_stand = GRRLIB_LoadTextureFromFile("images/sonic/sonic_stand.png"); | |
270 | GRRLIB_texImg *tex_sonic_ball = GRRLIB_LoadTextureFromFile("images/sonic/sonic_ball.png"); | |
271 | GRRLIB_texImg *tex_sonic_run = GRRLIB_LoadTextureFromFile("images/sonic/sonic_run.png"); | |
272 | GRRLIB_InitTileSet(tex_sonic_walk, 80, 80, 0); | |
273 | GRRLIB_InitTileSet(tex_sonic_stand, 80, 80, 0); | |
274 | GRRLIB_InitTileSet(tex_sonic_ball, 80, 80, 0); | |
275 | GRRLIB_InitTileSet(tex_sonic_run, 80, 80, 0); | |
276 | unsigned int count; | |
277 | struct CAMOBJ camera; | |
278 | struct PLAYEROBJ sonic_obj; | |
279 | sonic_obj.score = 0; | |
280 | sonic_obj.lives = 4; | |
281 | sonic_obj.anim = 0; | |
282 | sonic_obj.frame = 0; | |
283 | sonic_obj.x_coord = 368; | |
284 | sonic_obj.y_coord = 434; | |
285 | ||
286 | // ring | |
287 | GRRLIB_texImg *tex_ring = GRRLIB_LoadTextureFromFile("images/ring.png"); | |
288 | GRRLIB_ttfFont *font1 = GRRLIB_LoadTTF(font, font_size); | |
289 | GRRLIB_texImg *tex_pointer = GRRLIB_LoadTextureFromFile("images/cursor.png"); | |
290 | ||
291 | // cursor for collision picking | |
292 | struct cursor pointer; | |
293 | pointer.x=200; | |
294 | pointer.y=200; | |
295 | ||
296 | /*----------------======Game Variables=========----------------------*/ | |
297 | unsigned int tickcounter=0; | |
298 | u8 framecounter=0; | |
299 | u8 secondcounter=0; | |
300 | unsigned int minutecounter=0; | |
301 | char time_string[15]=""; | |
302 | char debug_ln1[30]=""; | |
303 | char debug_ln2[30]=""; | |
304 | char debug_ln3[30]=""; | |
305 | char debug_ln4[30]=""; | |
306 | bool debugflag=false; | |
307 | bool mapflag=false; | |
308 | camera.x=6; | |
309 | camera.y=222; | |
310 | sonic_obj.score = 0; | |
311 | sonic_obj.rings = 0; | |
312 | ||
313 | sprintf(sonic_obj.score_string, "Score: %d", sonic_obj.score); | |
314 | sprintf(sonic_obj.ring_string, "Rings: %d", sonic_obj.rings); | |
315 | /*----------------======END Game Variables=====-----------------------*/ | |
316 | ||
317 | ||
318 | /*----------------=======Level Processing=====------------------------*/ | |
319 | unsigned int vis_tiles[4][4]; | |
320 | unsigned int first_tile[2]; | |
321 | unsigned int x_current,y_current; | |
322 | unsigned short h,v; | |
323 | LoadMap(level); | |
324 | /*---------------------=========END level processing====----------------------------*/ | |
325 | ||
326 | // Done loading, begin game loop. | |
327 | while(1) | |
328 | { | |
329 | tickcounter++; | |
330 | ||
331 | if (framecounter < 60) framecounter ++; | |
332 | ||
333 | if ((framecounter == 60) && (secondcounter < 60)) | |
334 | { | |
335 | framecounter = 0; | |
336 | secondcounter++; | |
337 | } | |
338 | ||
339 | if ((framecounter == 60) && (secondcounter == 60)) | |
340 | { | |
341 | framecounter = 0; | |
342 | secondcounter = 0; | |
343 | minutecounter++; | |
344 | } | |
345 | ||
346 | /*------------====Control Collection/Gameplay Calc=====------------- | |
347 | Obviously comes before drawing =P | |
348 | --------------------------------------------------------------------*/ | |
349 | WPAD_ScanPads(); // Scan the Wiimotes | |
350 | WPAD_IR(WPAD_CHAN_0, &ir); | |
351 | ||
352 | pointer.x = ir.x; | |
353 | pointer.y = ir.y; | |
354 | ||
355 | if ((WPAD_ButtonsHeld(0) & WPAD_BUTTON_RIGHT) && (camera.y >= 1)) camera.y--; | |
356 | else if ((WPAD_ButtonsHeld(0) & WPAD_BUTTON_RIGHT) && (camera.y == 0)) camera.y = 0; | |
357 | ||
358 | if (WPAD_ButtonsHeld(0) & WPAD_BUTTON_LEFT) camera.y++; | |
359 | ||
360 | if ((WPAD_ButtonsHeld(0) & WPAD_BUTTON_UP) && (camera.x >= 1)) camera.x--; | |
361 | else if((WPAD_ButtonsHeld(0) & WPAD_BUTTON_UP) && (camera.x == 0)) camera.x = 0; | |
362 | ||
363 | if (WPAD_ButtonsHeld(0) & WPAD_BUTTON_DOWN) camera.x++; | |
364 | ||
365 | if ((WPAD_ButtonsDown(0) & WIIMOTE_BUTTON_ONE)) debugflag = !debugflag; | |
366 | ||
367 | if (WPAD_ButtonsDown(0) & WIIMOTE_BUTTON_TWO) mapflag = true; | |
368 | ||
369 | /*--------------========END game calc===========--------------------*/ | |
370 | ||
371 | GRRLIB_FillScreen(GRRLIB_BLACK); | |
372 | ||
373 | /*--------------------------------------------------------------- | |
374 | Map drawing will need to be split into 2 different passes, so that the characters can | |
375 | be drawn inbetween the 2 layers. This is the first of 2 passes. At any given time, 16 | |
376 | tiles will be in the level renderer. To figure out which tiles to draw and how far to | |
377 | offset them, we'll need to use the camera's coordinates and divide by 256 to find our | |
378 | starting tile. The rest can be filled in automatically, as each line is 4 tiles long. | |
379 | 4 arrays were created for holding this render queue, named "vis_tiles_x[4]" | |
380 | respectively. A member of CAMOBJ called in_tile was added for computing where in the | |
381 | main tile array to search. | |
382 | -------------------------------------------------------------------*/ | |
383 | // first we fill our screen cache | |
384 | camera.in_tile[0] = camera.x/256; // row | |
385 | camera.in_tile[1] = camera.y/256; // column | |
386 | ||
387 | first_tile[0] = camera.in_tile[0]; | |
388 | first_tile[1] = camera.in_tile[1]; | |
389 | ||
390 | for(h=0; h < 4; h++) // first row | |
391 | { | |
392 | for(v=0; v < 4; v++) | |
393 | { | |
394 | vis_tiles[h][v] = tilearray[first_tile[1] + v][first_tile[0] + h]; | |
395 | } | |
396 | } | |
397 | ||
398 | // this is the actual display loop, first pass | |
399 | for(h = 0; h < 4; h++) | |
400 | { | |
401 | for(v=0; v < 4; v++) | |
402 | { | |
403 | x_current = (first_tile[0] + h) * 256; | |
404 | y_current = (first_tile[1] + v) * 256; | |
405 | GRRLIB_DrawImg(x_current - camera.x, y_current - camera.y, tiledata[vis_tiles[h][v]].tile_col, 0, 1, 1, GRRLIB_WHITE); | |
406 | } | |
407 | } | |
408 | ||
409 | // Draw Sonic | |
410 | GRRLIB_DrawTile(sonic_obj.x_coord - camera.x, sonic_obj.y_coord - camera.y, tex_sonic_stand, 0,1,1,GRRLIB_WHITE,sonic_obj.frame); | |
411 | GRRLIB_Rectangle(pointer.x, pointer.y, 4, 4, GRRLIB_RED, true); | |
412 | ||
413 | // second level render pass goes here. | |
414 | ||
415 | // Drawing HUD - this will need to get moved to the end of the drawchain to show up | |
416 | // on top of everything else | |
417 | sprintf(time_string, "Time: %d:%d:%d", minutecounter,secondcounter,framecounter); | |
418 | GRRLIB_PrintfTTF(32,32, font1, sonic_obj.score_string, 26, GRRLIB_WHITE); | |
419 | GRRLIB_PrintfTTF(32,64, font1, time_string, 26, GRRLIB_WHITE); | |
420 | GRRLIB_PrintfTTF(32,98, font1, sonic_obj.ring_string, 26, GRRLIB_WHITE); | |
421 | ||
422 | if ((debugflag == true) && (mapflag == false)) | |
423 | { | |
424 | sprintf(debug_ln1, "x: %d", camera.x); | |
425 | sprintf(debug_ln2, "y: %d", camera.y); | |
426 | sprintf(debug_ln3, "it: %d:%d | %d x %d", camera.in_tile[0], camera.in_tile[1], (camera.x % 256), (camera.y % 256)); | |
427 | GRRLIB_PrintfTTF(420,32, font1, debug_ln1, 18, GRRLIB_RED); | |
428 | GRRLIB_PrintfTTF(420,64, font1, debug_ln2, 18, GRRLIB_RED); | |
429 | GRRLIB_PrintfTTF(420,98, font1, debug_ln3, 18, GRRLIB_RED); | |
430 | } | |
431 | ||
432 | while (mapflag == true) | |
433 | { | |
434 | WPAD_ScanPads(); | |
435 | debugflag = false; | |
436 | sprintf(debug_ln1, "%d | %d | %d | %d", vis_tiles[0][0], vis_tiles[1][0], vis_tiles[2][0], vis_tiles[3][0]); | |
437 | sprintf(debug_ln2, "%d | %d | %d | %d", vis_tiles[0][1], vis_tiles[1][1], vis_tiles[2][1], vis_tiles[3][1]); | |
438 | sprintf(debug_ln3, "%d | %d | %d | %d", vis_tiles[0][2], vis_tiles[1][2], vis_tiles[2][2], vis_tiles[3][2]); | |
439 | sprintf(debug_ln4, "%d | %d | %d | %d", vis_tiles[0][3], vis_tiles[1][3], vis_tiles[2][3], vis_tiles[3][3]); | |
440 | GRRLIB_PrintfTTF(50,32, font1, debug_ln1, 22, GRRLIB_WHITE); | |
441 | GRRLIB_PrintfTTF(50,64, font1, debug_ln2, 22, GRRLIB_WHITE); | |
442 | GRRLIB_PrintfTTF(50,98, font1, debug_ln3, 22, GRRLIB_WHITE); | |
443 | //GRRLIB_PrintfTTF(50,130, font1, debug_ln4, 22, GRRLIB_WHITE); | |
444 | ||
445 | if (WPAD_ButtonsHeld(0) & WIIMOTE_BUTTON_ONE) | |
446 | { | |
447 | mapflag = false; | |
448 | break; | |
449 | } else if (WPAD_ButtonsHeld(0) & WPAD_BUTTON_HOME) | |
450 | { | |
451 | GRRLIB_Exit(); | |
452 | exit(0); | |
453 | } | |
454 | ||
455 | GRRLIB_Render(); | |
456 | } | |
457 | ||
458 | ||
459 | if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME) break; | |
460 | if (WPAD_ButtonsDown(0) & WIIMOTE_BUTTON_A) GRRLIB_ScrShot("screenshot.png"); | |
461 | ||
462 | GRRLIB_Render(); | |
463 | } | |
464 | return; | |
465 | } | |
466 | ||
467 | int main(int argc, char **argv) | |
468 | { | |
469 | // Initialise the Graphics & Video subsystem | |
470 | GRRLIB_Init(); | |
471 | ||
472 | // Initialise the Wiimotes | |
473 | WPAD_Init(); | |
474 | WPAD_SetDataFormat(WPAD_CHAN_0, WPAD_FMT_BTNS_ACC_IR); | |
475 | ||
476 | GameLoop(); | |
477 | ||
478 | GRRLIB_Exit(); // Be a good boy, clear the memory allocated by GRRLIB | |
479 | ||
480 | exit(0); // Use exit() to exit a program, do not use 'return' from main() | |
481 | } |