9マス上のマスを動く敵キャラを作るために時間の関数がほしいです。

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Ouxiy
記事: 165
登録日時: 3ヶ月前

9マス上のマスを動く敵キャラを作るために時間の関数がほしいです。

#1

投稿記事 by Ouxiy » 2ヶ月前

過去に「画像のように3D っぽい2Dの9マスA~I上をキャラにキー入力で移動させたい」というプログラムにおいて、質問したものです。
あれから

コード:

#include "DxLib.h"

int Key[256];

int gpUpdateKey()
{
	char tmpKey[256];
	GetHitKeyStateAll(tmpKey);
	for (int i = 0; i < 256; i++)
		(tmpKey[i] == 0) ? (Key[i] = 0) : Key[i]++;
	return 0;
}

int idou[5][5] = {
	{ 1, 1, 1, 1, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 1, 1, 1, 1 },
};

int box[4][7][2], player[5][5][2];

void init_box()
{
	for (int j = 0; j < 7; j++) {
		int w = (j - 3) * 100, h = 600;
		for (int i = 4; --i >= 0; ) {
			box[i][j][0] = w + 400, box[i][j][1] = h - 200;
			w = w * 9 / 10, h = h * 9 / 10;
		}
	}
	for (int i = 1; i <= 3; i++)
		for (int j = 1; j <= 3; j++) {
			player[i][j][0] = (box[i - 1][j - 1][0] + box[i][j][0]) / 2 - 25;
			player[i][j][1] = (box[i - 1][j - 1][1] + box[i][j][1]) / 2 - 66;
		}
}

int WINAPI WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR cl, int cs)
{
	SetGraphMode(780, 680, 32);        // ウィンドウの大きさを指定
	ChangeWindowMode(TRUE);             // 全画面ではなくウインドウを使用
	if (DxLib_Init() == -1) return -1;  // DXライブラリ初期化処理
	SetDrawScreen(DX_SCREEN_BACK);      // 裏画面を使用する設定

	init_box();
	int boxColor = GetColor(160, 64, 64);

	int nx = 2, ny = 2;  // プレイヤーの初期位置
	int px = player[ny][nx][0], py = player[ny][nx][1];  // 表示位置
	int keep = 0;  // 移動不可能状態継続カウンタ

	int gh[12];  //グラフィックハンドル格納用配列
			// 5:正面、7:右向き、2:左向き、4:上向き、3:下向き、9:移動不可
	LoadDivGraph("charall.png", 12, 3, 4, 49, 66, gh);  //画像読み込み
	int playerphoto = gh[5];

	while (ProcessMessage() == 0) {
		gpUpdateKey();  // キーの入力状態を取得
		if (Key[KEY_INPUT_RIGHT] == 1) {  // 右キーが押されている
			if (idou[nx + 1][ny] == 0) {  // 移動先が空いていれば
				nx++; playerphoto = gh[7];  // 右向き
			}
			else {
				keep = 1; playerphoto = gh[9];  // 移動不可能
			}
		}
		if (Key[KEY_INPUT_LEFT] == 1) {
			if (idou[nx - 1][ny] == 0) {  // 移動先が空いていれば
				nx--; playerphoto = gh[2];  // 左向き
			}
			else {
				keep = 1; playerphoto = gh[9];  // 移動不可能
			}
		}
		if (Key[KEY_INPUT_UP] == 1) {
			if (idou[nx][ny - 1] == 0) {  // 移動先が空いていれば
				ny--; playerphoto = gh[4];  // 上向き
			}
			else {
				keep = 1; playerphoto = gh[9];  // 移動不可能
			}
		}
		if (Key[KEY_INPUT_DOWN] == 1) {
			if (idou[nx][ny + 1] == 0) {  // 移動先が空いていれば
				ny++; playerphoto = gh[3];  // 下向き
			}
			else {
				keep = 1; playerphoto = gh[9];  // 移動不可能
			}
		}

		ClearDrawScreen();  // 裏画面をクリア

		for (int i = 0; i < 4; i++)
			DrawLine(box[i][0][0], box[i][0][1],
				box[i][6][0], box[i][6][1], boxColor);
		for (int j = 0; j < 7; j++)
			DrawLine(box[0][j][0], box[0][j][1],
				box[3][j][0], box[3][j][1], boxColor);

		int x = player[ny][nx][0], y = player[ny][nx][1];  // 表示位置に変換
		if (x == px && y == py) {
			if (keep == 0 || ++keep == 10) {
				keep = 0; playerphoto = gh[5];
			}
		}
		else {
			if (abs(x - px) < 8) px = x;
			else if (x > px) px += 8;
			else if (x < px) px -= 8;
			if (abs(y - py) < 6) py = y;
			else if (y > py) py += 6;
			else if (y < py) py -= 6;
		}
		DrawGraph(px, py, playerphoto, FALSE);  // プレイヤーを裏画面に描画
		ScreenFlip();  // 裏画面を表画面に反映
	}

	DxLib_End();  // DXライブラリ使用の終了処理
	return 0;  // ソフトの終了 
}
以上のプログラムを使わせて頂いているのですが、敵を登場させるために、敵のプログラムも必要になりました。そこで以下のプログラムでランダム関数と時間の関数を使い、9マス上を毎秒1s事に敵キャラを9マス上のいずれかのパネルに移動させ、たまに数秒間その場に止まるようなプログラムを作ろうとしました。
ですが、時間に関する関数が見つからず困っています。
ランダム関数は見つかったので、なんとかプログラムを作ろうとしているのですが、毎1sごとにランダムに変数の中身を変えて、9マス上をランダムに動く敵キャラのを実現させたいです。

