-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.cpp
490 lines (408 loc) · 13.1 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
// シューティングゲームサンプル
//
// 1年生の夏休み前までに覚えておきたい命令だけでつくられています。
// わからない命令は調べたり、先生に聞いたりして、
// 夏休み前に理解できるようにしましょう!
//
// Code by Masao Watanabe
// DXライブラリを使用するためにヘッダーファイルをインクルードする。
#include "DxLib.h"
#include "screen.h"
// ------------------------------------------------------------------------------------------------------------------------
// デファイン定義
// ------------------------------------------------------------------------------------------------------------------------
#define OBJECT_PLAYER 1 // プレイヤーを示すID
#define OBJECT_ENEMY 2 // 敵を示すID
#define STATE_NONE -1 // オブジェクトは存在していない
#define STATE_LIVE 1 // オブジェクトは存在中
#define STATE_HIT 2 // オブジェクトはぶつかっている
// プレイヤー情報用データ
#define PLAYER_START_X (SCREEN_WIDTH / 2) // プレイヤーの初期X位置
#define PLAYER_START_Y (SCREEN_HEIGHT - PLAYER_HEIGHT) // プレイヤーの初期Y位置
#define PLAYER_WIDTH 32 // プレイヤーの横幅
#define PLAYER_HEIGHT 32 // プレイヤーの縦幅
#define PLAYER_COLOR 0xFFFFFF // プレイヤーの色(16進数で記入されています)
#define PLAYER_SHOT_WIDTH 16 // プレイヤーのショットの横幅
#define PLAYER_SHOT_HEIGHT 16 // プレイヤーのショットの縦幅
#define PLAYER_SHOT_SPEED 8 // プレイヤーのショットのスピード
#define PLAYER_MOVESPEED 4 // プレイヤーの移動量
// 敵情報用データ
#define ENEMY_START_X 0 // 敵の初期X位置
#define ENEMY_START_Y 0 // 敵の初期Y位置
#define ENEMY_WIDTH 32 // 敵の横幅
#define ENEMY_HEIGHT 32 // 敵の縦幅
#define ENEMY_COLOR 0x00FF00 // 敵の色(16進数で記入されています)
#define ENEMY_SHOT_WIDTH 16 // 敵のショットの横幅
#define ENEMY_SHOT_HEIGHT 16 // 敵のショットの縦幅
#define ENEMY_MOVESPEED 2 // 敵の移動量
#define ENEMY_SHOT_SPEED 8 // 敵のショットのスピード
#define ENEMY_SHOT_MIN_TIME 100 // 敵がショットを打つまでの最低間隔
#define ENEMY_SHOT_MAX_TIME 400 // 敵がショットを打つまでの最大間隔
// 背景情報
#define BG_COLOR 0x000000 // 背景の色
#define SCREEN_WIDTH 640 // スクリーンの横幅
#define SCREEN_HEIGHT 480 // スクリーンの縦幅
// ------------------------------------------------------------------------------------------------------------------------
// 構造体定義
// ------------------------------------------------------------------------------------------------------------------------
// オブジェクト構造体。プレイヤー、敵、ショットの元となる構造体
struct OBJECT
{
int x; // X座標
int y; // Y座標
int width; // 横幅
int height; // 縦幅
int color; // 色
int state; // 状態を表す変数(-1...存在していない, 1...生きてる, 2...ぶつかった)
};
// ------------------------------------------------------------------------------------------------------------------------
// グローバル変数定義
// ------------------------------------------------------------------------------------------------------------------------
int PlayerGraphic;
OBJECT Player; // プレイヤー情報
OBJECT Enemy; // 敵情報
OBJECT PlayerShot; // プレイヤーのショット情報
OBJECT EnemyShot; // 敵のショット情報
int enemyMoveDirc = 1; // 敵の移動方向
int enemyShotTime = 0; // 敵が弾をうつタイミング
void InitGame(void);
void GameMain(void);
// --------------------------------------------------------------------
// メイン関数定義
// --------------------------------------------------------------------
int WINAPI WinMain(
HINSTANCE hInstance, // 現在のインスタンスのハンドル
HINSTANCE hPrevInstance, // 以前のインスタンスのハンドル
LPSTR lpCmdLine, // コマンドライン
int nCmdShow // 表示状態
)
{
// DXLIBの初期化処理
DxLib_Init();
// ゲーム初期化
InitGame();
// ゲームループ
// 以下の処理をエスケープキーが押されるまでかプレイヤーが生きている間繰り返す
while( ProcessMessage() == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 && Player.state == STATE_LIVE)
{
GameMain();
}
// DXLIBの終了処理
DxLib_End();
// アプリケーションの終了
return 0;
}
// --------------------------------------------------------------------
// プレイヤー情報の初期化関数
// --------------------------------------------------------------------
void InitPlayer()
{
int value = PLAYER_START_Y;
PlayerGraphic = LoadGraph("player.png");
// プレイヤーデータに初期値を入れる
Player.x = PLAYER_START_X;
Player.y = PLAYER_START_Y;
Player.width = PLAYER_WIDTH;
Player.height = PLAYER_HEIGHT;
Player.color = PLAYER_COLOR;
Player.state = STATE_LIVE;
// プレイヤーショットデータに初期値を入れる
// ショットは存在しない状態からゲームが開始されるので-1で初期化する
// 座標データはショットを打つまでわからないのでまだ入れない
PlayerShot.width = PLAYER_SHOT_WIDTH;
PlayerShot.height = PLAYER_SHOT_HEIGHT;
PlayerShot.color = PLAYER_COLOR;
PlayerShot.state = STATE_NONE;
return;
}
// --------------------------------------------------------------------
// 敵がショットをうつまでのタイミングを計算する
// --------------------------------------------------------------------
void CalcEnemyShotTiming()
{
// ショットを打つまでの間隔を決める
// ENEMY_SHOT_MIN_TIMEからENEMY_SHOT_MAX_TIMEまでの間の乱数をつくる
enemyShotTime = GetRand(ENEMY_SHOT_MAX_TIME - ENEMY_SHOT_MIN_TIME) + ENEMY_SHOT_MIN_TIME;
}
// --------------------------------------------------------------------
// 敵情報の初期化関数
// --------------------------------------------------------------------
void InitEnemy()
{
// 敵データの初期値を入れる
Enemy.x = GetRand(SCREEN_WIDTH - ENEMY_WIDTH); // 毎回ランダムな場所に出現させる
Enemy.y = ENEMY_START_Y;
Enemy.width = ENEMY_WIDTH;
Enemy.height = ENEMY_HEIGHT;
Enemy.color = ENEMY_COLOR;
Enemy.state = STATE_LIVE;
// 敵ショットデータに初期値を入れる
// ショットは存在しない状態からゲームが開始されるので-1で初期化する
// 座標データはショットを打つまでわからないのでまだ入れない
EnemyShot.width = ENEMY_SHOT_WIDTH;
EnemyShot.height = ENEMY_SHOT_HEIGHT;
EnemyShot.color = ENEMY_COLOR;
EnemyShot.state = STATE_NONE;
// 敵の初期移動方向を計算
// より広くあいている方向へ移動する
if (Enemy.x < SCREEN_WIDTH / 2)
{
enemyMoveDirc = 1;
}
else
{
enemyMoveDirc = -1;
}
CalcEnemyShotTiming();
return;
}
// --------------------------------------------------------------------
// ゲーム情報を初期化する関数
// --------------------------------------------------------------------
void InitGame()
{
// プレイヤー情報の初期化
InitPlayer();
// 敵情報の初期化
InitEnemy();
return;
}
// --------------------------------------------------------------------
// オブジェクト描画を行う関数
// --------------------------------------------------------------------
void DrawObject(OBJECT target)
{
// オブジェクトが存在しないときは描画しなくてよい
if (target.state == STATE_NONE) return;
// オブジェクト描画
DrawBox(target.x, // X1座標
target.y, // Y1座標
target.x + target.width - 1, // X2座標 この引数は幅を指定するのではなく座標をしているので-1している。
target.y + target.height - 1, // Y2座標 この引数は幅を指定するのではなく座標をしているので-1している。
target.color, // 色
TRUE); // 塗りつぶしモード(TRUEで塗りつぶし、FALSE)
return;
}
// --------------------------------------------------------------------
// 背景を塗りつぶす関数
// --------------------------------------------------------------------
void DrawBG()
{
RECT screenRect; // 描画エリアを格納する変数
// 描画エリアを取得する
GetDrawArea(&screenRect);
// 背景を塗りつぶす
DrawBox(screenRect.left, // X1座標
screenRect.top, // Y1座標
screenRect.right - 1, // X2座標 この引数は幅を指定するのではなく座標をしているので-1している。
screenRect.bottom - 1, // Y2座標 この引数は幅を指定するのではなく座標をしているので-1している。
BG_COLOR, // 塗りつぶし色
TRUE); // 塗りつぶしモード(TRUEで塗りつぶし、FALSE)
return;
}
// --------------------------------------------------------------------
// objAとobjBが衝突しているかを調べる
// 引数:OBJECT objA,objB...衝突判定したいオブジェクト
// 戻り値:1...衝突している 0...衝突していない
// --------------------------------------------------------------------
int IsHit(OBJECT objA, OBJECT objB)
{
int x0 = objA.x;
int y0 = objA.y;
int x1 = objA.x + objA.width - 1;
int y1 = objA.y + objA.height - 1;
int x2 = objB.x;
int y2 = objB.y;
int x3 = objB.x + objB.width - 1;
int y3 = objB.y + objB.height - 1;
// 二つの矩形が何かしらの形で重なっているか?
if (x0 < x3 && x2 < x1 && y0 < y3 && y2 < y1)
{
int z = 0;
z++;
// 重なっていた
return 1;
}
// 重なってなかった
return 0;
}
// --------------------------------------------------------------------
// 弾を生成する関数
// 引数:int shooterID...弾をうつのはプレイヤーか敵なのかの情報
// 引数:OBJECT shooter...弾をうったオブジェクト情報
// --------------------------------------------------------------------
void CreateShot(int shooterID, OBJECT shooter)
{
// 自分の弾か敵の弾なのかで処理を変更
switch(shooterID)
{
case OBJECT_PLAYER:
PlayerShot.state = STATE_LIVE;
PlayerShot.x = shooter.x + shooter.width / 2 - PlayerShot.width / 2; // プレイヤーの真ん中から発射
PlayerShot.y = shooter.y - PlayerShot.height;
break;
case OBJECT_ENEMY:
EnemyShot.state = STATE_LIVE;
EnemyShot.x = shooter.x + shooter.width / 2 - EnemyShot.width / 2; // 敵の真ん中から発射
EnemyShot.y = shooter.y + shooter.height;
break;
}
}
// --------------------------------------------------------------------
// プレイヤーの移動・ショットの発射処理を行う
// --------------------------------------------------------------------
void ControllPlayer()
{
// 右カーソルが押されているかどうかをチェック
if (CheckHitKey(KEY_INPUT_RIGHT) == 1)
{
Player.x += PLAYER_MOVESPEED;
}
// 左カーソルが押されているかどうかをチェック
if (CheckHitKey(KEY_INPUT_LEFT) == 1)
{
Player.x -= PLAYER_MOVESPEED;
}
// ショット発射チェック
if (CheckHitKey(KEY_INPUT_SPACE) == 1 && PlayerShot.state == STATE_NONE)
{
// 弾を生成
CreateShot(OBJECT_PLAYER, Player);
}
}
// --------------------------------------------------------------------
// プレイヤーのショットの移動関数
// --------------------------------------------------------------------
void ControllPlayerShot()
{
// 弾が無いか敵にヒットしているなら移動処理はせずに終了
if (PlayerShot.state != STATE_LIVE) return;
// 弾の移動
PlayerShot.y -= PLAYER_SHOT_SPEED;
// 弾は敵にヒットしている?
if (IsHit(PlayerShot, Enemy) == TRUE)
{
// 弾を消す
PlayerShot.state = STATE_NONE;
// 敵をまた出す
InitEnemy();
return;
}
// 弾は画面外に消えた?
if (PlayerShot.y < 0)
{
PlayerShot.state = STATE_NONE;
}
return;
}
// --------------------------------------------------------------------
// 敵のショットの移動関数
// --------------------------------------------------------------------
void ControllEnemyShot()
{
// 弾が無いかプレイヤーにヒットしているなら移動処理はせずに終了
if (EnemyShot.state != STATE_LIVE) return;
// 弾の移動
EnemyShot.y += ENEMY_SHOT_SPEED;
// 弾はプレイヤーにヒットしている?
if (IsHit(EnemyShot, Player) == TRUE)
{
// 弾を消す
EnemyShot.state = STATE_NONE;
// プレイヤーを死亡状態にする
Player.state = STATE_HIT;
return;
}
// 弾は画面外に消えた?
if (EnemyShot.y > SCREEN_HEIGHT)
{
EnemyShot.state = STATE_NONE;
}
return;
}
// --------------------------------------------------------------------
// 敵の移動・ショットの発射処理を行う
// --------------------------------------------------------------------
void ControllEnemy()
{
// 端っこまで来ていたら移動方向を反転
switch (enemyMoveDirc)
{
case -1:
if (Enemy.x <= 0)
{
enemyMoveDirc = 1;
}
break;
case 1:
if (Enemy.x >= SCREEN_WIDTH - ENEMY_WIDTH)
{
enemyMoveDirc = -1;
}
break;
}
// 移動
Enemy.x += ENEMY_MOVESPEED * enemyMoveDirc;
// ショット発射チェック
enemyShotTime--;
if (enemyShotTime == 0)
{
// 弾を現在出していないのなら弾を出す
if (EnemyShot.state == STATE_NONE)
{
// 弾を生成
CreateShot(OBJECT_ENEMY, Enemy);
}
// 次に弾をうつ間隔を決める
CalcEnemyShotTiming();
}
}
// --------------------------------------------------------------------
// プレイヤー、敵、弾の移動、あたり判定処理を呼ぶ
// --------------------------------------------------------------------
void ControllGame()
{
// プレイヤーの移動判定
ControllPlayer();
// プレイヤーのショットの移動
ControllPlayerShot();
// 敵の移動処理
ControllEnemy();
// 敵の弾の移動処理
ControllEnemyShot();
return;
}
// --------------------------------------------------------------------
// プレイヤー、敵、弾、背景の描画処理を呼ぶ
// --------------------------------------------------------------------
void DrawGame()
{
// 画面を初期化
ClearDrawScreen();
// 描画先画面を裏にする
SetDrawScreen( DX_SCREEN_BACK );
// 背景描画
DrawBG();
// プレイヤーの描画処理
DrawObject(Player);
// プレイヤーの弾描画
DrawObject(PlayerShot);
// 敵の描画
DrawObject(Enemy);
// 敵の弾描画
DrawObject(EnemyShot);
// 裏画面に描いたものを表画面に反映する
ScreenFlip();
return;
}
// --------------------------------------------------------------------
// 様々なゲーム内処理を呼ぶ関数
// --------------------------------------------------------------------
void GameMain()
{
// コントロール
ControllGame();
// 描画
DrawGame();
return;
}