Subversion Repositories Kolibri OS

Rev

Rev 9011 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
9011 leency 1
#include 
2
#include 
3
#include "images.hpp"
4
 
5
//Global const strings
6
const char HEADER_STRING[] = "Flappy bird";
7
const char CONTROL_STRING[] = "SPACEBAR TO JUMP";
8
const char GAMEOVER_STRING[] = "GAMEOVER";
9
const char ANY_KEY_STRING[] = "Press any key for restart";
10
const char SELECT_SPEED_STRING[] = "select the speed of the game";
11
const char FAST_STRING[] = "1 FAST";
12
const char SLOW_STRING[] = "2 SLOW";
13
 
14
//Global const variables
15
const int WINDOW_WIDTH = 400;
16
const int WINDOW_HEIGHT = 400;
17
const int BORDER_TOP = 24;
18
const int BORDER_LEFT = 5;
19
const int BORDER_RIGHT = 5;
20
const int BORDER_DOWN = 5;
21
 
22
enum GameState
23
{
24
	GAMESTATE_MENU,
25
	GAMESTATE_STARTED,
26
	GAMESTATE_GAMEOVER
27
};
28
 
29
struct ScreenSize
30
{
31
	int width;
32
	int height;
33
};
34
 
35
class Bird
36
{
37
public:
9046 leency 38
	static const int sizeX = 19;
39
	static const int sizeY = 20;
9011 leency 40
	static const int x = 100;
41
	int prev_y;
42
	int y;
43
	int acceleration;
44
 
45
	inline void initialize()
46
	{
47
		y = WINDOW_HEIGHT / 2;
48
		acceleration = 0;
49
	}
50
 
51
	inline void move()
52
	{
53
		if (acceleration <= 30)
54
			acceleration += 2;
55
		prev_y = y;
56
		y += acceleration / 10;
57
	}
58
 
59
	inline void jump()
60
	{
61
		acceleration = -50;
62
	}
63
 
64
	inline void draw()
65
	{
66
		kos_PutImage(birdImage, sizeX, sizeY, x, y);
67
	}
68
};
69
 
70
class Tube
71
{
72
public:
73
	static const int width = 50;
74
	static const int gapHeight = 100;
75
	static const int headHeight = 18;
76
	int x;
77
	int gapY;
78
 
79
	inline void randomize()
80
	{
81
		x = WINDOW_WIDTH + 1;
82
		gapY = rtlRand() % 200 + 50;
83
	}
84
 
85
	inline void move()
86
	{
87
		x -= 2;
88
		if (x < -width - 2)
89
			randomize();
90
	}
91
 
92
	void draw()
93
	{
9046 leency 94
		//cleanup
95
		int pixels = (WINDOW_WIDTH - (BORDER_LEFT + BORDER_RIGHT - 1)) - (x + width + 2);
96
		if (pixels >= -1)
97
		{
98
			pixels = (pixels == -1) ? 1 : 2;
99
			kos_DrawBar(x + width, gapY - headHeight, pixels, headHeight, 0x00FFFF);
100
			kos_DrawBar(x + width, gapY + gapHeight, pixels, headHeight, 0x00FFFF);
101
		}
102
 
9011 leency 103
		int offset = x >= 0 ? 0 : -x;
104
		int trim = x + width >= WINDOW_WIDTH - (BORDER_LEFT + BORDER_RIGHT - 1) ? WINDOW_WIDTH - x - width - (BORDER_LEFT + BORDER_RIGHT - 1) : 0;
9046 leency 105
		int trimHead = x + width >= WINDOW_WIDTH - (BORDER_LEFT + BORDER_RIGHT - 1) ? WINDOW_WIDTH - x - width - (BORDER_LEFT + BORDER_RIGHT - 1) : 0;
9011 leency 106
 
107
		//top
108
		for (int y = 0; y < gapY - headHeight; ++y)
109
			kos_PutImage(tubeBodyImage + offset, width - offset + trim, 1, x + offset, y);
110
		//head top
111
		for (int y = gapY - headHeight; y < gapY; ++y)
9046 leency 112
			kos_PutImage(tubeHeadImage + width * (y - (gapY - headHeight)) + offset, width - offset + trimHead, 1, x + offset, y);
9011 leency 113
		//head down
114
		for (int y = gapY + gapHeight; y < gapY + gapHeight + headHeight; ++y)
9046 leency 115
			kos_PutImage(tubeHeadImage + width * (y - (gapY + gapHeight)) + offset, width - offset + trimHead, 1, x + offset, y);
9011 leency 116
		//down
117
		for (int y = gapY + gapHeight + headHeight; y < WINDOW_HEIGHT - (BORDER_TOP + BORDER_DOWN - 1); ++y)
118
			kos_PutImage(tubeBodyImage + offset, width - offset + trim, 1, x + offset, y);
119
 
120
	}
121
};
122
 