以下はランダム関数と敵キャラcharall.pngを表したプログラムです。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "DxLib.h"

int idou[5][5] = {//敵の動く範囲
	{ 1, 1, 1, 1, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 1, 1, 1, 1 },
};

int teki[5][5][2] = {
		{{0}}, // どうせここには来ない
		{{0, 0}, {60,  60}, {100,  60}, {140,  60}, {0, 0}},//敵の配列の範囲に座標を加えて、この上の配列内のこの座標上を動くようにする。
		{{0, 0}, {50, 100}, {100, 100}, {150, 100}, {0, 0}},
		{{0, 0}, {40, 160}, {100, 160}, {160, 160}, {0, 0}},
		{{0}} // どうせここには来ない
};

int WINAPI WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR cl, int cs)
{
	SetGraphMode(780, 680, 32);        // ウィンドウの大きさを指定
	ChangeWindowMode(TRUE);             // 全画面ではなくウインドウを使用
	if (DxLib_Init() == -1) return -1;  // DXライブラリ初期化処理
	SetDrawScreen(DX_SCREEN_BACK);      // 裏画面を使用する設定

	
	//int boxColor = GetColor(160, 64, 64);//ステージの色
	int nx = 2, ny = 2;  // 敵の初期位置
	int px = teki[ny][nx][0], py = teki[ny][nx][1];  // 表示位置
	int gh[12];  //グラフィックハンドル格納用配列
			// 5:正面、7:右向き、2:左向き、4:上向き、3:下向き、9:移動不可
	LoadDivGraph("charall.png", 12, 3, 4, 49, 66, gh);  //画像読み込み
	int playerphoto = gh[5];

	while (ProcessMessage() == 0) {
		ClearDrawScreen();  // 裏画面をクリア
		DrawGraph(teki[ny][nx][0], teki[ny][nx][1], playerphoto, FALSE);
		ScreenFlip();  // 裏画面を表画面に反映

	}


	int s;

	/* 乱数の種を初期化 */
	srand(time(NULL));

	/* 1 〜 9 のランダムな数値 */
	s = rand() % 9 + 1;

	/* 出力 */
	printf("%d\n", s);

	DxLib_End();  // DXライブラリ使用の終了処理
	return 0;  // ソフトの終了 
	
}

Ouxiy
記事: 165
登録日時: 3ヶ月前

Re: 9マス上のマスを動く敵キャラを作るために時間の関数がほしいです。

#2

投稿記事 by Ouxiy » 2ヶ月前

環境は
  • Windows10
  • visual studio2019
  • DXライブラリ
です

アバター
みけCAT
記事: 6235
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: 9マス上のマスを動く敵キャラを作るために時間の関数がほしいです。

#3

投稿記事 by みけCAT » 2ヶ月前

DXライブラリ置き場 リファレンスページには「時間関係の関数」という見出しがあり、
の3関数が挙げられています。

また、C言語の標準ライブラリにも時間を取り扱う関数群があり、
Ouxiyさんも使われているtime関数をはじめとして様々な関数があります。

さらに、Windows APIにも、GetLocalTime関数GetTickCount関数などの時間や時刻を扱う関数があります。

Ouxiyさんのいう「時間に関する関数」とは、どのような関数のことですか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Ouxiy
記事: 165
登録日時: 3ヶ月前

Re: 9マス上のマスを動く敵キャラを作るために時間の関数がほしいです。

#4

投稿記事 by Ouxiy » 2ヶ月前

どうもありがとうございます。
えーと、そうですね。カウントとしてGetNowCountがいいように思えましたが、ただ、毎秒ずっと動いているわけにもいかないので少し動いたら、止まったり、また動いたりを繰り返せばいいと考えています。
そのようにコードを書くにはどうしたらいいでしょうか。time関数を使わない方向になってしまうかもしれませんが、どうかよろしくお願いいたします。

Ouxiy
記事: 165
登録日時: 3ヶ月前

