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