さあC言語(DXライブラリ)を使って超繊細、美麗、箱庭シューティングゲームを作ってみましょう 超初心者向けです 0.367
自機と敵機がぶつかったら 自機と敵機が消えるようにするだけでなく さらに 自分の弾と敵機がぶつかったら 自分の弾と敵機が消えるようにしてみましょう
自機と敵機がぶつかったら 自機と敵機が消えるようにするだけでなく さらに 自分の弾と敵機がぶつかったら 自分の弾と敵機が消えるようにしてみましょう
ソーラー「それは置いておいて
今度は
自機と敵機がぶつかったら
自機と敵機が消えるようにするだけでなく
Ⓜ️自分の弾Ⓜ️と敵機がぶつかったら
自分の弾と敵機が消えるようにしてみましょう
今回
登場する敵は1機
Zボタンを押すと1度に発射される弾は
1発にするね
(ここでは敵のデータを取り扱うために
struct Character tekinohikouki[1];
を実行して
構造体変数tekinohikouki[0]を作成し
自分の弾のデータを取り扱うために
struct Character jibunnotama[1];
を
実行して
構造体変数jibunnotama[0]を作成します)
まず手始めに
自分の弾と敵機がぶつかったときの
判定条件を
求めてみようよ」
マックス「自分の弾と敵機がぶつかったときの
判定条件をか?
なんで?
暇なのか?」
solarplexuss「もう それ今までやってきたことじゃない
自分の弾と敵機がぶつかったときの
判定条件をみたしたとき
自分の弾と敵機が消えるようにするんでしょう
自分の弾と敵機がぶつかったときの
判定条件とは
自分の弾の画像データの中の四角形の領域
と
敵機の画像データの中の四角形の領域
が重なった状態を表す条件のことでしょう
その条件を満たしたとき
自分の弾と敵機が消えるようにするようにすればいいんでしょ〜う💃」
ソーラー「そのとおり
そして
自分の弾の画像データの中の四角形の領域
と
敵機の画像データの中の四角形の領域
が重なった状態を表す条件は
自分の弾の画像データの中の四角形の頂点の座標
と
敵機の画像データの中の四角形の頂点の座標
であらわされることになるんだったね」
solarplexuss「え〜とっ
確か・・・
敵機の画像データの中の
緑色の四角形の左上の頂点の座標は
(tekinohikouki.x+7, tekinohikouki.y+6)
緑色の四角形の左下の頂点の座標は
(tekinohikouki.x+7, tekinohikouki.y+13)
緑色の四角形の右上の頂点の座標は
(tekinohikouki.x+28,tekinohikouki.y+6)
緑色の四角形の右下の頂点の座標は
(tekinohikouki.x+28,tekinohikouki.y+13)
となっていたよね」
その様子はこちらです
👇
https://solalion.blogspot.com/2021/11/blog-post_78.html
solarplexuss「敵機の画像データの中の四角形の頂点の座標がわかったところで
次は
自分の弾の画像データの中の四角形の頂点の座標を求めてみようかな?
そのためにまずは
自分の弾の画像データの中の四角形の領域
を
決めてみようかな」
その様子はこちらです
👇
https://solalion.blogspot.com/2021/11/blog-post_84.html
(自分の弾のあたり判定の四角形の領域は青色で覆われています)
マックス「なんだ まんま 自分の弾の画像データの全部の四角形の領域を
あたり判定の四角形の領域に選んだわけだ」
ソーラー「自分の弾の画像データには
何も描かれていない黒い領域がほとんどない
つまり
自分の弾の画像データのほとんどの領域に自分の弾が描かれているので
自分の弾の画像データの全部の領域を
自分の弾のあたり判定に使うことにしたってわけなんだね
自分の弾の画像がゲーム画面に表示されるときの
自分の弾の画像データの左上の頂点の座標は
(jibunnotama[0].x,jibunnotama[0].y)
となるので
青色の四角形の左上の頂点の座標は
(jibunnotama[0].x,jibunnotama[0].y)
青色の四角形の左下の頂点の座標は
(jibunnotama[0]x,jibunnotama[0].y+5)
青色の四角形の右上の頂点の座標は
(jibunnotama[0].x+15,jibunnotama[0].y)
青色の四角形の右下の頂点の座標は
(jibunnotama[0].x+15,jibunnotama[0].y+5)
となるね
となると
今までのエピソードで学んだように
🌞y軸の下にいくほどyの座標の値が大きくなる特殊なxy平面であるゲーム画面上での🌞
自分の弾の画像データの中の青色の四角形の領域
と
敵機の画像データの中の緑色の四角形の領域
が
重なっている条件は
jibunnotama[0].x<tekinohikouki.x+28
かつ
tekinohikouki.x+7< jibunnotama[0].x+15
かつ
jibunnotama[0].y< tekinohikouki.y+13
かつ
tekinohikouki.y+6< jibunnotama[0].y+5
となります
自分の弾の画像データの中の青色の四角形の領域
と
敵機の画像データの中の緑色の四角形の領域
が重なったとき
すなわち
jibunnotama[0].x<tekinohikouki.x+28
かつ
tekinohikouki.x+7< jibunnotama[0].x+15
かつ
jibunnotama[0].y< tekinohikouki.y+13
かつ
tekinohikouki.y+6< jibunnotama[0].y+5
を満たしたとき
自分の弾と敵機が消えるようにすればいいわけなんだね」
そのプログラムはこちらです
👇
#include "DxLib.h"
struct Character {
int x;
int y;
int graphichandle;
int life;
};
//👆🌞Characterの構造体宣言です
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
ChangeWindowMode(TRUE); // ウインドウモードに設定します
if (DxLib_Init() == -1) // DXライブラリを初期化処理しています
{
return -1; // DXライブラリの初期化に失敗したら直ちにプログラムを終了します
}
SetDrawScreen(DX_SCREEN_BACK);//👈🌞SetDrawScreen関数です 裏画面に画像を描きます
struct Character jibunnohikouki;
//👆🌞jibunnohikoukiの構造体変数宣言です
jibunnohikouki.x = 0;
jibunnohikouki.y = 0;
jibunnohikouki.graphichandle = LoadGraph("画像データ\\ソーラーが描いた飛行機.bmp");
jibunnohikouki.life = 1;//👈🌞🌞🌞ここがポイントです🌞🌞🌞
//👆🌞構造体変数jibunnohikoukiのメンバ変数の初期化を行っています
//👆😋自分の飛行機😋のデータをとりあつかっています
struct Character tekinohikouki[1];
//👆🌞敵の飛行機を1体登場させるために要素数を1にして構造体変数tekinohikouki[0]を1つ作成します
tekinohikouki[0].x = 600;
tekinohikouki[0].y = 100;
tekinohikouki[0].graphichandle = LoadGraph("画像データ\\敵の飛行機.bmp");
//👆メモリに取り込まれた😋敵の飛行機のデータ😋に割り当てられた番号が tekinohikouki[0].graphichandle に代入されています
tekinohikouki[0].life = 1; //👈🌞🌞🌞ここがポイントです🌞🌞🌞
//👆🌞構造体変数tekinohikouki[0]のメンバ変数の初期化を行っています
//👆😋敵の飛行機😋のデータをとりあつかっています
struct Character jibunnotama[1];
//🌞👆自分の弾を1つ作成しています
for (int i = 0; i < 1; i = i + 1) {
jibunnotama[i].x = 0;
jibunnotama[i].y = 0;
jibunnotama[i].graphichandle = LoadGraph("画像データ\\自分の弾.bmp");
jibunnotama[i].life = 0;
}
int tsix;//🌞🌞🌞tsixには発射される弾の最初の位置のx座標が代入されることになります tは弾、sは最初、iは位置、xはx座標を表しています
int count = 0;//🌞🌞🌞ここでint型の変数countを作製し0で初期化しました
while (CheckHitKey(KEY_INPUT_ESCAPE) == 0 && ProcessMessage() == 0) {
DrawBox(100, 100, 500, 300, GetColor(0, 255, 255), TRUE);
int key = GetJoypadInputState(DX_INPUT_KEY_PAD1);
if (key & PAD_INPUT_UP) jibunnohikouki.y = jibunnohikouki.y - 4;
if (key & PAD_INPUT_DOWN) jibunnohikouki.y = jibunnohikouki.y + 4;
if (key & PAD_INPUT_LEFT) jibunnohikouki.x = jibunnohikouki.x - 4;
if (key & PAD_INPUT_RIGHT) jibunnohikouki.x = jibunnohikouki.x + 4;
if (jibunnohikouki.life == 1) {
DrawGraph(jibunnohikouki.x, jibunnohikouki.y, jibunnohikouki.graphichandle, TRUE);
}
//👆 jibunnohikouki.lifeに格納されている値が1なら自分の飛行機の画像を描きます
//👆jibunnohikouki.lifeに格納されている値が0なら自分の飛行機の画像が描かれることはありません
for (int i= 0; i < 1; i++) {
if (tekinohikouki[i].life == 1) {
DrawGraph(tekinohikouki[i].x, tekinohikouki[i].y, tekinohikouki[i].graphichandle, TRUE);
}
}
//👆 tekinohikouki[0].lifeに格納されている値が1なら敵の飛行機の画像を描きます
//👆 tekinohikouki[0].lifeに格納されている値が0なら敵の飛行機の画像が描かれることはありません
for (int i = 0; i < 1; i++)
if ((jibunnohikouki.x + 7 < tekinohikouki[i].x + 28) && (tekinohikouki[i].x + 7 < jibunnohikouki.x + 27) && (jibunnohikouki.y + 7 < tekinohikouki[i].y + 13) && (tekinohikouki[i].y + 6 < jibunnohikouki.y + 13)) {
jibunnohikouki.life = 0;
tekinohikouki[i].life = 0;
}
//👆自機と敵機が重なった条件を満たせばjibunnohikouki.lifeとtekinohikouki[0].lifeには0が代入されることになります
for (int i = 0; i < 1; i++){
if ((jibunnotama[0].x < tekinohikouki[i].x + 28) && (tekinohikouki[i].x + 7 < jibunnotama[0].x + 15) && (jibunnotama[0].y < tekinohikouki[i].y + 13) && (
tekinohikouki[i].y + 6 < jibunnotama[0].y + 5)) {
jibunnotama[0].life = 0;
tekinohikouki[i].life = 0;
}
}
//👆自分の弾と敵機が重なった条件を満たせばjibunnotama[0].lifeとtekinohikouki[0].lifeには0が代入されることになります
/*👆この部分は以下のように書き換えることができます
for (int i = 0; i < 1; i = i + 1) {
for (int j= 0; j< 1; j= j+ 1){
if ((jibunnotama[j].x < tekinohikouki[i].x + 28) && (tekinohikouki[i].x + 7 < jibunnotama[j].x + 15) && (jibunnotama[j].y < tekinohikouki[i].y + 13) && (
tekinohikouki[i].y + 6 < jibunnotama[j].y + 5)) {
jibunnotama[j].life = 0;
tekinohikouki[i].life = 0;
}
}
}
なぜこのように記述するのかの解説は後ほどです🥰
*/
if ((key & PAD_INPUT_A) && (count == 0)) {
for (int i = 0; i < 1; i = i + 1) {
if (jibunnotama[i].life == 0) {
jibunnotama[i].x = jibunnohikouki.x + 35;
tsix = jibunnotama[i].x;
jibunnotama[i].y = jibunnohikouki.y + 20;
jibunnotama[i].life = 1;
break;
}
}
count = 10;
}
if (count > 0) { count = count - 1; }
for (int i = 0; i < 1; i = i + 1) {
if (jibunnotama[i].life == 1) {
//🌞🌞🌞 jibunnotama[i].lifeに1が代入されていると自分の弾がゲーム画面に表示されることになります jibunnotama[i].lifeに0が代入されていると自分の弾がゲーム画面に表示されることになります
DrawGraph(jibunnotama[i].x, jibunnotama[i].y, jibunnotama[i].graphichandle, TRUE);
jibunnotama[i].x = jibunnotama[i].x + 10;
if (jibunnotama[i].x - tsix > 640)
//🌞🌞🌞発射された弾の位置のx座標が発射されたときの最初の弾の位置のx座標から640を超えて離れると条件式jibunnotama[i].x - tsix > 640は真の値1をとることになります
//🌞🌞🌞🌞🌞👆 tsixにはZボタンが押されたときの自分の弾のいる位置のx座標を記憶していたのでjibunnotama[i].xがZボタンが押されたときの自分の弾のいる位置から640ドット離れた時jibunnotama[i].x -tsix> 640は真の値1を持つことになります
jibunnotama[i].life = 0;
}
}
ScreenFlip();
ClearDrawScreen();
};
DxLib_End(); // DXライブラリの使用を終了します DXライブラリの使用しているメモリ領域が解放されます
return 0; // プログラムを終了します
}
デバッグなしで実行をしてから一度プログラムを終了し
生成されたexeファイルをハードディスクから探し出しクリックする方法により得られたプログラムの実行結果はこちらです
👇
https://www.youtube.com/watch?v=mkIGYVJKwjo
マックス「自分の弾と敵機があたっても
自分の弾と敵機が消えるようになった!
が
なんか微妙い
自分の弾と敵機が当たって
自分の弾と敵機が消えるようになったのはいいんだが
敵機の表示されていた場所に
新たな自分の弾を打ち込むと
その位置で自分の弾がきえてしまうじゃないか
何にも見えてないところで自分の弾が消えるのか
ぬあんでぇ」
solarplexuss「ホントだ
そこに敵機がいるみたい」
ソーラー「確かに
敵機はみえなくなっただけで
その位置に敵機はいるからね
だからその位置に自分の弾を打ち込んだら
自分の弾と敵機が当たったと判定されて
自分の弾が消えるんだね
だから
敵機が消えたら
新たに
その敵機が消えた場所に
(見えなくなっている敵機に)
自分の弾を打ち込んでも
自分の弾は消えないようにする必要があるんだね
自分の弾と敵機がぶつかったと判定されたとき
tekinohikouki[0].life = 0;
が実行されるので
(このとき敵機が消えることになります)
tekinohikouki[0].lifeに0が代入されたときは
自分の弾は消えないようすればいいんだね」
マックス「なんだ 簡単に解決しそうじゃないか」
ソーラー「では
自分の弾が撃ち込まれて
見えなくなっている敵機に
新たに
自分の弾を打ち込んでも
自分の弾は消えないようにする
その前に
とりあえず
今のこのプログラムの仕組みを考察してみましょう
このプログラムでは
struct Character tekinohikouki[1];
を行い
Character型の構造体変数
tekinohikouki[0]
を
用意しています
1体の敵の飛行機
(ここでは
敵の飛行機とよびます)
のデータを
Character型の構造体変数
tekinohikouki[0]
のメンバ変数を用いて取り扱っています
tekinohikouki[0].x = 600;
tekinohikouki[0].y = 100;
tekinohikouki[0].graphichandle = LoadGraph("画像データ\\敵の飛行機.bmp");
tekinohikouki[0].life=1;
の実行により
Character型の構造体変数
tekinohikouki[0]
のメンバ変数
tekinohikouki[0].x
tekinohikouki[0].y
tekinohikouki[0].graphichandle
tekinohikouki[0].life
を敵の飛行機のデータで初期化しています
そして
for(int i=0;i<1;i++){
if(tekinohikouki[i].life==1){
DrawGraph(tekinohikouki[i].x, tekinohikouki[i].y, tekinohikouki[i].graphichandle, TRUE);
}
}
の実行に注目ですね
tekinohikouki[0].lifeに格納されている値が1なら
敵の飛行機の画像が表示され
tekinohikouki[0].lifeに格納されている値が0なら
敵の飛行機の画像は表示されません
そして
for(int i=0;i<1;i++)
if((jibunnohikouki.x+7< tekinohikouki[i].x+28)&&(tekinohikouki[i].x+7 < jibunnohikouki.x+27)&& (jibunnohikouki.y+7< tekinohikouki[i].y+13)&&(tekinohikouki[i].y+6<jibunnohikouki.y+13)){
jibunnohikouki.life=0;
tekinohikouki[i].life=0;
}
の実行ですね
iは0のときの
条件式
(jibunnohikouki.x+7< tekinohikouki[0].x+28)&&(tekinohikouki[0].x+7 < jibunnohikouki.x+27)&& (jibunnohikouki.y+7< tekinohikouki[0].y+13)&&(tekinohikouki[0].y+6<jibunnohikouki.y+13)
が
真の値1を持つとき
すなわち
(jibunnohikouki.x+7< tekinohikouki[0].x+28)
かつ
(tekinohikouki[0].x+7 < jibunnohikouki.x+27)
かつ
(jibunnohikouki.y+7< tekinohikouki[0].y+13)
かつ
(tekinohikouki[0].y+6<jibunnohikouki.y+13)
が満たされた時
自機と敵の飛行機がぶつかったと判定されます
このとき
jibunnohikouki.life=0;
tekinohikouki[0].life=0;
が実行されて
jibunnohikouki.life
と
tekinohikouki[0].life
に
0が代入されるので
自機と敵の飛行機が表示されることはなくなります
つまり
自機と敵の飛行機は消えるというわけです
ここまでが
自機と敵機
が当たったとき
自機と敵機が消える仕組みだね」
solarplexuss「はい 遠い過去のお話でした」
ソーラー「
そして続いて
for (int i = 0; i < 1; i = i + 1) {
if ((jibunnotama[0].x < tekinohikouki[i].x + 28) && (tekinohikouki[i].x + 7 < jibunnotama[0].x + 15) && (jibunnotama[0].y < tekinohikouki[i].y + 13) && (
tekinohikouki[i].y + 6 < jibunnotama[0].y + 5)) {
jibunnotama[0].life = 0;
tekinohikouki[i].life = 0;
}
}
//👆自分の弾と敵機が重なった条件を満たせばjibunnotama[0].lifeとtekinohikouki[0].lifeには0が代入されることになります
の実行ですね
iは0のときの
条件式
(jibunnotama[0].x < tekinohikouki[0].x + 28) && (tekinohikouki[0].x + 7 < jibunnotama[0].x + 15) && (jibunnotama[0].y < tekinohikouki[0].y + 13) && (
tekinohikouki[0].y + 6 < jibunnotama[0].y + 5)
が
真の値1を持つとき
自分の弾と敵の飛行機がぶつかったと判定されます
このとき
jibunnotama[0].life = 0;
tekinohikouki[0].life=0;
が実行されて
jibunnotama[0].life
と
tekinohikouki[0].life
に
0が代入されるので
自分の弾と敵の飛行機が表示されることはなくなります
つまり
自分の弾と敵の飛行機は消えるというわけです
自分の弾は消えたとしても新たに何度でも自分の弾を発射することができるので
このままでは
😊✈️敵の飛行機✈️はすでに消えていても😊
新たに発射された自分の弾と敵機がぶつかった時の条件
(jibunnotama[0].x < tekinohikouki[0].x + 28)
かつ
(tekinohikouki[0].x + 7 < jibunnotama[0].x + 15)
かつ
(jibunnotama[0].y < tekinohikouki[0].y + 13)
かつ
(tekinohikouki[0].y + 6 < jibunnotama[0].y + 5)
が満たされて
条件式
(jibunnotama[0].x < tekinohikouki[i].x + 28) && (tekinohikouki[0].x + 7 < jibunnotama[0].x + 15) && (jibunnotama[0].y < tekinohikouki[0].y + 13) && (tekinohikouki[0].y + 6 < jibunnotama[0].y + 5)
が
真の値1を持つとき
jibunnotama[0].life = 0;
tekinohikouki[0].life=0;
が実行されて
😊新たに発射された自分の弾は敵機とぶつかったと判定された位置で消えてしまうことになります😊
そこで
tekinohikouki[0].life=0;
が実行されて
tekinohikouki[0].lifeに0が代入された場合
もう自分の弾と見えない敵機がぶつかっても自分の弾が消えないように
for (int i = 0; i < 1; i = i + 1) {
if ((jibunnotama[0].x < tekinohikouki[i].x + 28) && (tekinohikouki[i].x + 7 < jibunnotama[0].x + 15) && (jibunnotama[0].y < tekinohikouki[0].y + 13) && (
tekinohikouki[i].y + 6 < jibunnotama[0].y + 5)) {
jibunnotama[0].life = 0;
tekinohikouki[i].life = 0;
}
}
が実行されないようにする必要があります」
solarplexuss「じゃあ
tekinohikouki[0].lifeに1が代入されていて
ゲーム画面に
敵機が
表示される場合にのみ
for (int i = 0; i < 1; i = i + 1) {
if ((jibunnotama[0].x < tekinohikouki[i].x + 28) && (tekinohikouki[i].x + 7 < jibunnotama[0].x + 15) && (jibunnotama[0].y < tekinohikouki[i].y + 13) && (
tekinohikouki[i].y + 6 < jibunnotama[0].y + 5)) {
jibunnotama[0].life = 0;
tekinohikouki[i].life = 0;
}
}
が
実行されるようにすればいいんじゃなーい?
だったら
if(tekinohikouki[0].life==1)
を
for (int i = 0; i < 1; i = i + 1) {
if ((jibunnotama[0].x < tekinohikouki[i].x + 28) && (tekinohikouki[i].x + 7 < jibunnotama[0].x + 15) && (jibunnotama[0].y < tekinohikouki[i].y + 13) && (
tekinohikouki[i].y + 6 < jibunnotama[0].y + 5)) {
jibunnotama[0].life = 0;
tekinohikouki[i].life = 0;
}
}
にくっつけた
👇
if(tekinohikouki[0].life==1){
for (int i = 0; i < 1; i = i + 1) {
if ((jibunnotama[0].x < tekinohikouki[i].x + 28) && (tekinohikouki[i].x + 7 < jibunnotama[0].x + 15) && (jibunnotama[0].y < tekinohikouki[i].y + 13) && (
tekinohikouki[i].y + 6 < jibunnotama[0].y + 5)) {
jibunnotama[0].life = 0;
tekinohikouki[i].life = 0;
}
}
}
を実行すればいいんじゃないかな」
ソーラー「いいアイデアだね
う〜ん この場合は
それでもいいんだけど
ただしくは
for (int i = 0; i < 1; i = i + 1)の中で
if(tekinohikouki[i].life==1)を
👇
if ((jibunnotama[0].x < tekinohikouki[i].x + 28) && (tekinohikouki[i].x + 7 < jibunnotama[0].x + 15) && (jibunnotama[0].y < tekinohikouki[i].y + 13) && (
tekinohikouki[i].y + 6 < jibunnotama[0].y + 5)) {
jibunnotama[0].life = 0;
tekinohikouki[i].life = 0;
}
👆
の前にくっつけた
for (int i = 0; i < 1; i = i + 1) {
if(tekinohikouki[i].life==1){
if ((jibunnotama[0].x < tekinohikouki[i].x + 28) && (tekinohikouki[i].x + 7 < jibunnotama[0].x + 15) && (jibunnotama[0].y < tekinohikouki[i].y + 13) && (
tekinohikouki[i].y + 6 < jibunnotama[0].y + 5)) {
jibunnotama[0].life = 0;
tekinohikouki[i].life = 0;
}
}
}
を実行することになります」
solarplexuss「ぬあぜですかあー」
ソーラー「それは
👇
for (int i = 0; i < 1; i = i + 1) {
if(tekinohikouki[i].life==1){
if ((jibunnotama[0].x < tekinohikouki[i].x + 28) && (tekinohikouki[i].x + 7 < jibunnotama[0].x + 15) && (jibunnotama[0].y < tekinohikouki[i].y + 13) && (
tekinohikouki[i].y + 6 < jibunnotama[0].y + 5)) {
jibunnotama[0].life = 0;
tekinohikouki[i].life = 0;
}
}
}
👆
の
意味を考えてみればよくわかります
これは
jibunnotama[0]とtekinohikouki[0]
がぶつかったと判定されたときに時に実行される命令文なんです
ということは
for (int i = 0; i < 1; i = i + 1)
を
for (int i = 0; i < 5; i = i + 1)
に切り替えた
👇
for (int i = 0; i < 5; i = i + 1) {
if(tekinohikouki[i].life==1){
if ((jibunnotama[0].x < tekinohikouki[i].x + 28) && (tekinohikouki[i].x + 7 < jibunnotama[0].x + 15) && (jibunnotama[0].y < tekinohikouki[i].y + 13) && (
tekinohikouki[i].y + 6 < jibunnotama[0].y + 5)) {
jibunnotama[0].life = 0;
tekinohikouki[i].life = 0;
}
}
}
👆
の場合は
jibunnotama[0]とtekinohikouki[0]
jibunnotama[0]とtekinohikouki[1]
jibunnotama[0]とtekinohikouki[2]
jibunnotama[0]とtekinohikouki[3]
jibunnotama[0]とtekinohikouki[4]
がぶつかったと判定されたときに時に実行される命令文なんです
jibunnotama[0]とtekinohikouki[0]
jibunnotama[0]とtekinohikouki[1]
jibunnotama[0]とtekinohikouki[2]
jibunnotama[0]とtekinohikouki[3]
jibunnotama[0]とtekinohikouki[4]
がぶつかったなら
jibunnotama[0].life = 0;
tekinohikouki[0].life = 0;
jibunnotama[0].life = 0;
tekinohikouki[1].life = 0;
jibunnotama[0].life = 0;
tekinohikouki[2].life = 0;
jibunnotama[0].life = 0;
tekinohikouki[3].life = 0;
jibunnotama[0].life = 0;
tekinohikouki[4].life = 0;
が実行されることになります
つまり
自分の弾を発射して
jibunnotama[0]とtekinohikouki[0]
もしくは
jibunnotama[0]とtekinohikouki[1]
もしくは
jibunnotama[0]とtekinohikouki[2]
もしくは
jibunnotama[0]とtekinohikouki[3]
もしくは
jibunnotama[0]とtekinohikouki[4]
がぶつかったなら
tekinohikouki[0].life
tekinohikouki[1].life
tekinohikouki[2].life
tekinohikouki[3].life
tekinohikouki[4].life
には0が代入されることになるので
tekinohikouki[0]
もしくは
tekinohikouki[1]
もしくは
tekinohikouki[2]
もしくは
tekinohikouki[3]
もしくは
tekinohikouki[4]
は
ゲーム画面から消えることになりますね
ところが
👇
if(tekinohikouki[0].life==1){
for (int i = 0; i < 5; i = i + 1) {
if ((jibunnotama[0].x < tekinohikouki[i].x + 28) && (tekinohikouki[i].x + 7 < jibunnotama[0].x + 15) && (jibunnotama[0].y < tekinohikouki[i].y + 13) && (
tekinohikouki[i].y + 6 < jibunnotama[0].y + 5)) {
jibunnotama[0].life = 0;
tekinohikouki[i].life = 0;
}
}
}
👆
と記述してしまうとおかしなことがおこります
この命令文は
tekinohikouki[0].life==1が真の値1を持つ場合にのみ
すなわち
tekinohikouki[0]がゲーム画面に表示されている時の条件のもとで
(tekinohikouki[0]が消滅していないときに)
jibunnotama[0]とtekinohikouki[0]
jibunnotama[0]とtekinohikouki[1]
jibunnotama[0]とtekinohikouki[2]
jibunnotama[0]とtekinohikouki[3]
jibunnotama[0]とtekinohikouki[4]
がぶつかったと判定されたときに時に実行される命令文なんです
tekinohikouki[0]がゲーム画面に表示されているかどうかで
実行される命令文なので
tekinohikouki[0]がゲーム画面に表示されている場合は
jibunnotama[0]とtekinohikouki[0]
jibunnotama[0]とtekinohikouki[1]
jibunnotama[0]とtekinohikouki[2]
jibunnotama[0]とtekinohikouki[3]
jibunnotama[0]とtekinohikouki[4]
がぶつかったなら
jibunnotama[0].life = 0;
tekinohikouki[0].life = 0;
jibunnotama[0].life = 0;
tekinohikouki[1].life = 0;
jibunnotama[0].life = 0;
tekinohikouki[2].life = 0;
jibunnotama[0].life = 0;
tekinohikouki[3].life = 0;
jibunnotama[0].life = 0;
tekinohikouki[4].life = 0;
が実行されることになります
つまり
自分の弾を発射して
jibunnotama[0]とtekinohikouki[0]
もしくは
jibunnotama[0]とtekinohikouki[1]
もしくは
jibunnotama[0]とtekinohikouki[2]
もしくは
jibunnotama[0]とtekinohikouki[3]
もしくは
jibunnotama[0]とtekinohikouki[4]
がぶつかったなら
(
for(int i=0;i<5《😊》;i++){
if(tekinohikouki[i].life==1){
DrawGraph(tekinohikouki[i].x, tekinohikouki[i].y, tekinohikouki[i].graphichandle, TRUE);
}
}
と記述されていた場合)
tekinohikouki[0].life
もしくは
tekinohikouki[1].life
もしくは
tekinohikouki[2].life
もしくは
tekinohikouki[3].life
もしくは
tekinohikouki[4].life
に格納されている値は0なので
jibunnotama[0]
と
tekinohikouki[0]
もしくは
jibunnotama[0]
と
tekinohikouki[1]
もしくは
jibunnotama[0]
と
tekinohikouki[2]
もしくは
jibunnotama[0]
と
tekinohikouki[3]
もしくは
jibunnotama[0]
と
tekinohikouki[4]
は
ゲーム画面から消えることになります
が・・・
しかし
tekinohikouki[0].lifeに0が代入されている場合は
すなわち
tekinohikouki[0].life==1
が偽の値0を持つ場合は
すなわち
tekinohikouki[0]が前に発射された自分の弾に当たったなどしてゲーム画面に表示されていない場合は
すなわち
🍊敵機tekinohikouki[0]がゲーム画面から消滅してしまっている場合は🍊
jibunnotama[0]とtekinohikouki[0]
jibunnotama[0]とtekinohikouki[1]
jibunnotama[0]とtekinohikouki[2]
jibunnotama[0]とtekinohikouki[3]
jibunnotama[0]とtekinohikouki[4]
がぶつかったとしても
何も実行されない
すなわち
jibunnotama[0].life = 0;
tekinohikouki[0].life = 0;
jibunnotama[0].life = 0;
tekinohikouki[1].life = 0;
jibunnotama[0].life = 0;
tekinohikouki[2].life = 0;
jibunnotama[0].life = 0;
tekinohikouki[3].life = 0;
jibunnotama[0].life = 0;
tekinohikouki[4].life = 0;
が実行されないことになります
つまり
自分の弾を発射して
jibunnotama[0]とtekinohikouki[1]
jibunnotama[0]とtekinohikouki[2]
jibunnotama[0]とtekinohikouki[3]
jibunnotama[0]とtekinohikouki[4]
がぶつかったとしても
tekinohikouki[0]が消滅している場合は
tekinohikouki[0]
と関係のないはずの
tekinohikouki[1]
tekinohikouki[2]
tekinohikouki[3]
tekinohikouki[4]
は
ゲーム画面から消えなくなる
消滅しなくなるんです
敵機が一体だけなら
👇
if(tekinohikouki[0].life==1){
for (int i = 0; i < 1; i = i + 1) {
if ((jibunnotama[0].x < tekinohikouki[i].x + 28) && (tekinohikouki[i].x + 7 < jibunnotama[0].x + 15) && (jibunnotama[0].y < tekinohikouki[i].y + 13) && (
tekinohikouki[i].y + 6 < jibunnotama[0].y + 5)) {
jibunnotama[0].life = 0;
tekinohikouki[i].life = 0;
}
}
}
の記述でもいいのですが
実際のゲームでは敵キャラがたくさん登場してくるので
for (int i = 0; i < 1; i = i + 1) {
if(tekinohikouki[i].life==1){
if ((jibunnotama[0].x < tekinohikouki[i].x + 28) && (tekinohikouki[i].x + 7 < jibunnotama[0].x + 15) && (jibunnotama[0].y < tekinohikouki[i].y + 13) && (
tekinohikouki[i].y + 6 < jibunnotama[0].y + 5)) {
jibunnotama[0].life = 0;
tekinohikouki[i].life = 0;
}
}
}
のように
for{}文の中に
if(tekinohikouki[i].life==1)が記述されているタイプの記述のほうがいいわけなんだね😊」
solarplexuss「にゃるほどね😸」
ソーラー「
それでは
👇
for (int i = 0; i < 1; i = i + 1) {
if ((jibunnotama[0].x < tekinohikouki[i].x + 28) && (tekinohikouki[i].x + 7 < jibunnotama[0].x + 15) && (jibunnotama[0].y < tekinohikouki[i].y + 13) && (
tekinohikouki[i].y + 6 < jibunnotama[0].y + 5)) {
jibunnotama[0].life = 0;
tekinohikouki[i].life = 0;
}
}
👆
の部分を
for (int i = 0; i < 1; i = i + 1) {
if(tekinohikouki[i].life==1){
if ((jibunnotama[0].x < tekinohikouki[i].x + 28) && (tekinohikouki[i].x + 7 < jibunnotama[0].x + 15) && (jibunnotama[0].y < tekinohikouki[i].y + 13) && (
tekinohikouki[i].y + 6 < jibunnotama[0].y + 5)) {
jibunnotama[0].life = 0;
tekinohikouki[i].life = 0;
}
}
}
に変更したプログラムを実行してみましょう
そのプログラムはこちらです
👇
#include "DxLib.h"
struct Character {
int x;
int y;
int graphichandle;
int life;
};
//👆🌞Characterの構造体宣言です
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
ChangeWindowMode(TRUE); // ウインドウモードに設定します
if (DxLib_Init() == -1) // DXライブラリを初期化処理しています
{
return -1; // DXライブラリの初期化に失敗したら直ちにプログラムを終了します
}
SetDrawScreen(DX_SCREEN_BACK);//👈🌞SetDrawScreen関数です 裏画面に画像を描きます
struct Character jibunnohikouki;
//👆🌞jibunnohikoukiの構造体変数宣言です
jibunnohikouki.x = 0;
jibunnohikouki.y = 0;
jibunnohikouki.graphichandle = LoadGraph("画像データ\\ソーラーが描いた飛行機.bmp");
jibunnohikouki.life = 1;//👈🌞🌞🌞ここがポイントです🌞🌞🌞
//👆🌞構造体変数jibunnohikoukiのメンバ変数の初期化を行っています
//👆😋自分の飛行機😋のデータをとりあつかっています
struct Character tekinohikouki[1];
//👆🌞敵の飛行機を1体登場させるために要素数を1にして構造体変数tekinohikouki[0]を1つ作成します
tekinohikouki[0].x = 600;
tekinohikouki[0].y = 100;
tekinohikouki[0].graphichandle = LoadGraph("画像データ\\敵の飛行機.bmp");
//👆メモリに取り込まれた😋敵の飛行機のデータ😋に割り当てられた番号が tekinohikouki[0].graphichandle に代入されています
tekinohikouki[0].life = 1; //👈🌞🌞🌞ここがポイントです🌞🌞🌞
//👆🌞構造体変数tekinohikouki[0]のメンバ変数の初期化を行っています
//👆😋敵の飛行機😋のデータをとりあつかっています
struct Character jibunnotama[1];
//🌞👆自分の弾を1つ作成しています
for (int i = 0; i < 1; i = i + 1) {
jibunnotama[i].x = 0;
jibunnotama[i].y = 0;
jibunnotama[i].graphichandle = LoadGraph("画像データ\\自分の弾.bmp");
jibunnotama[i].life = 0;
}
int tsix;//🌞🌞🌞tsixには発射される弾の最初の位置のx座標が代入されることになります tは弾、sは最初、iは位置、xはx座標を表しています
int count = 0;//🌞🌞🌞ここでint型の変数countを作製し0で初期化しました
while (CheckHitKey(KEY_INPUT_ESCAPE) == 0 && ProcessMessage() == 0) {
DrawBox(100, 100, 500, 300, GetColor(0, 255, 255), TRUE);
int key = GetJoypadInputState(DX_INPUT_KEY_PAD1);
if (key & PAD_INPUT_UP) jibunnohikouki.y = jibunnohikouki.y - 4;
if (key & PAD_INPUT_DOWN) jibunnohikouki.y = jibunnohikouki.y + 4;
if (key & PAD_INPUT_LEFT) jibunnohikouki.x = jibunnohikouki.x - 4;
if (key & PAD_INPUT_RIGHT) jibunnohikouki.x = jibunnohikouki.x + 4;
if (jibunnohikouki.life == 1) {
DrawGraph(jibunnohikouki.x, jibunnohikouki.y, jibunnohikouki.graphichandle, TRUE);
}
//👆 jibunnohikouki.lifeに格納されている値が1なら自分の飛行機の画像を描きます
//👆jibunnohikouki.lifeに格納されている値が0なら自分の飛行機の画像が描かれることはありません
for (int i = 0; i < 1; i++) {
if (tekinohikouki[i].life == 1) {
DrawGraph(tekinohikouki[i].x, tekinohikouki[i].y, tekinohikouki[i].graphichandle, TRUE);
}
}
//👆 tekinohikouki[0].lifeに格納されている値が1なら敵の飛行機の画像を描きます
//👆 tekinohikouki[0].lifeに格納されている値が0なら敵の飛行機の画像が描かれることはありません
for (int i = 0; i < 1; i++)
if ((jibunnohikouki.x + 7 < tekinohikouki[i].x + 28) && (tekinohikouki[i].x + 7 < jibunnohikouki.x + 27) && (jibunnohikouki.y + 7 < tekinohikouki[i].y + 13) && (tekinohikouki[i].y + 6 < jibunnohikouki.y + 13)) {
jibunnohikouki.life = 0;
tekinohikouki[i].life = 0;
}
//👆自機と敵機が重なった条件を満たせばjibunnohikouki.lifeとtekinohikouki[0].lifeには0が代入されることになります
for (int i = 0; i < 1; i = i + 1) {
if (tekinohikouki[i].life == 1) {
if ((jibunnotama[0].x < tekinohikouki[i].x + 28) && (tekinohikouki[i].x + 7 < jibunnotama[0].x + 15) && (jibunnotama[0].y < tekinohikouki[i].y + 13) && (
tekinohikouki[i].y + 6 < jibunnotama[0].y + 5)) {
jibunnotama[0].life = 0;
tekinohikouki[i].life = 0;
}
}
}
//👆自分の弾と敵機が重なった条件を満たせばjibunnotama[0].lifeとtekinohikouki[0].lifeには0が代入されることになります
//👆この部分は以下のように書き換えることができます
/*
for (int j = 0; j < 1; j = j + 1) {
for (int i = 0; i < 1; i = i + 1) {
if (tekinohikouki[i].life == 1) {
if ((jibunnotama[j].x < tekinohikouki[i].x + 28) && (tekinohikouki[i].x + 7 < jibunnotama[j].x + 15) && (jibunnotama[j].y < tekinohikouki[i].y + 13) && (
tekinohikouki[i].y + 6 < jibunnotama[j].y + 5)) {
jibunnotama[j].life = 0;
tekinohikouki[i].life = 0;
}
}
}
}
なぜこのように記述するのかの解説は後ほど🥰
*/
if ((key & PAD_INPUT_A) && (count == 0)) {
for (int i = 0; i < 1; i = i + 1) {
if (jibunnotama[i].life == 0) {
jibunnotama[i].x = jibunnohikouki.x + 35;
tsix = jibunnotama[i].x;
jibunnotama[i].y = jibunnohikouki.y + 20;
jibunnotama[i].life = 1;
break;
}
}
count = 10;
}
if (count > 0) { count = count - 1; }
for (int i = 0; i < 1; i = i + 1) {
if (jibunnotama[i].life == 1) {
//🌞🌞🌞 jibunnotama[i].lifeに1が代入されていると自分の弾がゲーム画面に表示されることになります jibunnotama[i].lifeに0が代入されていると自分の弾がゲーム画面に表示されることはありません
DrawGraph(jibunnotama[i].x, jibunnotama[i].y, jibunnotama[i].graphichandle, TRUE);
jibunnotama[i].x = jibunnotama[i].x + 10;
if (jibunnotama[i].x - tsix > 640)
//🌞🌞🌞発射された弾の位置のx座標が発射されたときの最初の弾の位置のx座標から640を超えて離れると条件式jibunnotama[i].x - tsix > 640は真の値1をとることになります
//🌞🌞🌞🌞🌞👆 tsixにはZボタンが押されたときの自分の弾のいる位置のx座標を記憶していたのでjibunnotama[i].xがZボタンが押されたときの自分の弾のいる位置から640ドット離れた時jibunnotama[i].x -tsix> 640は真の値1を持つことになります
jibunnotama[i].life = 0;
}
}
ScreenFlip();
ClearDrawScreen();
};
DxLib_End(); // DXライブラリの使用を終了します DXライブラリの使用しているメモリ領域が解放されます
return 0; // プログラムを終了します
}
solarplexuss「いやっほう~
敵機が自分の弾に当たってゲーム画面から消えた後
敵機のいた場所に自分の弾をうちこんでも
自分の弾が消える事はなくなった
やったね!
それにしてもよく改良できたね
ねえ ねえ うちらも大分進歩してんじゃない😊」
ソーラー「そうだね いい感じだね」
新規登録で充実の読書を
- マイページ
- 読書の状況から作品を自動で分類して簡単に管理できる
- 小説の未読話数がひと目でわかり前回の続きから読める
- フォローしたユーザーの活動を追える
- 通知
- 小説の更新や作者の新作の情報を受け取れる
- 閲覧履歴
- 以前読んだ小説が一覧で見つけやすい
アカウントをお持ちの方はログイン
ビューワー設定
文字サイズ
背景色
フォント
組み方向
機能をオンにすると、画面の下部をタップする度に自動的にスクロールして読み進められます。
応援すると応援コメントも書けます