123
//Global variables
124
int loopDelay;
125
GameState gameState;
126
char scoreString[] = "Score:    ";
127
bool scoreChanged;
128
int score;
129
Bird bird;
130
int tubeNumber;
131
Tube tubes[3];
132
int windowX;
133
int windowY;
134
 
135
//Function prototypes
136
void kos_Main();
137
void startGame();
138
ScreenSize getScreenSize();
139
void updateScoreString();
140
void WriteBorderedText(Word x, Word y, Byte fontType, Dword textColor, const char* textPtr, Dword textLen, Dword borderColor, int borderSize);
141
inline bool checkAddScore(Tube tube);
142
inline bool checkCollision(Tube tube);
143
 
144
void drawMenuWindow();
145
void drawGameWindow();
146
void redrawGameWindow();
147
void drawGameoverWindow();
148
 
149
//Functions
150
 
151
void startGame()
152
{
153
	kos_SetMaskForEvents(0x7); /// 111 in binary
154
 
155
	bird.initialize();
156
 
157
	score = 0;
158
	memset((Byte*)scoreString + 6, ' ', 3);
159
	updateScoreString();
160
 
161
	tubeNumber = 1;
162
	tubes[0].randomize();
163
 
164
	gameState = GAMESTATE_STARTED;
165
	drawGameWindow();
166
}
167
 
168
ScreenSize getScreenSize()
169
{
170
	Dword result;
171
	__asm {
172
		push 14		//System function 14
173
		pop eax
174
		int 0x40
175
		mov result, eax
176
	}
177
	ScreenSize screenSize;
178
	screenSize.height = (result & 0xFFFF) + 1;	//last two bytes
179
	screenSize.width = (result >> 16) + 1;		//first two bytes
180
	return screenSize;
181
}
182
 