Re: 9マス上のマスを動く敵キャラを作るために時間の関数がほしいです。

#5

投稿記事 by Ouxiy » 2ヶ月前

あの後、考えて変数moveを使い、(move > 0 && ++move == 30)の++moveで変数の値を変えていき、マス目上を自動で移動する方法を取りました。
ですがなかなかプログラムに出来ずにいます。
// カーソルキーの右が押されている
if (Key[KEY_INPUT_RIGHT] == 1)
if (idou[ny + 0][move + 1] == 0) {//移動しようとする先が空いていれば
//移動可能
move = 1;
move = move + 1; //移動
playerphoto = gh[6];
}
として見たのですが、うまくいきません。

以下は全体のコードです。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "DxLib.h"

int Key[256];

int gpUpdateKey()
{
	char tmpKey[256];
	GetHitKeyStateAll(tmpKey);
	for (int i = 0; i < 256; i++)
		(tmpKey[i] == 0) ? (Key[i] = 0) : Key[i]++;//キーのフレームの習得
	return 0;
}
int idou[5][5] = {
	{ 1, 1, 1, 1, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 1, 1, 1, 1 },
};
int box[4][7][2], teki[5][5][2];

void init_box()
{
	for (int j = 0; j < 7; j++) {
		int w = (j - 3) * 100, h = 600;
		for (int i = 4; --i >= 0; ) {
			box[i][j][0] = w + 400, box[i][j][1] = h - 200;
			w = w * 9 / 10, h = h * 9 / 10;
		}
	}
	for (int i = 1; i <= 3; i++)
		for (int j = 1; j <= 3; j++) {
			teki[i][j][0] = (box[i - 1][j - 1][0] + box[i][j][0]) / 2 - 25;
			teki[i][j][1] = (box[i - 1][j - 1][1] + box[i][j][1]) / 2 - 66;
		}
}

int WINAPI WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR cl, int cs)
{
	SetGraphMode(780, 680, 32);        // ウィンドウの大きさを指定
	ChangeWindowMode(TRUE);             // 全画面ではなくウインドウを使用
	if (DxLib_Init() == -1) return -1;  // DXライブラリ初期化処理
	SetDrawScreen(DX_SCREEN_BACK);      // 裏画面を使用する設定

	init_box();//これによりint box()を呼び出して初期かしたbox[4][7][2], teki[5][5][2]を呼び出した。
	//int boxColor = GetColor(160, 64, 64);//ステージの色
	int nx = 2, ny = 2;  // tekiのxとyでの初期位置
	int px = teki[ny][nx][0], py = teki[ny][nx][1];  // tekiのx、y、zでの初期位置
	int move = 0;  // 移動状態
	int gh[12];  //グラフィックハンドル格納用配列
			// 5:正面、7:右向き、2:左向き、4:上向き、3:下向き、9:移動不可
	LoadDivGraph("charall.png", 12, 3, 4, 49, 66, gh);  //画像読み込み
	int playerphoto = gh[5];

	while (ProcessMessage() == 0) {

		gpUpdateKey();  // キーの入力状態を取得
		
			// カーソルキーの右が押されている
			if (Key[KEY_INPUT_RIGHT] == 1)
				if (idou[ny + 0][move + 1] == 0) {//移動しようとする先が空いていれば
				//移動可能
					move = 1;
					move = move + 1; //移動
					playerphoto = gh[6];
				}
			if (Key[KEY_INPUT_LEFT] == 1)
				if (idou[ny + 0][move - 1] == 0) { //移動しようとする先が空いていれば
				//移動可能
					move = 1;
					move = move - 1; //移動
					playerphoto = gh[4];
				}
		

		ClearDrawScreen();  // 裏画面をクリア
		if (move > 0 && ++move == 30) {
			move = 0; playerphoto = gh[5];  // 移動終了
		}
		DrawGraph(teki[ny][nx][0], teki[ny][nx][1], playerphoto, FALSE);//tekiの画像が描画される最初の位置
		ScreenFlip();  // 裏画面を表画面に反映

	}
		

	DxLib_End();  // DXライブラリ使用の終了処理
	return 0;  // ソフトの終了 
	
}

アバター
みけCAT
記事: 6235
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: 9マス上のマスを動く敵キャラを作るために時間の関数がほしいです。

#6

投稿記事 by みけCAT » 2ヶ月前

きちんと変数の意味を意識しましょう。

キャラの座標はnxとny。
これらの値を変える処理が無いので、キャラは動きません。

