作ったプログラムです。攻撃すると敵の画僧がenemyGHandle[5]となり、それと同時にattackdamage = 100を設置します。
if文よりattackdamage = 100かつ攻撃を食らった際の画像のenemyGHandle[5]の時、enemyHPからattackdamageを引くようにして、attackdamage = 0にするプログラムにしました。
ちゃんと書けたと思ったら実行と同時に何もしていないのに敵のHPが急激に減っていきます。原因がわかりません。
if (lock) {
if (Key[KEY_INPUT_A] == 1 && count <= 500) { //殴る//(lock){}の中に書くとロックする度にcountが0になるので意味がない
//count++; ここにcount書くとifの条件よりcountが0の時の下のlockやplayerX = enemyX - 1など条件になるため、++でcountが1になったらロックできても攻撃できないんだ
//ここのcountの情報がそのまま下の描画関数に渡されるだけ。
//if (count >= 0 && ++count > 40) {//countが0から15になるまでを一フレームで表しただけでは?ようはcountを0〜1にするのに15フレームかかっただけでは?いや、単純にここにフレームは働いていないなので++count > 40と書いて39回行うはずがフレームが働かないので1しか上がっていないので一回しか攻撃が出来ないのだ
lock = 0;//lock = 1の時の「lock!!」の描画を消すためにlockの値を0に変更。
lockonMove = 0;//アタックする時 ロックオンの画像が消えるように値を0にする。
preplayerX = playerX; // 元の位置を保持
playerX = enemyX - 1; // 俺は敵の眼前へ
after = 1;//アタック状態 ここまでをアタックとしてafter = 1と置いた。
enemyImage = enemyGHandle[5];//攻撃を食らうと右向きになるようにする
count = count - 500;//キーAを押すたびに10だけ引く
attackdamage = 100;
}
}
if (attackdamage = 100&& enemyGHandle[5]) {
enemyHP = enemyHP - attackdamage;
attackdamage = 0;
}
以下は全体のコードです。
#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 stage[4][7][2]; // 盤上のマスの格子点の座標
int pos[3][6][2]; // キャラ描画座標
void init_stage() // stage と pos を初期化する
{
for (int j = 0; j < 7; j++) {
int w = (j - 3) * 100, h = 300;
for (int i = 4; --i >= 0; ) {
stage[i][j][0] = w + 400, stage[i][j][1] = h - 100;
w = w * 9 / 10, h = h * 9 / 10;
}
}
for (int i = 0; i < 3; i++)
for (int j = 0; j < 6; j++) {
pos[i][j][0] = (stage[i][j][0] + stage[i + 1][j + 1][0]) / 2 - 25;
pos[i][j][1] = (stage[i][j][1] + stage[i + 1][j + 1][1]) / 2 - 65;
}
}
int White;
int function_status;//戦闘画面中は1とするための変数function_statusの定義
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
SetGraphMode(780, 680, 32); // ウィンドウの大きさを指定
ChangeWindowMode(TRUE); // 全画面ではなくウインドウを使用
if (DxLib_Init() == -1) return -1; // DXライブラリ初期化処理
SetDrawScreen(DX_SCREEN_BACK); // 裏画面を使用する設定
init_stage(); // stage, pos の初期化
int enemyX = 4, enemyY = 1; // 敵の位置
int playerX = 1, playerY = 1; // 俺の位置
int enemyMove = 0; // 敵の移動状態
// 俺の移動状態//1〜21で右に振り向きのプログラム@が終わり、22になったら足踏みするAを実行するようにする。
int playerMove = 1;
int lockonMove = 0;
int lockonHandle[3];
function_status = 1;//最初は1にして戦闘画面状態にする。
int lock = 0; // ロック状態
int enemyGHandle[12]; // 敵のグラフィックハンドル格納用配列
int playerGHandle[12]; // 俺のグラフィックハンドル格納用配列
// 0-2:後ろ向き、3-5:右向き、6-8:前向き、9-11:左向き
LoadDivGraph("charall.png", 12, 3, 4, 49, 66, enemyGHandle);
LoadDivGraph("charall.png", 12, 3, 4, 49, 66, playerGHandle);
LoadDivGraph("lockon.bmp", 3, 3, 1, 23, 23, lockonHandle);
int enemyImage = enemyGHandle[11]; // 敵 左向き
int playerImage = playerGHandle[4]; // 俺 右向き
int lockImge = lockonHandle[3];
int preplayerX;
int after = 0;
unsigned int count = 500;
int count2 = 500;
unsigned int count3 = 50;
int attackdamage = 0;//殴る際の攻撃判定として作った。
const int MOVE_INTERVAL = 1000; // 何ミリ秒ごとに移動処理をするか
int nextMoveTime = GetNowCount() + MOVE_INTERVAL; // 次回移動処理をする時刻
int stopCount = 0; // 動かないのがあと何回か
int enemyHP = 300;
while (ProcessMessage() == 0) {
gpUpdateKey(); // キーの入力状態を取得
if (Key[KEY_INPUT_X] == 1) { //キーXを押すとfunction_statusは0になる
function_status = 0;
}
if (Key[KEY_INPUT_Y] == 1) { //キーYを押すとfunction_statusは1になる
function_status = 1;//戦闘画面に戻す
}
else {//戦闘画面中は1とする
//gpUpdateKey(); // キーの入力状態を取得 上のifで既にgpUpdateKey();があり、elseはif以外の情報は引き継ぐので再びgpUpdateKey();書く必要はなかった。
// 俺の移動
if (Key[KEY_INPUT_RIGHT] == 1 && playerX < 2) { //キーを入力する以外にも押した後に早く画像を切り替えて足踏みするようにするために初期値にも1はあるがキーにもplayerMove=1を書いたり、キーを押したらどうしたいかをするためにplayerX++を書いている。
playerMove = 1; playerX++; playerImage = playerGHandle[2];
} //playerMove = 1;があると下に書いたplayerMoveより足踏みするplayerMoveが無いと初期値の1でそのまま足踏みするので遅く反応するのでは?
if (Key[KEY_INPUT_LEFT] == 1 && playerX > 0) {//キーにplayerMove=1を書くと初期値の1よりも早くキーに書いたplayerMoveの1が行くため早く足踏みに行くため、止まってから足踏みに行くまでの間にある向きを変える画像playerGHandle[2]が一瞬であるため、向きを変えるのが早く見えるのでは?足踏みを速く来るようにしたため。
playerMove = 1; playerX--; playerImage = playerGHandle[9];//まあ、足踏みさせなくても、ただ書くだけでも方向を十分早く変えれる
}
if (Key[KEY_INPUT_UP] == 1 && playerY > 0) {
playerMove = 1; playerY--; playerImage = playerGHandle[2];
}
if (Key[KEY_INPUT_DOWN] == 1 && playerY < 2) {
playerMove = 1; playerY++; playerImage = playerGHandle[8];
}
//Rが一度押された上でフレームを利用してループさせるためにif文を新しく外に書いたのだ。
if (Key[KEY_INPUT_R] == 1 && playerY == enemyY) {
DrawGraph(pos[enemyY][enemyX][0], pos[enemyY][enemyX][1],//多分ここはいらない下に描画するための関数を書くため
lockImge, FALSE); // ロックマークの描画
lock = 1;//Key[KEY_INPUT_R] == 1 && playerY == enemyYの時、lockを1にする。lockを「何フレーム目の時」でも値を1として置いたため、条件式lockの入力キーAに呼び出せる。
lockonMove = 1;
}
if (lockonMove > 0) {//lockonMoveが0より大きいならば++lockonMoveをする、
++lockonMove;
}
if (lockonMove == 10) {
lockImge = lockonHandle[0];//情報lockonMove == 10やlockonHandle[0]を引き継いで下に書いた描画関数に入るため、ここには関数に入れる情報だけ入るのだ。
//その時の情報lockonMove == 10やlockonHandle[0]以外の引き継がれたとうかその時の敵の座標なども関数に入る。関数が求めるものが入るので、関数に必要なものを揃える。
}
else if (lockonMove == 20) {
lockImge = lockonHandle[1];
}
else if (lockonMove == 30) {
lockImge = lockonHandle[2];
}
else if (lockonMove == 40) {
lockImge = lockonHandle[1];
lockonMove = 1;
}
if (playerY != enemyY) {
lock = 0;
lockonMove = 0;//敵が移動した場合ロックオンの画像が消えるようにlockonMoveを0にする。
}
//playerY != enemyYよりY座標が異なる場合を表す、Y座標が異なる場合はlockの値は0になる。要はロックが解除されてしまう。
if (lock) {
if (Key[KEY_INPUT_A] == 1 && count <= 500) { //殴る//(lock){}の中に書くとロックする度にcountが0になるので意味がない
//count++; ここにcount書くとifの条件よりcountが0の時の下のlockやplayerX = enemyX - 1など条件になるため、++でcountが1になったらロックできても攻撃できないんだ
//ここのcountの情報がそのまま下の描画関数に渡されるだけ。
//if (count >= 0 && ++count > 40) {//countが0から15になるまでを一フレームで表しただけでは?ようはcountを0〜1にするのに15フレームかかっただけでは?いや、単純にここにフレームは働いていないなので++count > 40と書いて39回行うはずがフレームが働かないので1しか上がっていないので一回しか攻撃が出来ないのだ
lock = 0;//lock = 1の時の「lock!!」の描画を消すためにlockの値を0に変更。
lockonMove = 0;//アタックする時 ロックオンの画像が消えるように値を0にする。
preplayerX = playerX; // 元の位置を保持
playerX = enemyX - 1; // 俺は敵の眼前へ
after = 1;//アタック状態 ここまでをアタックとしてafter = 1と置いた。
enemyImage = enemyGHandle[5];//攻撃を食らうと右向きになるようにする
count = count - 500;//キーAを押すたびに10だけ引く
attackdamage = 100;
}
}
if (attackdamage = 100&& enemyGHandle[5]) {
enemyHP = enemyHP - attackdamage;
}
if (count < 500) ++count;//これにより連続で攻撃してもif (Key[KEY_INPUT_A] == 1 && enemyImage == enemyGHandle[5])を考慮して連続攻撃ができる!
//★あるフレームが進んでから画像がを動くまでを遅くした、ならば、あるフレームが進んだら数字も次の数字に移るまで遅くできるのは?と考えた。
if (after > 0 && ++after > 15) {//afterが1より大きい時++afterが働き15より大きくなったら、
///ifの中にifを書いてしまうとその前のifを否定してしまうためデータが引き継げない。なので別のif文として書いた。←多分違う
playerX = preplayerX;//preplayerXの座標をplayerXに代入する。
playerImage = playerGHandle[4];
after = 0;//アタック解除
}
// 敵の移動
int t = GetNowCount();
if (t >= nextMoveTime) { // 指定の時間が経ったら(1sごとに)
nextMoveTime = t + MOVE_INTERVAL; // 次回移動処理をする時刻
if (stopCount > 0) { // 停止中のとき
stopCount--; // 止まっている残り時間(回数)を減らす
}
else { // 普通の状態のとき
if (GetRand(99) < 10) { // たまに(10%の確率で)
stopCount = GetRand(4); // 数秒間(1〜5秒間)その場に止まる
}
else { // 9マス上のいずれかのパネルに移動させる
int cy = enemyY, cx = enemyX;
do {
enemyY = GetRand(2);
enemyX = GetRand(2) + 3;
} while (enemyX == cx && enemyY == cy ||
enemyX == playerX && enemyY == playerY);
enemyImage = enemyGHandle[10];
enemyMove = 1;
}
}
}
if (playerMove > 0) {//1フレームで処理を終わらせるためifの後はelse ifを使った。//フレームがあってもplayerMove++を書かないと1ずつ上がらない。playerMove++をフレームの60回ループするするところに書くことで以下のように書いて足踏みしている画像が描けた。
playerMove++;//60フレームの中で、このifで条件(playerMove > 0)が真であるためplayerMove++を「フレーム」と「条件式」により繰り返しplayerMove++して、
if (playerMove == 10)//以前の文を否定しないelse ifが次にあるためplayerMoveの情報を引き継ぎplayerMove == 20となるまで繰り返しplayerMove++をした。次にもelse ifがあるので同様、、、
{
playerImage = playerGHandle[4];
}
else if (playerMove == 20)//条件式として書くため=は==と書いた。//else ifによりplayerMoveが20を超えて(20の場合を否定し)30の場合を表す。
{
playerImage = playerGHandle[5];
}
else if (playerMove == 40)//30まで上がったものが40に上がった時、playerGHandle[4]になる。if文の連続では文法のルールで前の文を否定するため連続的に画像が流れず足踏みできない、なのでelse ifにしたのだ。
{
playerImage = playerGHandle[4];
}
else if (playerMove == 60 * 4) {//下に書いているように60フレームないに納めないといけないため、50まで上がったところで終わっている。
playerImage = playerGHandle[3];//上に書いてることには誤りがある、60フレームで1sなだけ、超えてもいい。
playerMove = 1;//
}
}
//ループ内に書いたenemyMoveについてenemyMoveが0より大きくて40を超えたら{}の中身を実行。
if (enemyMove > 0 && ++enemyMove > 40) {//pcが60フレームで一周するためenemyMoveが61以上だとenemyGHandle[8]が反映されず元のままで移動が終わる。なのでenemyMoveは60以下でなくてはならない
enemyMove = 0; enemyImage = enemyGHandle[11];//60になる前に画像11を描画するようにしなければならないため、60より小さい40フレームにした。
}
}
//これより以下は描画するためのプログラム
ClearDrawScreen(); // 裏画面を
//if (function_status == 0) {//function_status = 0の時はメニュー画面でfunction_statusが1の時は戦闘画面とした。
//キーXを押すとfunction_statusを0とするように書いた
if (function_status == 0) {
White = GetColor(255, 255, 255); //色の取得
DrawString(100, 140, "メニュー画面 (xをプッシュ)", White);
//攻撃手段を選んでいる最中は0とする
ScreenFlip(); // 裏画面を表画面に反映
}
else {// ステージの描画 ★function_status == 0の場合ではないし、0か1の二択しかため、function_statusの初期値は1であるためif (function_status == 0)は除外されelseの方が描画される。
int stageColor = GetColor(160, 64, 64);
for (int i = 0; i < 4; i++)
DrawLine(stage[i][0][0], stage[i][0][1],
stage[i][6][0], stage[i][6][1], stageColor, 5);
for (int j = 0; j < 7; j++)
DrawLine(stage[0][j][0], stage[0][j][1],
stage[3][j][0], stage[3][j][1], stageColor, 5);
DrawGraph(pos[enemyY][enemyX][0], pos[enemyY][enemyX][1],
enemyImage, true); // 敵キャラの描画
DrawGraph(pos[playerY][playerX][0], pos[playerY][playerX][1],
playerImage, true); // 俺キャラの描画
if (lock == 1) {
DrawGraph(pos[enemyY][enemyX][0], pos[enemyY][enemyX][1],
lockImge, FALSE);//ロックマーク中だけ描画するようにした。
}//ロックマークの描画
if (lock) DrawFormatString(100, 200, GetColor(255, 255, 255), "LOCK");//ループ内に書くと条件式lockのによりlockの値を0にしてもずっと表示されるため、必要な時に表示するようにここに書いた
DrawFormatString(50, 300, GetColor(255, 0, 0), "%d/%d", count, count2);//1回殴った時にすべて消費して、再び溜まるまでの過程を表示するための関数
if (count < 500) {
DrawFormatString(50, 300, GetColor(0, 255, 255), "%d", count);//ここでcountの情報だけを条件(count < 500)より呼び出して、countの色を変えた
}
//敵のHPの描画
DrawFormatString(200, 300, GetColor(100, 100, 0), "HP%d",enemyHP);
}
ScreenFlip(); // 裏画面を表画面に反映
}
DxLib_End(); // DXライブラリ使用の終了処理
return 0; // ソフトの終了
}