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
}