moveは移動の状態(時間)の管理用。
idouの各要素は5しかないのに、最大30になるmove(の±1程度の値)を添字に使ってしまうと、
範囲外へのアクセスが発生して危険です。
Ouxiy さんが書きました:
2ヶ月前
move = 1;
move = move + 1; //移動
というのも意味がよくわかりません。これはどういう「移動」を表しているのでしょうか?
さらに、move = 1; move = move - 1;だと、実質move = 0;であり、条件move > 0を満たせずに移動できなそうです。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6235
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: 9マス上のマスを動く敵キャラを作るために時間の関数がほしいです。

#7

投稿記事 by みけCAT » 2ヶ月前

Ouxiy さんが書きました:
2ヶ月前
ランダム関数と時間の関数を使い、9マス上を毎秒1s事に敵キャラを9マス上のいずれかのパネルに移動させ、たまに数秒間その場に止まるようなプログラム
こんな感じでしょうか?

コード:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "DxLib.h"

int Key[256];

int gpUpdateKey()
{
	char tmpKey[256];
	GetHitKeyStateAll(tmpKey);
	for (int i = 0; i < 256; i++)
		(tmpKey[i] == 0) ? (Key[i] = 0) : Key[i]++;//キーのフレームの習得
	return 0;
}
int idou[5][5] = {
	{ 1, 1, 1, 1, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 1, 1, 1, 1 },
};
int box[4][7][2], teki[5][5][2];

void init_box()
{
	for (int j = 0; j < 7; j++) {
		int w = (j - 3) * 100, h = 600;
		for (int i = 4; --i >= 0; ) {
			box[i][j][0] = w + 400, box[i][j][1] = h - 200;
			w = w * 9 / 10, h = h * 9 / 10;
		}
	}
	for (int i = 1; i <= 3; i++)
		for (int j = 1; j <= 3; j++) {
			teki[i][j][0] = (box[i - 1][j - 1][0] + box[i][j][0]) / 2 - 25;
			teki[i][j][1] = (box[i - 1][j - 1][1] + box[i][j][1]) / 2 - 66;
		}
}