183
void kos_Main()
184
{
185
	rtlSrand( kos_GetSystemClock() );
186
 
187
	//Centring window
188
	ScreenSize screenSize = getScreenSize();
189
	windowX = (screenSize.width - WINDOW_WIDTH) / 2;
190
	windowY = (screenSize.height - WINDOW_HEIGHT) / 2;
191
 
192
	gameState = GAMESTATE_MENU;
193
 
194
	kos_SetMaskForEvents(0x27); // 100111 in binary
195
 
196
	while( true )
197
	{
198
		switch (gameState)
199
		{
200
		case GAMESTATE_STARTED:
201
			kos_Pause(loopDelay);
202
 
203
			bird.move();
204
 
205
			//Adding new tubes
206
			if ((tubeNumber == 1 || tubeNumber == 2) && (tubes[tubeNumber - 1].x < (WINDOW_WIDTH - WINDOW_WIDTH / 3)))
207
				tubes[tubeNumber++].randomize();
208
 
209
			//Processing all tubes
210
			scoreChanged = false;
211
			for (int i = 0; i < tubeNumber; ++i)
212
			{
213
				//Adding score
214
				if (checkAddScore(tubes[i]))
215
				{
216
					++score;
217
					scoreChanged = true;
218
				}
219
 
220
				//Check collision with bird
221
				if (checkCollision(tubes[i]))
222
				{
223
					gameState = GAMESTATE_GAMEOVER;
224
					continue;
225
				}
226
 
227
				//Move tube
228
				tubes[i].move();
229
			}
230
 
231
			if (scoreChanged)
232
				updateScoreString();
233
 
234
			//Cheking the bird is too high or low
235
			if (bird.y + bird.sizeY > WINDOW_HEIGHT - (BORDER_TOP + BORDER_DOWN - 1) || bird.y < 0)
236
			{
237
				gameState = GAMESTATE_GAMEOVER;
238
				continue;
239
			}
240
 
241
			redrawGameWindow();
242
 
243
			switch (kos_CheckForEvent())
244
			{
245
			case 1:
246
				drawGameWindow();
247
				break;
248
 
249
			case 2: // key pressed
250
				Byte keyCode;
251
				kos_GetKey(keyCode);
252
				if (keyCode == 32) //if pressed key is spacebar
253
					bird.jump();
254
				break;
255
 
256
			case 3: // button pressed; we have only one button, close
257
				kos_ExitApp();
258
			}
259
			break;
260
 
261
		case GAMESTATE_GAMEOVER:
262
			drawGameoverWindow();
263
 
264
			switch (kos_WaitForEvent())
265
			{
266
			case 1:
267
				drawGameoverWindow();
268
				break;
269
 
270
			case 2:
271
				startGame();
272
				break;
273
 
274
			case 3:
275
				kos_ExitApp();
276
			}
277
			break;
278
 
279
		case GAMESTATE_MENU:
280
			switch (kos_WaitForEvent())
281
			{
282
			case 1:
283
				drawMenuWindow();
284
				break;
285
 
286
			case 2:
287
				Byte keyCode;
288
				kos_GetKey(keyCode);
289
				if (keyCode == 0x31 || keyCode == 0x61)	//1 or NumPad1
290
				{
291
					loopDelay = 1;
292
					startGame();
293
				}
294
				else if (keyCode == 0x32 || keyCode == 0x62) //2 or NumPad2
295
				{
296
					loopDelay = 2;
297
					startGame();
298
				}
299
				break;
300
 
301
			case 3:
302
				kos_ExitApp();
303
 
304
			case 6:
305
				Dword result;
306
				__asm {
307
					push 37 //Function 37 - work with mouse
308
					pop eax
309
					mov ebx, 3 //Subfunction 3 - states and events of the mouse buttons
310
					int 0x40
311
					mov result, eax
312
				}
313
				result &= 0x100; //bit 8 is set = left button is pressed
314
				if ( result )
315
				{
316
					Dword coordinates;
317
					__asm {
318
						push 37	//Function 37 - work with mouse
319
						pop eax
320
						mov ebx, 1 //Subfunction 1 - coordinates of the mouse relative to the window
321
						int		0x40
322
						mov coordinates, eax
323
					}
324
					int clickX = coordinates >> 16;
325
					int clickY = coordinates & 0xFFFF;
326
					if (clickX >= 100 && clickX < 390 && clickY >= 170 && clickY < 230)
327
					{
328
						loopDelay = 1;
329
						startGame();
330
					}
331
					else if (clickX >= 100 && clickX < 390 && clickY >= 270 && clickY < 330)
332
					{
333
						loopDelay = 2;
334
						startGame();
335
					}
336
				}
337
				break;
338
			}
339
			break;
340
		}
341
	}
342
}
343
 
344
void drawGameWindow()
345
{
346
	kos_DefineAndDrawWindow(windowX, windowY, WINDOW_WIDTH, WINDOW_HEIGHT, 0x33, 0x00FFFF, 0, 0, (Dword)HEADER_STRING);
347
	bird.draw();
348
	for (int i = 0; i < tubeNumber; ++i)
349
		tubes[i].draw();
350
	kos_WriteTextToWindow(10, 10, 0x81, 0x000000, scoreString, 0);
351
	kos_WriteTextToWindow(10, 30, 0x81, 0x000000, CONTROL_STRING, 0);
352
}
353
void redrawGameWindow()
354
{
355
	//cleaning the screen
356
	if (scoreChanged)
357
		kos_DrawBar(80, 10, 50, 15, 0x00FFFF);
358
	if (bird.y > bird.prev_y)
359
		kos_DrawBar(bird.x, bird.prev_y, bird.sizeX, bird.y - bird.prev_y, 0x00FFFF);
360
	else
361
		kos_DrawBar(bird.x, bird.y + bird.sizeY, bird.sizeX, bird.prev_y - bird.y, 0x00FFFF);
362
 
363
	bird.draw();
364
	for (int i = 0; i < tubeNumber; ++i)
365
		tubes[i].draw();
366
 
367
	kos_WriteTextToWindow(10, 10, 0x81, 0x000000, scoreString, 0);
368
	kos_WriteTextToWindow(10, 30, 0x81, 0x000000, CONTROL_STRING, 0);
369
}
370
 
