質問なんですが・・・

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
リク

質問なんですが・・・

#1

投稿記事 by リク » 18年前

インベーダーゲームをつくりたいのですが、
敵の動きのプログラムが分からないです。
教えていただけませんか?

tk-xleader

Re:質問なんですが・・・

#2

投稿記事 by tk-xleader » 18年前

>リクさん

とりあえず、ある画像をウィンドウ内で下に動かすようなプログラムは組めますか?

敵の動きというのは、アニメーションの考え方になります。そこで、画像の描画位置を少しずつ動かしていく事で表現できます。
ということは、座標を少しずつ変化させていく事で、画像を動かせます。

リク

Re:質問なんですが・・・

#3

投稿記事 by リク » 18年前

回答ありがとうございます。

画像を右なら右、左なら左みたいに
一方通行ならプログラムはできるんですが、

インベーダーゲームみたいに
→→→→→↓
↓←←←←←

みたいなプログラムができないのです。

管理人

Re:質問なんですが・・・

#4

投稿記事 by 管理人 » 18年前

まずゲームだと思わずにコンソール画面で処理出来るかどうか試してみてください。

int x,y;

の変数を用意し、増減フラグ

int flag;

を用意して、座標(x,y)を考えます。

(0,0)→(1,0)→(2,0)→(3,0)
                           ↓
       (1,1)←(2,1)←(3,1)←(4,1)
   ↓
(0,2)→(1,2)→(2,2)→(3,2)

このような動きをさせたいなら最初増減フラグはオンにしておきます。
増減フラグがオンの時はx座標が増加します。4まで来たら増減フラグはオフにします。
増減フラグが入れ替わる時、yが1増加します。
オフにしている最中はxは減少します。0まで来ると増減フラグはオンになります。

これを実装すればいいのではないでしょうか?
上記のような座標がコンソールで出せるかやってみてください。

管理人

Re:質問なんですが・・・

#5

投稿記事 by 管理人 » 18年前

もし言っている意味がわからなければ以下のサンプルを参考にしてください。

アルゴリズムは上のものをそのまま実装しただけです。
#include <stdio.h>

int main(){
	int x=0,y=0,flag=1;
	while(y<5){
		printf("(%d,%d)\n",x,y);
		x += flag;        //x座標を増減
		if(x>=4 || x<=0){ //範囲の外まで来たら
			flag*=-1;//フラグを入れ替える
			y++;     //y座標増加
		}
	}
	return 0;
}
 

管理人

Re:質問なんですが・・・

#6

投稿記事 by 管理人 » 18年前

DXライブラリをお使いでしたら以下のサンプルもどうぞ。
#include "DxLib.h"

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
  int x=0,y=0,flag=1;
  char Key[256];
  if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //初期化処理
  SetDrawScreen( DX_SCREEN_BACK );        //裏画面に設定

  while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){
         //↑メッセージ処理       ↑画面をクリア          ↑キーボード入力状態取得       ↑ESCが押されていない
		DrawBox(x*30,y*30,(x+1)*30,(y+1)*30,GetColor(255,255,255),TRUE);//四角形描画	
		x += flag;
		if(x>=10 || x<=0){
			flag*=-1;
			y++;
		}
		if(y>10)break;
		ScreenFlip();  //裏画面反映
		WaitTimer(100);//0.1秒待つ
  }
  DxLib_End();
  return 0;
}
 

リク

Re:質問なんですが・・・

#7

投稿記事 by リク » 18年前

回答ありがとうございます。
DXライブラリをつかっているので、下のプログラムを実行してみました。
思っているような動きをしたのはしたのですが、
さきほど管理人さんがおっしゃられたものなのですが、
(0,0)→(1,0)→(2,0)→(3,0)
                           ↓
       (1,1)←(2,1)←(3,1)←(4,1)
   ↓
(0,2)→(1,2)→(2,2)→(3,2)

これを下のようにできませんか?

(0,0)→(1,0)→(2,0)→(3,0)→(4,0)
                             ↓