int WINAPI WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR cl, int cs)
{
	SetGraphMode(780, 680, 32);        // ウィンドウの大きさを指定
	ChangeWindowMode(TRUE);             // 全画面ではなくウインドウを使用
	if (DxLib_Init() == -1) return -1;  // DXライブラリ初期化処理
	SetDrawScreen(DX_SCREEN_BACK);      // 裏画面を使用する設定

	init_box();//これによりint box()を呼び出して初期かしたbox[4][7][2], teki[5][5][2]を呼び出した。
	//int boxColor = GetColor(160, 64, 64);//ステージの色
	int nx = 2, ny = 2;  // tekiのxとyでの初期位置
	int px = teki[ny][nx][0], py = teki[ny][nx][1];  // tekiのx、y、zでの初期位置
	int move = 0;  // 移動状態
	int gh[12];  //グラフィックハンドル格納用配列
			// 5:正面、7:右向き、2:左向き、4:上向き、3:下向き、9:移動不可
	LoadDivGraph("charall.png", 12, 3, 4, 49, 66, gh);  //画像読み込み
	int playerphoto = gh[5];

	const int MOVE_INTERVAL = 1000; // 何ミリ秒ごとに移動処理をするか
	int nextMoveTime = GetNowCount() + MOVE_INTERVAL; // 次回移動処理をする時刻
	int stopCount = 0; // 動かないのがあと何回か

	while (ProcessMessage() == 0) {

		gpUpdateKey();  // キーの入力状態を取得

		if (GetNowCount() >= nextMoveTime) { // 指定の時間が経ったら(1sごとに)
			nextMoveTime += MOVE_INTERVAL; // 次に移動処理をする時刻を設定する
			if (stopCount > 0) {
				// 停止中のとき
				stopCount--; // 止まっている残り時間(回数)を減らす
			} else {
				// 普通の状態のとき
				if (GetRand(99) < 10) { // たまに(10%の確率で)
					stopCount = GetRand(4); // 数秒間(1~5秒間)その場に止まる
				} else {
					// 9マス上のいずれかのパネルに移動させる
					int cy = ny, cx = nx;
					do {
						ny = GetRand(2) + 1;
						nx = GetRand(2) + 1;
					} while (nx == cx && ny == cy); // 移動先が今いるパネルなら、移動先を選びなおす
				}
			}
		}

		ClearDrawScreen();  // 裏画面をクリア
		DrawGraph(teki[ny][nx][0], teki[ny][nx][1], playerphoto, FALSE);//tekiの画像が描画される最初の位置
		ScreenFlip();  // 裏画面を表画面に反映

	}
		

	DxLib_End();  // DXライブラリ使用の終了処理
	return 0;  // ソフトの終了 
	
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Ouxiy
記事: 165
登録日時: 3ヶ月前

Re: 9マス上のマスを動く敵キャラを作るために時間の関数がほしいです。

#8

投稿記事 by Ouxiy » 2ヶ月前

どうもありがとうございました。そのような感じになります。
ただ、もう少し行いたいことがあります。
移動した瞬間に向きが切り替わり瞬間移動したようなエフェクトを付けたいです。

そこで私は以下のようにしました。

コード:

ClearDrawScreen();  // 裏画面をクリア
		if (move > 0 && ++move == 20) {
			move = 0; int playerphoto = gh[8];  // 移動終了
		}
をコード全体に付け足して、移動した後の状態はplayerphoto = gh[8]より真正面を向いたのままですが、
再び移動してから新しい座標でほんの一瞬だけ横を向くようにしたいためif (move > 0 && ++move == 20) として、瞬間移動して進んだように見せようとしました。うまく機能していませんが。なぜでしょうか。

コード:

// 9マス上のいずれかのパネルに移動させる
					int cy = ny, cx = nx;
					do {
						move = 1;
						ny = GetRand(2) + 1;
						nx = GetRand(2) + 1;
						
					} while (nx == cx && ny == cy); // 移動先が今いるパネルなら、移動先を選びなおす
				
のようにマスをランダムに動くときにmove = 1;としてmove > 0 && ++move == 20の条件が働くように書いたつもりなのですが。教えてください。お願いいたします。

以下のコードを参考に作りました。

コード:

#include "DxLib.h"

int Key[256];  // キーが押されているフレーム数を格納する配列

int gpUpdateKey() // キーの入力状態を更新する
{
    char tmpKey[256];  // 現在のキーの入力状態を格納する配列
    GetHitKeyStateAll(tmpKey);  // 全てのキーの入力状態を得る
    for (int i = 0; i < 256; i++) {
        if (tmpKey[i] != 0) {  // i番のキーが押されていたら
            Key[i]++;  // 加算
        }
        else {  // 押されていなければ
            Key[i] = 0; // 0にする
        }
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR cl, int cs)
{
    SetGraphMode(1600, 680, 32);        // ウィンドウの大きさを指定
    ChangeWindowMode(TRUE);             // 全画面ではなくウインドウを使用
    if (DxLib_Init() == -1) return -1;  // DXライブラリ初期化処理
    SetDrawScreen(DX_SCREEN_BACK);      // 裏画面を使用する設定

    int idou[5][5] = {
        { 1, 1, 1, 1, 1 },
        { 1, 0, 0, 0, 1 },
        { 1, 0, 0, 0, 1 },
        { 1, 0, 0, 0, 1 },
        { 1, 1, 1, 1, 1 },
    };
    int nx = 2, ny = 2;  // プレイヤーの初期位置
    int move = 0;  // 移動状態

    int gh[12];  //グラフィックハンドル格納用配列
            // 5:正面、7:右向き、2:左向き、4:上向き、3:下向き、9:移動不可
    LoadDivGraph("charall.png", 12, 3, 4, 49, 66, gh);  //画像読み込み
    int playerphoto = gh[5];

    while (ProcessMessage() == 0) {
        gpUpdateKey();  // キーの入力状態を取得
        if (Key[KEY_INPUT_RIGHT] == 1) {  // カーソルキーの右が押されている
            move = 1;
            if (idou[nx + 1][ny] == 0) {  //移動先が空いていれば
                nx = nx + 1; playerphoto = gh[7];  // 右向き
            }
            else {
                playerphoto = gh[9];  // 移動不可能
            }
        }
        if (Key[KEY_INPUT_LEFT] == 1) {
            move = 1;
            if (idou[nx - 1][ny] == 0) {  //移動先が空いていれば
                nx = nx - 1; playerphoto = gh[2];  // 左向き
            }
            else {
                playerphoto = gh[9];  // 移動不可能
            }
        }
        if (Key[KEY_INPUT_UP] == 1) {
            move = 1;
            if (idou[nx][ny - 1] == 0) {  //移動先が空いていれば
                ny = ny - 1; playerphoto = gh[4];  // 上向き
            }
            else {
                playerphoto = gh[9];  // 移動不可能
            }
        }
        if (Key[KEY_INPUT_DOWN] == 1) {
            move = 1;
            if (idou[nx][ny + 1] == 0) {  //移動先が空いていれば
                ny = ny + 1; playerphoto = gh[3];  // 下向き
            }
            else {
                playerphoto = gh[9];  // 移動不可能
            }
        }

        ClearDrawScreen();  // 裏画面をクリア
        if (move > 0 && ++move == 20) {
            move = 0; playerphoto = gh[5];  // 移動終了
        }
        int x = nx * 60 + 100, y = ny * 80 + 100;  // 表示位置に変換
        DrawGraph(x, y, playerphoto, FALSE);  // プレイヤーを裏画面に描画
        ScreenFlip();  // 裏画面を表画面に反映
    }

    DxLib_End();  // DXライブラリ使用の終了処理
    return 0;  // ソフトの終了 
}
以下のプログラムは全体のプログラムです。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "DxLib.h"

int Key[256];

int gpUpdateKey()
{
	char tmpKey[256];
	GetHitKeyStateAll(tmpKey);
	for (int i = 0; i < 256; i++)
		(tmpKey[i] == 0) ? (Key[i] = 0) : Key[i]++;//キーのフレームの習得
	return 0;
}
int idou[5][5] = {
	{ 1, 1, 1, 1, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 1, 1, 1, 1 },
};
int box[4][7][2], teki[5][5][2];

void init_box()
{
	for (int j = 0; j < 7; j++) {
		int w = (j - 3) * 100, h = 600;
		for (int i = 4; --i >= 0; ) {
			box[i][j][0] = w + 400, box[i][j][1] = h - 200;
			w = w * 9 / 10, h = h * 9 / 10;
		}
	}
	for (int i = 1; i <= 3; i++)
		for (int j = 1; j <= 3; j++) {
			teki[i][j][0] = (box[i - 1][j - 1][0] + box[i][j][0]) / 2 - 25;
			teki[i][j][1] = (box[i - 1][j - 1][1] + box[i][j][1]) / 2 - 66;
		}
}

int WINAPI WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR cl, int cs)
{
	SetGraphMode(780, 680, 32);        // ウィンドウの大きさを指定
	ChangeWindowMode(TRUE);             // 全画面ではなくウインドウを使用
	if (DxLib_Init() == -1) return -1;  // DXライブラリ初期化処理
	SetDrawScreen(DX_SCREEN_BACK);      // 裏画面を使用する設定

	init_box();//これによりint box()を呼び出して初期かしたbox[4][7][2], teki[5][5][2]を呼び出した。
	//int boxColor = GetColor(160, 64, 64);//ステージの色
	int nx = 2, ny = 2;  // tekiのxとyでの初期位置
	int px = teki[ny][nx][0], py = teki[ny][nx][1];  // tekiのx、y、zでの初期位置
	int move = 0;  // 移動状態
	int gh[12];  //グラフィックハンドル格納用配列
			// 5:正面、7:右向き、2:左向き、4:上向き、3:下向き、9:移動不可
	LoadDivGraph("charall.png", 12, 3, 4, 49, 66, gh);  //画像読み込み
	int playerphoto = gh[8];

	const int MOVE_INTERVAL = 1000; // 何ミリ秒ごとに移動処理をするか
	int nextMoveTime = GetNowCount() + MOVE_INTERVAL; // 次回移動処理をする時刻
	int stopCount = 0; // 動かないのがあと何回か

	while (ProcessMessage() == 0) {
		
		gpUpdateKey();  // キーの入力状態を取得
	

		if (GetNowCount() >= nextMoveTime) { // 指定の時間が経ったら(1sごとに)
			nextMoveTime += MOVE_INTERVAL; // 次に移動処理をする時刻を設定する
			if (stopCount > 0) {
				// 停止中のとき
				stopCount--; // 止まっている残り時間(回数)を減らす
			}
			else {
				// 普通の状態のとき
				if (GetRand(99) < 10) { // たまに(10%の確率で)
					stopCount = GetRand(2); // 数秒間(1~5秒間)その場に止まる
				}
				else {
					// 9マス上のいずれかのパネルに移動させる
					int cy = ny, cx = nx;
					do {
						move = 1;
						ny = GetRand(2) + 1;
						nx = GetRand(2) + 1;
						
					} while (nx == cx && ny == cy); // 移動先が今いるパネルなら、移動先を選びなおす
				}
			}
		}

		ClearDrawScreen();  // 裏画面をクリア
		if (move > 0 && ++move == 20) {
			move = 0; int playerphoto = gh[8];  // 移動終了
		}
		DrawGraph(teki[ny][nx][0], teki[ny][nx][1], playerphoto, FALSE);//tekiの画像が描画される最初の位置
		ScreenFlip();  // 裏画面を表画面に反映

	}


	DxLib_End();  // DXライブラリ使用の終了処理
	return 0;  // ソフトの終了 

}

Ouxiy
記事: 165
登録日時: 3ヶ月前

Re: 9マス上のマスを動く敵キャラを作るために時間の関数がほしいです。

#9

投稿記事 by Ouxiy » 2ヶ月前

もう一つお聞きしたいのですが、
if文での以下の部分ですが、どのように順序だてて以下のように作ったのですが、勉強したいためフローチャートが知りたいです。
どうかよろしくお願いいたします。

コード:

if (GetNowCount() >= nextMoveTime) { // 指定の時間が経ったら(1sごとに)
			nextMoveTime += MOVE_INTERVAL; // 次に移動処理をする時刻を設定する
			if (stopCount > 0) {
				// 停止中のとき
				stopCount--; // 止まっている残り時間(回数)を減らす
			} else {
				// 普通の状態のとき
				if (GetRand(99) < 10) { // たまに(10%の確率で)
					stopCount = GetRand(4); // 数秒間(1~5秒間)その場に止まる
				} else {
					// 9マス上のいずれかのパネルに移動させる
					int cy = ny, cx = nx;
					do {
						ny = GetRand(2) + 1;
						nx = GetRand(2) + 1;
					} while (nx == cx && ny == cy); // 移動先が今いるパネルなら、移動先を選びなおす
				}
			}
		}

かずま

Re: 9マス上のマスを動く敵キャラを作るために時間の関数がほしいです。

#10

投稿記事 by かずま » 2ヶ月前

Ouxiy さんが書きました:
2ヶ月前
if文での以下の部分ですが、どのように順序だてて以下のように作ったのですが、勉強したいためフローチャートが知りたいです。
なぜ、フローチャートが必要なんですか?

コード:

	if (GetNowCount() >= nextMoveTime) {
	nextMoveTime += MOVE_INTERVAL;
	if (stopCount > 0) {
	stopCount--;
	} else {
	if (GetRand(99) < 10) {
	stopCount = GetRand(4);
	} else {
	int cy = ny, cx = nx;
	do {
	ny = GetRand(2) + 1;
	nx = GetRand(2) + 1;
	} while (nx == cx && ny == cy);
	}
	}
	}
上記のコードでは、現在実行している行の次にどの行が実行されるのか
がすぐには分かりません。そこで、フローチャートが必要になります。

次のように書くと、現在実行している行の次にどの行が実行されるのか
が一目瞭然です。だから、フローチャートは不要です。

コード:

	if (GetNowCount() >= nextMoveTime) {
		nextMoveTime += MOVE_INTERVAL;
		if (stopCount > 0) {
			stopCount--;
		} else {
			if (GetRand(99) < 10) {
				stopCount = GetRand(4);
			} else {
				int cy = ny, cx = nx;
				do {
					ny = GetRand(2) + 1;
					nx = GetRand(2) + 1;
				} while (nx == cx && ny == cy);
			}
		}
	}

Ouxiy
記事: 165
登録日時: 3ヶ月前

Re: 9マス上のマスを動く敵キャラを作るために時間の関数がほしいです。

#11

投稿記事 by Ouxiy » 2ヶ月前

どうもありがとうございます。かずまさん。
フロチャートがほしいというか。
説明が知りたいです。というのも

コード:

if (stopCount > 0) {
			stopCount--;
		}
の後のelse {}の中にある、ifの文がどう働くのかわからくて質問しました。

アバター
みけCAT
記事: 6235
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: 9マス上のマスを動く敵キャラを作るために時間の関数がほしいです。

#12

投稿記事 by みけCAT » 2ヶ月前

Ouxiy さんが書きました:
2ヶ月前
どうもありがとうございました。そのような感じになります。
ただ、もう少し行いたいことがあります。
移動した瞬間に向きが切り替わり瞬間移動したようなエフェクトを付けたいです。

そこで私は以下のようにしました。

コード:

ClearDrawScreen();  // 裏画面をクリア
		if (move > 0 && ++move == 20) {
			move = 0; int playerphoto = gh[8];  // 移動終了
		}
をコード全体に付け足して、移動した後の状態はplayerphoto = gh[8]より真正面を向いたのままですが、
再び移動してから新しい座標でほんの一瞬だけ横を向くようにしたいためif (move > 0 && ++move == 20) として、瞬間移動して進んだように見せようとしました。うまく機能していませんが。なぜでしょうか。
「移動した後18フレーム後に何かをする」ための条件としては間違っていないようです。
(移動したフレームでmoveを1にし、さらにインクリメントするため、moveは2になる。
後のフレームでもインクリメントしていくため、移動したnフレーム後のmoveはn+2になる。)
このifのブロックの中で描画に使うplayerphotoとは別のplayerphotoをわざわざ宣言しているのは気になりますが、
そもそもコード中でgh[8]以外のグラフィックハンドルが使われていないようです。
したがって、「なぜでしょうか」の答えは
「向きが切り替わり瞬間移動したようなエフェクトを出すコードが無いから」でしょう。
Ouxiy さんが書きました:
2ヶ月前
もう一つお聞きしたいのですが、
if文での以下の部分ですが、どのように順序だてて以下のように作ったのですが、勉強したいためフローチャートが知りたいです。
作ってみました。
furoochaato-20190829.png
フローチャート
furoochaato-20190829.png (15.47 KiB) 閲覧数: 1338 回
コメントをフローチャートでの表現に合わせました。

コード:

if (GetNowCount() >= nextMoveTime) { // 指定の時間が経った?
	nextMoveTime += MOVE_INTERVAL; // 次の処理の時刻を設定
	if (stopCount > 0) { // 停止中状態?
		stopCount--; // 残り停止回数を減らす
	} else {
		if (GetRand(99) < 10) { // 0~99の乱数が10未満?
			stopCount = GetRand(4); // 停止回数をランダムで設定
		} else {
			int cy = ny, cx = nx; // 今いる座標を記憶する
			do {
				// 移動先をランダムで選択
				ny = GetRand(2) + 1;
				nx = GetRand(2) + 1;
			} while (nx == cx && ny == cy); // 移動先が今いる座標?
		}
	}
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Ouxiy
記事: 165
登録日時: 3ヶ月前

Re: 9マス上のマスを動く敵キャラを作るために時間の関数がほしいです。

#13

投稿記事 by Ouxiy » 2ヶ月前

みけCATさんありがとうございます。
そもそもコード中でgh[8]以外のグラフィックハンドルが使われていないようです。
したがって、「なぜでしょうか」の答えは
「向きが切り替わり瞬間移動したようなエフェクトを出すコードが無いから」でしょう。
ということは描画関数が無いわけでしょうか、、、。
解決方法として、その時の座標から新しい座標に進み座標が更新されるたびにif (move > 0 && ++move == 50)が更新され、新しい座標になるたびにmoveが0に戻りplayerphoto = gh[8]を表し、++moveによりmoveの中身が50になったらplayerphoto = gh[5]になるようにして、再び座標を移動した際にmoveの中身が0になり、、、を繰り返しを実装できればいいのですが、表現方法がわかりません。
また、私の考え方は正しいでしょうか。正しいならば以上の表現をどのようにコードにするのかのノウハウと
できれば以上を表現したコードが欲しいです。

私なりに、基礎的なプログラム

コード:

while (i < 2){
  printf("こんにちは¥n");
  i++;
}
を参考に書いてみたのですが、構文エラーが起きてしまいます。
条件とその後の処理の構文は間違っていないと思うのですが。
以上のように考えはあるのですが、コードで表現できません。
以下は自分なりに部分的に書いたコードです。

コード:

while (nx == cx && ny == cy) // 移動先が今いる座標?
					{
					playerphoto = gh[5];
					move = 0;
					}

かずま

Re: 9マス上のマスを動く敵キャラを作るために時間の関数がほしいです。

#14

投稿記事 by かずま » 2ヶ月前

Ouxiy さんが書きました:
2ヶ月前
以下は自分なりに部分的に書いたコードです。

コード:

while (nx == cx && ny == cy) // 移動先が今いる座標?
					{
					playerphoto = gh[5];
					move = 0;
					}
この while ループの中に入ったら、
どうやってループから抜けだすんでしょうか?

ところで、gh[0]~gh[11] のそれぞれが、どんな画像で、どんな時に
どの画像を表示したいのかを詳しく説明してください。

charall.png を見せてもらえれば、もっと良いでしょう。

gh[0]~gh[11] のそれぞれがどんな画像かは、
プログラム中にコメントとして書くべきだと思います。

Ouxiy
記事: 165
登録日時: 3ヶ月前

Re: 9マス上のマスを動く敵キャラを作るために時間の関数がほしいです。

#15

投稿記事 by Ouxiy » 2ヶ月前

ありがとうございます。

コード:

else {
					// 9マス上のいずれかのパネルに移動させる
					int cy = ny, cx = nx;
					do {
						ny = GetRand(2) + 1;
						nx = GetRand(2) + 1;
					} while (nx == cx && ny == cy); // 移動先が今いるパネルなら、移動先を選びなおす
					playerphoto = gh[8]; // 正面向いて移動
					move = 1;
				}
よりelseの中身の話なのでnx == cx && ny == cyで同じにならないときに抜け出して、新しい座標で正面を向いたplayerphoto = gh[8];が描画されます。

かずま

Re: 9マス上のマスを動く敵キャラを作るために時間の関数がほしいです。

#16

投稿記事 by かずま » 2ヶ月前

do文というものを知らないのですか?

do文の while以降だけを切り出し、「;」を「{」に変えて
新たな while文であるかのように改変して質問するなんて、
そんな無意味なことはやめてほしい。

それより、gh[0]~gh[11] のそれぞれがどんな画像か、
charall.png はどんなものかを、答えてください。

Ouxiy
記事: 165
登録日時: 3ヶ月前

Re: 9マス上のマスを動く敵キャラを作るために時間の関数がほしいです。

#17

投稿記事 by Ouxiy » 2ヶ月前

色々ありがとうございます。
gh[0]~gh[11] のそれぞれがどんな画像か、
charall.png はどんなものかを、答えてください。
こちらのサイトの画像を使わせて頂きました。
https://bituse.info/game/21

返信

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