371
void drawGameoverWindow()
372
{
373
	kos_DefineAndDrawWindow(windowX, windowY, WINDOW_WIDTH, WINDOW_HEIGHT, 0x33, 0x000000, 0, 0, (Dword)HEADER_STRING);
374
	kos_WriteTextToWindow(125, 50, 0x82, 0xFFFFFF, GAMEOVER_STRING, 0);
375
	kos_WriteTextToWindow(135, 100, 0x81, 0xFFFFFF, scoreString, 0);
376
	kos_WriteTextToWindow(50, 150, 0x81, 0xFFFFFF, ANY_KEY_STRING, 0);
377
}
378
 
379
void WriteBorderedText(Word x, Word y, Byte fontType, Dword textColor, const char *textPtr, Dword textLen, Dword borderColor, int borderSize)
380
{
381
	kos_WriteTextToWindow(x - borderSize, y - borderSize, fontType, borderColor, textPtr, textLen);
382
	kos_WriteTextToWindow(x - borderSize, y + borderSize, fontType, borderColor, textPtr, textLen);
383
	kos_WriteTextToWindow(x + borderSize, y - borderSize, fontType, borderColor, textPtr, textLen);
384
	kos_WriteTextToWindow(x + borderSize, y + borderSize, fontType, borderColor, textPtr, textLen);
385
	kos_WriteTextToWindow(x, y, fontType, textColor, textPtr, textLen);
386
}
387
 
388
void drawMenuWindow()
389
{
390
	kos_DefineAndDrawWindow(windowX, windowY, WINDOW_WIDTH, WINDOW_HEIGHT, 0x33, 0x00FFFF, 0, 0, (Dword)HEADER_STRING);
391
 
392
	WriteBorderedText(85, 40, 0x4, 0xFFFFFF, HEADER_STRING, 6, 0x000000, 2);
393
	WriteBorderedText(185, 80, 0x84, 0xFFFFFF, HEADER_STRING + 7, 0, 0x000000, 2);
394
 
395
	RGB* pos = &tubeHeadImage[0];
396
	for (int x = 100 - 1; x >= 100 - Tube::headHeight; --x)
9046 leency 397
		for (int y = 170; y < 170 + Tube::width; ++y)
9011 leency 398
		{
399
			kos_PutPixel(x, y, (pos->r << 16) + (pos->g << 8) + (pos->b));	//first tube
400
			kos_PutPixel(x, y+100, (pos->r << 16) + (pos->g << 8) + (pos->b)); //second tube
401
			++pos;
402
		}
403
 
404
	//First button
405
	for(int x = 100; x < WINDOW_WIDTH - (BORDER_LEFT + BORDER_RIGHT - 1); ++x)
406
		kos_PutImage(tubeBodyImage, 1, Tube::width, x, 170);
407
	WriteBorderedText(140, 185, 0x82, 0x000000, FAST_STRING, 0, 0xFFFFFF, 1);
408
 
409
	//Second button
410
	for (int x = 100; x < WINDOW_WIDTH - (BORDER_LEFT + BORDER_RIGHT - 1); ++x)
411
		kos_PutImage(tubeBodyImage, 1, Tube::width, x, 270);
412
	WriteBorderedText(140, 285, 0x82, 0x000000, SLOW_STRING, 0, 0xFFFFFF, 1);
413
}
414
 
415
inline bool checkCollision(Tube tube)
416
{
9046 leency 417
	return ((tube.x <= (bird.x + bird.sizeX) && tube.x + tube.width >= bird.x)
418
		&& (bird.y <= tube.gapY || bird.y + bird.sizeY >= tube.gapY + tube.gapHeight));
9011 leency 419
}
420
 
421
inline bool checkAddScore(Tube tube)
422
{
423
	//int diff = bird.x - (tube.x + tube.width);
424
	//return diff == 0 || diff == 1;
425
	return ((bird.x - (tube.x + tube.width)) >> 1) == 0;
426
}
427
 
428
void updateScoreString()
429
{
430
	int temp = score;
431
	int index = 9;
432
	do {
433
		scoreString[index--] = temp % 10 + '0';
434
		temp /= 10;
435
	} while (temp > 0);
436
}