(0,1)→(1,1)←(2,1)←(3,1)←(4,1)
  ↓
(0,2)→(1,2)→(2,2)→(3,2)→(4,2)
 

リク

Re:質問なんですが・・・

#8

投稿記事 by リク » 18年前

空白をいれたつもりが変な風になってしまいました。

僕が変えたところは、

上の↓は(4,0)の下です。

tk-xleader

Re:質問なんですが・・・

#9

投稿記事 by tk-xleader » 18年前

Dxライブラリ使用だとしたら、画面の座標は左上を(0,0)として、右に行くほどx座標がが増加し、下に行くほどy座標が増加します。
つまり、int型変数で上下左右の動きを制御する変数を用意し、その変数の値によって、座標を動かすという考え方になります。
とりあえず、サンプルプログラムを作ってみましたのでlzhで添付します。

リク

Re:質問なんですが・・・

#10

投稿記事 by リク » 18年前

回答ありがとうございます。

今から実行してみます。

リク

Re:質問なんですが・・・

#11

投稿記事 by リク » 18年前

さきほどのサンプルの意味はわかったのですが、
キーボードで動かすのではなく、勝手に動くようにするには、
どこをかえればいいですか?

リク

Re:質問なんですが・・・

#12

投稿記事 by リク » 18年前

管理人さんのとtkmakwins15のを両方を合体させて自分なりにプログラムを書いてみました。
こんな感じでいいでしょうか?


#include"DxLib.h"

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
int x=0,y=0;//座標の変数
int x_flag=0,y_flag=0;//上下左右に動いているかのフラグ。
int grhandle; //グラフィックハンドル。
int flg = 3;

if(ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init()==-1) return -1;
SetDrawScreen(DX_SCREEN_BACK);

grhandle=LoadGraph("shikaku.bmp");

while(ProcessMessage()!=-1){

DrawGraph(x,y,grhandle,FALSE);

ScreenFlip();
ClearDrawScreen();

x += flg;

if(x==0 || x==300){
flg *= -1;
y += 5;
}
}

DxLib_End();
return 0;
}

tk-xleader

Re:質問なんですが・・・

#13

投稿記事 by tk-xleader » 18年前

方向を勝手に変えるには、乱数を使うとよいでしょう。
#include"DxLib.h"

int WINAPI WinMain(HINSTANCE hInstance,
		   HINSTANCE hPrevInstance,
		   LPSTR lpCmdLine,
		   int nCmdShow)
{
	int x=320-16,y=240-16;//座標の変数
	int x_flag=0,y_flag=0;//上下左右に動いているかのフラグ。
	int grhandle;         //グラフィックハンドル。
	int begin;            //最初の基準秒数を記録する変数。
	
	ChangeWindowMode(TRUE);
	SetMainWindowText("sample");
	SetOutApplicationLogValidFlag(FALSE);
	if(DxLib_Init()==-1)return -1;
	SetDrawScreen(DX_SCREEN_BACK);
	
	grhandle=LoadGraph("shikaku.bmp");
	
	begin=GetNowCount();
	while(ProcessMessage()!=-1){
		
		DrawGraph(x,y,grhandle,FALSE);
		
		DrawFormatString(0,0,GetColor(255,255,255),"(%d,%d)",x,y);
		
		ScreenFlip();
		ClearDrawScreen();
		
		if(CheckHitKey(KEY_INPUT_ESCAPE))break;//エスケープキーが押されたら終了。
		
		//動いてから1秒経ったら動く方向を乱数で取得。
		if(GetNowCount()-begin>1000){
			x_flag=GetRand(2)-1;
			y_flag=GetRand(2)-1;
			begin=GetNowCount();
		}
		//x_flagは上に動くなら-1、変化なしなら0、下へ動くなら1を指し示す。
		x += x_flag*2;
		//y_flagも右なら-1、動かないなら0、左なら1を指す。
		y += y_flag*2;
		if(x<0)x=0;       //X座標が0より下ならば、見えないので強制的に0にする。
		if(x>640-32)x=640-32;//X座標が640-32より上ならば、同じ理由で640-32にする。
		//Y座標も同じように修正する。
		if(y<0)y=0;
		if(y>480-32)y=480-32;
		
	}
	DxLib_End();
	return 0;
}

//基本的な部分の説明は省略させていただきました。
これはサンプルプログラムです、さっきのソースコードをこれに置き換えて、コンパイルしなおすと、さっきとは動きが変わります。
考え方は、X座標が右に変化する時は-、左に動く時は+、動かなければ0とすると、それに1フレームで動かしたいドット数をかけると、その方向に変化するということです。

管理人

Re:質問なんですが・・・

#14

投稿記事 by 管理人 » 18年前

それなら方向を決める変数を用意して、if文で制御してもいいのではないでしょうか?

方向を示す

int dir=0;

を用意します。

dir=0 は右方向に進む
dir=1 は下方向に進む
dir=2 は左方向に進む
dir=3 は下方向に進む

これを繰り返したらいいですよね?これを繰り返すには

dir = (dir+1)%4;

でOKです。
この変数に格納されている指示通り動かせばいいでしょう。
#include "DxLib.h"

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
  int x=1,y=0,dir=0;
  char Key[256];
  if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //初期化処理
  SetDrawScreen( DX_SCREEN_BACK );        //裏画面に設定

  while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){
         //↑メッセージ処理       ↑画面をクリア          ↑キーボード入力状態取得       ↑ESCが押されていない
	
	    DrawBox(x*30,y*30,(x+1)*30,(y+1)*30,GetColor(255,255,255),TRUE);

		if(x>=10 || x<=0)//外側まで来たら
			dir = (dir+1)%4;//方向転換

		if     (dir==0)//右方向なら
			x++;//右へ
		else if(dir==1 || dir==3)//下方向なら
			y++;//下へ
		else if(dir==2)//左方向なら
			x--;//左へ

		if(y>10)break;
		ScreenFlip();
		WaitTimer(100);
  }
  DxLib_End();
  return 0;
}

管理人

Re:質問なんですが・・・

#15

投稿記事 by 管理人 » 18年前

ifを並べるのがいやならこんな風にスマートにも出来ます。
黄色の部分が変更点です。

#include "DxLib.h"

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
  int x=1,y=0,dir=0;
  int dx[4]={1,0,-1,0},dy[4]={0,1,0,1};  char Key[256];
  if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //初期化処理
  SetDrawScreen( DX_SCREEN_BACK );        //裏画面に設定

  while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){
         //↑メッセージ処理       ↑画面をクリア          ↑キーボード入力状態取得       ↑ESCが押されていない
	
	    DrawBox(x*30,y*30,(x+1)*30,(y+1)*30,GetColor(255,255,255),TRUE);


		if(x>=10 || x<=0)//外側まで来たら
			dir = (dir+1)%4;//方向転換
		
		x+=dx[di[/url];	y+=dy[di[/url];

		if(y>10)break;
		ScreenFlip();
		WaitTimer(100);
  }
  DxLib_End();
  return 0;
}

リク

Re:質問なんですが・・・

#16

投稿記事 by リク » 18年前

回答ありがとうございます。
プログラムはとても分かりやすかったです。

続けて質問したいのですが、
縦に3匹、横4匹、計12匹いるようなものを
全部まとめてさきほどと同じように動かすにはどうすればいいですか?

管理人

Re:質問なんですが・・・

#17

投稿記事 by 管理人 » 18年前

全部聞いてしまったらプログラムを作る楽しみが減りませんか??
リクさんがよいのでしたらサンプル作りますが、一応基礎があるので、はってんさせてみてはいかがでしょうか?
上記サンプルを応用するとすれば、12匹のどれかが端にさしかかったら方向転換すればいいんですよね。
xy座標は12匹全部違うはずですが、端にくる敵はかわらないはずですから、その敵を判定材料にすればよいでしょう。

緑が左端、黄色が右端にさしかかったことを判定させればいいでしょう。

□■■■■□□
□■■■■□□
■■□□
□□□□□□□

□□■■■■□
□□■■■■□
□□■■
□□□□□□□

□□□■■■■
□□□■■■■
□□□■■
□□□□□□□

□□□□□□□
□□□■■■■
□□□■■■■
□□□■■

□□□□□□□
□□■■■■□
□□■■■■□
□□■■

□□□□□□□
□■■■■□□
□■■■■□□
■■□□

□□□□□□□
■■■■□□□
■■■■□□□
■■□□□

tk-xleader

Re:質問なんですが・・・

#18

投稿記事 by tk-xleader » 18年前

長方形型なのであれば、その長方形ひとつで考えるという方法もあります。描画は別として、

後、余談ですが、リクさん。ソースコード投稿時はそれらを
ソースコード
のように投稿するときれいに表示されると思います。

リク

Re:質問なんですが・・・

#19

投稿記事 by リク » 18年前

回答ありがとうございます。

勉強のつもりでやっているので、サンプルプログラムを載せていただいてもかまわないです。

一応今、自分で作っているプログラムでは32ピクセルの画像を2つ使って、
動かしているところです。

敵を配列にいれると簡単だと聞いたのですが
配列をつかってするにはどうすればよいですか?

管理人

Re:質問なんですが・・・

#20

投稿記事 by 管理人 » 18年前

一番左上の敵のみ座標を移動させています。
敵の間隔は常に等間隔で、決まったフォーマットなので、一匹敵の座標が決まるだけで全ての
座標が決められる事を利用しました。

プロジェクトファイルに

http://dixq.net/img/img.PNG

を保存して以下のプログラムを実行してください。

なお、ソースコードを投稿する時や、半角空白を使って文字で図を表したい時は
プレタグと言うものを利用してください。

これは<pre>というタグと</pre>というタグで囲む事で文字が等間隔、空白も表示されるようになります。
<>これは半角で入力してください。タグは記事には表示されません。
#include "DxLib.h"

typedef struct{
	int x,y;
}xy_t;

int img;
xy_t xy[3][4];//敵の座標構造体

void set(){//左上の敵の座標[0][0]をもとに、敵の座標を決定
	int i,j;
	for(i=0;i<3;i++){
		for(j=0;j<4;j++){
			xy[j].x=xy[0][0].x+j;
			xy[j].y=xy[0][0].y+i;
		}
	}
}

void graph(){//描画
	int i,j;
//四角形描画
	for(i=0;i<10;i++)
		for(j=0;j<10;j++)
		    DrawBox(j*20,i*20,(j+1)*20,(i+1)*20,GetColor(255,255,255),FALSE);
//敵描画
	for(i=0;i<3;i++)
		for(j=0;j<4;j++)
		    DrawGraph(xy[j].x*20,xy[j].y*20,img,FALSE);
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
  int dir=0,dx[4]={1,0,-1,0},dy[4]={0,1,0,1};
  char Key[256];

  if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //初期化処理
  SetDrawScreen( DX_SCREEN_BACK );        //裏画面に設定

  xy[0][0].x=1;
  xy[0][0].y=0;
  img = LoadGraph("img.PNG");

  while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){
         //↑メッセージ処理       ↑画面をクリア          ↑キーボード入力状態取得       ↑ESCが押されていない
		set();
		graph();

		if(xy[0][0].x<=0 || xy[0][3].x>=9)//外側まで来たら
			dir = (dir+1)%4;//方向転換
		
		xy[0][0].x+=dx[di[/url];	xy[0][0].y+=dy[di[/url];

		if(xy[0][0].y>7)break;
		ScreenFlip();
		WaitTimer(500);
  }
  DxLib_End();
  return 0;
}
 

リク

Re:質問なんですが・・・

#21

投稿記事 by リク » 18年前

回答ありがとうございます。

ご返事送れてすいません。

自機は自分でがんばりたいと思います。
でも当たり判定は悩みそうなので
分からなかったら、また質問させてください。

リク

Re:質問なんですが・・・

#22

投稿記事 by リク » 18年前

敵を32ピクセル×2個をつかって
動いてるように見せながら、移動させるには
どうすればいいですか?

リク

Re:質問なんですが・・・

#23

投稿記事 by リク » 18年前

一つ前の質問は解決しました。すいません。

当たり判定もできたのですが、
敵にあたって存在フラグを0にして、
敵を画面から消すことまでできたのですが、
その画面から消した敵のところに
弾を打つとそこで弾が消えてしまいます。

画面から消えても敵がいるみたいな感じになっています。

どうやって直せばいいでしょうか?

バグ

Re:質問なんですが・・・

#24

投稿記事 by バグ » 18年前

存在フラグが0の場合には、当たり判定処理を無視するように書き換えればよいかと思います(^-^)

リク

Re:質問なんですが・・・

#25

投稿記事 by リク » 18年前

回答ありがとうございます。

さっそくやってみます。

リク

Re:質問なんですが・・・

#26

投稿記事 by リク » 18年前

質問なんですが、
インベーダーの敵がランダムに1発ずつ攻撃してくる
方法が分からないです。

教えていただけませんか?

GetRandで乱数を発生させてやったのですが、
処理が早すぎて一瞬だけしか画面に表示されないのです。

たまー

画面の操作にて、

#27

投稿記事 by たまー » 18年前

連続の投稿になりすいません。
アプリ制作にて最初の画面でこのアプリ起動させるかの選択で、
「はい」「いいえ」以外に、もうこの画面を表示しないといったものを
作りたいのですが、どうやった書き方をすればよろしいでしょうか?
分かる方いましたらよろしくお願いします。

tk-xleader

Re:画面の操作にて、

#28

投稿記事 by tk-xleader » 18年前

メッセージボックスの中にはそのような機能はないです。
なので、ダイアログボックスを作ることになります。

たまー

Re:画面の操作にて、

#29

投稿記事 by たまー » 18年前

ダイアログボックスというのは分かってるのですが、
それで、一度決定するともう表示しなくなるようにするには
どうすればいいかと思い書きました。その場合だと、
アプリを落とした時、「もう表示しない」を選択しておくと
アプリ終了後もどこかにそのデータを残しとかなければいけないし、
立ちあげたときにはダイアログBOXより先にそっちを見に行って、
チェックの確認と、このようになると思うのですがその
やり方をしりたかったのです^^
よろしくお願いします。

GPGA

Re:画面の操作にて、

#30

投稿記事 by GPGA » 18年前

普通にセーブファイルを作ってフラグを書き込めばいいと思います。
以下サンプル。
#include <windows.h>
#include <stdio.h>

const char* szFileName = "conf.dat";

int CheckConf()
{
    FILE* fp = NULL;
    char ret = 0;

    fp = fopen(szFileName, "rb");
    if (fp != NULL) {
        fread(&ret, 1, sizeof(char), fp);
        fclose(fp);
    }
    return ret;
}

void SaveConf()
{
    FILE* fp = NULL;
    fp = fopen(szFileName, "wb");
    if (fp != NULL) {
        char flg = 1;
        fwrite(&flg, 1, sizeof(char), fp);
        fclose(fp);
    }
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    if (CheckConf() == 0) {
        int ret = MessageBox(NULL, "はい:通常起動\nいいえ:アプリ終了\nキャンセル:以降このメッセージボックスを表示しないに該当", "テスト", MB_YESNOCANCEL);
        if (ret == IDNO) {
            // いいえ
            return 0;
        } else if (ret == IDCANCEL) {
            // キャンセル(以降表示しないに該当)
            SaveConf();
        }
    }

    // 通常のアプリプログラム
    MessageBox(NULL, "通常のアプリ", "", MB_OK);
    return 0;
}
 

たまー

Re:画面の操作にて、

#31

投稿記事 by たまー » 18年前

回答ありがとうございます^^
GPGAさんのかかれたものを参考にさせていただきます^^
まだできていませんが、解決できそうなので助かりました~
ありがとうございます。

閉鎖

“C言語何でも質問掲示板” へ戻る