このスレッドはロックされています。記事の閲覧のみとなります。
トップページ > 記事閲覧
一定の時間内に連続攻撃したいです。
名前:マーク42 日時: 2019/09/25 16:35

RキーでロックオンしてAで攻撃するのですが、そのさいに追加攻撃が出来るようにしたいと考え 新しい変数addattacktimeという変数を作りました。 その変数を使った昨日はRキーでロックオンしてAで攻撃が成功すると、フレームを利用して20〜0の間だけ、常に相手の前にとどまり、Rキーを押さなくても キーA(殴る)やキーK(蹴る)が出来るというものです。 <追加攻撃の流れ> Rキーでロック Aで攻撃 addattacktimeが20になり(画面に「addattacktime 20」と描画され)徐々に-1されていく。 再びAで攻撃 攻撃するとaddattacktimeは20に戻る。 次はKで攻撃 攻撃するとaddattacktimeは20に戻る。 攻撃手段がなくなる(何もしない) addattacktimeは-1されていく0になる。 addattacktimeが0になったので敵の目の前に移動する前のマスに戻る。 以上を再現するために以下のようにコードを書きました。ですが、なぜかaddattacktimeは負の値から負の方向に増え続けます。そのため相手の目の前に移動しても 元のマスに戻れません。 フレームを利用して、毎フレーム事に20から-1出来ていると思ったのですが、うまくいきません。 フレームは+1していく場合にしか利用できないのでしょうか。 だとしたらプログラムの方でaddattacktimeは0の状態から20に+1していきあげるように作り、描画では20から-1されていき0になるように作ろうと考えたのですが、 作り方がわからず、前者のやり方でなんとかできないかと考えています。 if (lock) { if (Key[KEY_INPUT_A] == 1 && count == 50) { //殴る//(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; // 俺は敵の眼前へ if (playerX == enemyX - 1) { preplayerX; playerImage = playerGHandle[4];}//敵の前に言ったら、移動する前の残像が残る。 //after = 1;//アタック状態 ここまでをアタックとしてafter = 1と置いた。 enemyImage = enemyGHandle[5];//攻撃を食らうと右向きになるようにする count = count - 50;//50だけ引く addattacktime = 20;//addattacktimeは20にセットする。 if (enemyGHandle[5]) { enemyHP = enemyHP - 50; }//if (Key[KEY_INPUT_A] == 1 && count <= 500)に直接enemyHP = enemyHP - 50;を書き込むか、殴るが成立した時にif (enemyGHandle[5]) { enemyHP = enemyHP - 50; }と書いても良い。 } } //俺は敵の眼前へ言った後、このifの条件により続けて攻撃か元の位置に戻るかになる if (addattacktime <= 20 && --addattacktime == 0)//addattacktimeが0になるまでの間に攻撃があればaddattacktimeは20に戻る { if (Key[KEY_INPUT_K] == 1 && Kcount == 50) {//攻撃がキックだった場合 count = count - 100;//キーAを押すたびに100だけ引く enemyImage = enemyGHandle[5];//攻撃を食らうと右向きになるようにする enemyHP = enemyHP - 50; playerX = preplayerX; playerImage = playerGHandle[4]; addattacktime = 20; if (addattacktime == 0) { playerX = preplayerX; playerImage = playerGHandle[4]; addattacktime = 0;//addattacktimeが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); SetTransColor(255, 255, 255); // 読み込む画像の前にこいつを置くことで透明化できる。ループ内にも書いて正しく動くが毎回読み込むようになってしまうため処理が遅くなる。 LoadDivGraph("lockon.bmp", 3, 3, 1, 23, 23, lockonHandle);//なので、一度読み込むだけ画像は使えるし、処理を遅くしないためにループに入る前かつWinMainの中に書いた。 int enemyImage = enemyGHandle[11]; // 敵 左向き int playerImage = playerGHandle[4]; // 俺 右向き int lockImge = lockonHandle[3]; int preplayerX; int after = 0; unsigned int count = 50; int count2 = 50; unsigned int count3 = 50; int Kcount = 50;//キック攻撃のゲージ int Kcount2 = 50; int attackdamage = 0;//殴る際の攻撃判定として作った。 int addattacktime = 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 == 50) { //殴る//(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; // 俺は敵の眼前へ if (playerX == enemyX - 1) { preplayerX; playerImage = playerGHandle[4];}//敵の前に言ったら、移動する前の残像が残る。 //after = 1;//アタック状態 ここまでをアタックとしてafter = 1と置いた。 enemyImage = enemyGHandle[5];//攻撃を食らうと右向きになるようにする count = count - 50;//50だけ引く addattacktime = 20;//addattacktimeは20にセットする。 if (enemyGHandle[5]) { enemyHP = enemyHP - 50; }//if (Key[KEY_INPUT_A] == 1 && count <= 500)に直接enemyHP = enemyHP - 50;を書き込むか、殴るが成立した時にif (enemyGHandle[5]) { enemyHP = enemyHP - 50; }と書いても良い。 } } //俺は敵の眼前へ言った後、このifの条件により続けて攻撃か元の位置に戻るかになる if (addattacktime <= 20 && --addattacktime == 0)//addattacktimeが0になるまでの間に攻撃があればaddattacktimeは20に戻る { if (Key[KEY_INPUT_K] == 1 && Kcount == 50) {//攻撃がキックだった場合 count = count - 100;//キーAを押すたびに100だけ引く enemyImage = enemyGHandle[5];//攻撃を食らうと右向きになるようにする enemyHP = enemyHP - 50; playerX = preplayerX; playerImage = playerGHandle[4]; addattacktime = 20; if (addattacktime == 0) { playerX = preplayerX; playerImage = playerGHandle[4]; addattacktime = 0;//addattacktimeが0にると、元の位置に戻る } } } if (count < 50) ++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] + 13,//敵の中心にマークを持ってくるために+13した。 pos[enemyY][enemyX][1] + 21,//敵の中心にマークを持ってくるために+21した。 lockImge, true); // FALSE -> TRUE//ロックマーク中だけ描画するようにした。 }//ロックマークの描画 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 < 50) { DrawFormatString(50, 300, GetColor(0, 255, 255), "%d", count);//ここでcountの情報だけを条件(count < 500)より呼び出して、countの色を変えた } DrawFormatString(100, 400, GetColor(255, 0, 0), "%d/%d", Kcount, Kcount2);//1回殴った時にすべて消費して、再び溜まるまでの過程を表示するための関数 if (count < 50) { DrawFormatString(100, 400, GetColor(0, 255, 255), "%d", Kcount);//ここでcountの情報だけを条件(count < 500)より呼び出して、countの色を変えた } //敵のHPの描画 DrawFormatString(pos[enemyY][enemyX][0]+33, pos[enemyY][enemyX][1]-49, GetColor(152, 251, 152), "HP%d",enemyHP); //アドアタックタイムの描画 //if (addattacktime ==20) { DrawFormatString(50, 500, GetColor(255, 0, 0), "addattacktime%d", addattacktime); //} } ScreenFlip(); // 裏画面を表画面に反映 } DxLib_End(); // DXライブラリ使用の終了処理 return 0; // ソフトの終了 }
メンテ

Page: 1 |

Re: 一定の時間内に連続攻撃したいです。 ( No.1 )
名前:マーク42 日時:2019/09/25 16:38

ちなみに比較演算子に上限/下限を抑える機能はないと言われたのですが、本当でしょうか? if (addattacktime <= 20 && --addattacktime == 0) はaddattacktimeが20以下の場合、-1を毎フレーム事に引いていって==0より(下限)は0だと表せていると思うのですが。 私は正しいでしょうか。 どうかよろしくお願いいたします。
メンテ
Re: 一定の時間内に連続攻撃したいです。 ( No.2 )
名前:どん 日時:2019/09/25 19:16

if (addattacktime <= 20 && --addattacktime == 0) この文だと,addattacktimeが0のときにしか,if文の中に入らず, そのときにしか,追加攻撃ができないように見えるんですが... if (addattacktime <= 20 && --addattacktime > 0) とすると,addattacktimeが0から20の間のときにのみ条件式が真になるので, 時間内に追加攻撃ができると思います また,そのifの中の addattacktime = 20; if (addattacktime == 0) { playerX = preplayerX; playerImage = playerGHandle[4]; addattacktime = 0;//addattacktimeが0にると、元の位置に戻る } の部分ですが,ifの上でaddattack=20をしちゃってるので条件式は必ず偽になり if文の中のコードは実行されません なので,上のif文を1つ外に出してそこで判定したほうがいいと思います あと,インクリメントとか,デクリメントは条件式とか引数の中に入れると,順番がややこしいので, なれるまでは別々に書いたほうがいいかと思われます
メンテ
Re: 一定の時間内に連続攻撃したいです。 ( No.3 )
名前:紺帽子 日時:2019/09/25 21:41

ttps://dxlib.xsrv.jp/cgi/patiobbs/patio.cgi?mode=view&no=4709 ttps://dxlib.xsrv.jp/cgi/patiobbs/patio.cgi?mode=view&no=4706 ttps://dxlib.xsrv.jp/cgi/patiobbs/patio.cgi?mode=view&no=4712 ttps://dxlib.xsrv.jp/cgi/patiobbs/patio.cgi?mode=view&no=4713 以下のもマーク42さんでしょうか? ttps://dixq.net/forum/search.php?keywords=Ouxiy ttps://teratail.com/users/DR.Dexter00#question ttps://teratail.com/users/METALBOLL616#question ttps://teratail.com/users/carnage0216#question ttp://bbs.wankuma.com/index.cgi?mode=al2&mo=91920&namber=91919&space=15&page=0 ttps://ja.stackoverflow.com/users/27296/rolisx ttps://qa.atmarkit.co.jp/users/Onsly/questions 投稿するときはネット上でハンドルネームを統一されたほうがよいかと思います。 勘違いであれば申し訳ありません。
メンテ
Re: 一定の時間内に連続攻撃したいです。 ( No.4 )
名前:マーク42 日時:2019/09/25 22:40

どんさん、ヒントありがとうございます! 早速試してみます。 紺帽子さん、はいそうです。すべて私です。 決して疚しいことがあるわけではないですが、ハンドルネームにこだわってしまい各サイト事異なる名前でした。 そうですね。統一したほうが見やすくていいですね。 わざわざネット上の投稿を集めて知らせてくださりありがとうございます! もともと出来が悪く独学でもしんどい中いろんなサイトで皆さんに助けて頂いているので感謝しています。
メンテ
Re: 一定の時間内に連続攻撃したいです。 ( No.5 )
名前:管理人 日時:2019/09/26 00:05

DXライブラリ質問掲示板は特にルールはありませんが、例えば 『C言語何でも質問掲示板( https://dixq.net/forum/viewforum.php?f=3 )』ではこちらにルールが記載されていて <フォーラム(掲示板)ルール> https://dixq.net/forum/rules マルチポスト( 複数の掲示板で同じ質問をすること )をする場合は、相互リンク( 『こちらの掲示板でも 同じ質問をしています( [掲示板のURL記載] )』のように、どこの掲示板で同じ質問をしているか記載すること )が 必要であったりしますので、よろしければ各掲示板にルールが無いか確認してみてください m(_ _)m
メンテ
Re: 一定の時間内に連続攻撃したいです。 ( No.6 )
名前:マーク42 日時:2019/09/26 19:13

どうもありがとうございます! int addattacktime = 20と初期化して if (addattacktime <= 20 && --addattacktime > 0)(20以下で、0より大きい場合は-1していく) としたのですが、 20から-1されて0で止まらずマイナスの値の方向になぜか進んでいきます。 あまりに一瞬で-1されてマイナスの方向に行くため本当にaddattacktimeが20から始まっているかわかりませんが、 addattacktime = 20のみを描画するとちゃんと20と出ているので20からマイナスの方向に-1されているのだと思います。 それともフレームは+1されているので、それを利用して-1と出来るようにするしかないのでしょうか。 書いている途中なのですが、if (addattacktime >= 0 && ++addattacktime < 20)と addattacktimeは0なので、20より小さく0より大きい場合と思ったのですが、 20より小さければOKとなってしまっているため20には上がらないので間違っていると考え、 if (addattacktime >= 0 && ++addattacktime > 20)としてみたのですが、これではダメです。 途中ではありますが、以下のように書いてaddattacktimeが0から20へ上がることを利用して、初期値addattackimage=20から1を引いていき、それを画面に描画 仕様と考えています。 //俺は敵の眼前へ言った後、このifの条件により続けて攻撃か元の位置に戻るかになる if (addattacktime >= 0 && ++addattacktime > 20)//addattacktimeが0になるまでの間に攻撃があればaddattacktimeは20に戻る { addattackimage = addattackimage - 1; if (Key[KEY_INPUT_K] == 1 && Kcount == 50) {//攻撃がキックだった場合 Kcount = Kcount - 50;//キーKを押すたびに50だけ引く enemyImage = enemyGHandle[5];//攻撃を食らうと右向きになるようにする enemyHP = enemyHP - 50; playerX = preplayerX; playerImage = playerGHandle[4]; addattacktime = 20; if (addattacktime == 0) { playerX = preplayerX; playerImage = playerGHandle[4]; addattacktime = 0;//addattacktimeが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); SetTransColor(255, 255, 255); // 読み込む画像の前にこいつを置くことで透明化できる。ループ内にも書いて正しく動くが毎回読み込むようになってしまうため処理が遅くなる。 LoadDivGraph("lockon.bmp", 3, 3, 1, 23, 23, lockonHandle);//なので、一度読み込むだけ画像は使えるし、処理を遅くしないためにループに入る前かつWinMainの中に書いた。 int enemyImage = enemyGHandle[11]; // 敵 左向き int playerImage = playerGHandle[4]; // 俺 右向き int lockImge = lockonHandle[3]; int preplayerX = 0; int after = 0; unsigned int count = 50; int count2 = 50; unsigned int count3 = 50; int Kcount = 50;//キック攻撃のゲージ int Kcount2 = 50; int attackdamage = 0;//殴る際の攻撃判定として作った。 int addattacktime = 0;//追加攻撃をするための変数 int addattackimage = 20;//描画するための追加アタックのためのゲージ 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 == 50) { //殴る//(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; // 俺は敵の眼前へ if (playerX == enemyX - 1) { preplayerX; playerImage = playerGHandle[4]; }//敵の前に言ったら、移動する前の残像が残る。 //after = 1;//アタック状態 ここまでをアタックとしてafter = 1と置いた。 enemyImage = enemyGHandle[5];//攻撃を食らうと右向きになるようにする count = count - 50;//キーAを押すたびに10だけ引く attackdamage = 20; if (enemyGHandle[5]) { enemyHP = enemyHP - 50; }//if (Key[KEY_INPUT_A] == 1 && count <= 500)に直接enemyHP = enemyHP - 50;を書き込むか、殴るが成立した時にif (enemyGHandle[5]) { enemyHP = enemyHP - 50; }と書いても良い。 } } //俺は敵の眼前へ言った後、このifの条件により続けて攻撃か元の位置に戻るかになる if (addattacktime >= 0 && ++addattacktime > 20)//addattacktimeが0になるまでの間に攻撃があればaddattacktimeは20に戻る { addattackimage = addattackimage - 1; if (Key[KEY_INPUT_K] == 1 && Kcount == 50) {//攻撃がキックだった場合 Kcount = Kcount - 50;//キーKを押すたびに50だけ引く enemyImage = enemyGHandle[5];//攻撃を食らうと右向きになるようにする enemyHP = enemyHP - 50; playerX = preplayerX; playerImage = playerGHandle[4]; addattacktime = 20; if (addattacktime == 0) { playerX = preplayerX; playerImage = playerGHandle[4]; addattacktime = 0;//addattacktimeが0にると、元の位置に戻る } } } if (count < 50) ++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を超えたら{}の中身を実行。 //enemyMoveが0より大きいならば+1されて、40より大きい数値になれば両方の条件を満たすので+1される。40より大きい数値になったら敵の画像が変わる。 //enemyMoveが40より+1されて大きくなるために++enemyMove > 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 (count < 8) { DrawGraph(pos[playerY][preplayerX][0], pos[playerY][preplayerX][1], playerImage, true); }//移動した一瞬に元の位置に自分を描画したい、しかしうまく機能していない。 //★多分一瞬過ぎるのであえてcount < 8と範囲を付けることでほんの一瞬だが残像が見えるようにした。 //攻撃してcountが50に溜まるまでの期間を利用した。 if (lock == 1) { DrawGraph( pos[enemyY][enemyX][0] + 13,//敵の中心にマークを持ってくるために+13した。 pos[enemyY][enemyX][1] + 21,//敵の中心にマークを持ってくるために+21した。 lockImge, true); // FALSE -> TRUE//ロックマーク中だけ描画するようにした。 }//ロックマークの描画 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 < 50) { DrawFormatString(50, 300, GetColor(0, 255, 255), "%d", count);//ここでcountの情報だけを条件(count < 500)より呼び出して、countの色を変えた } //敵のHPの描画 DrawFormatString(pos[enemyY][enemyX][0] + 33, pos[enemyY][enemyX][1] - 49, GetColor(152, 251, 152), "HP%d", enemyHP); DrawFormatString(50, 400, GetColor(255, 0, 0), "%d/%d", Kcount, Kcount2); DrawFormatString(50, 500, GetColor(255, 0, 0), "%d", addattackimage); DrawFormatString(50, 600, GetColor(255, 0, 0), "%d", addattacktime); } ScreenFlip(); // 裏画面を表画面に反映 } DxLib_End(); // DXライブラリ使用の終了処理 return 0; // ソフトの終了 }
メンテ
Re: 一定の時間内に連続攻撃したいです。 ( No.7 )
名前:管理人 日時:2019/09/27 00:41

> int addattacktime = 20と初期化して > if (addattacktime <= 20 && --addattacktime > 0)(20以下で、0より大きい場合は-1していく) > としたのですが、 > 20から-1されて0で止まらずマイナスの値の方向になぜか進んでいきます。 if (addattacktime <= 20 && --addattacktime > 0) ↑こちらの文を分解すると、以下の処理が行われます if (addattacktime <= 20) { --addattacktime; if (addattacktime > 0) { // if文の中の処理 } } addattacktime は初期値が 20 で、20と同じかそれ以下なので最初の if文の条件である addattacktime <= 20 が成立するので if文の中に入ります、そして最初の if文を通過すると 必ず --addattacktime が実行されるので、addattacktime は際限なく-1されるという訳です 『(20以下で、0より大きい場合は-1していく)』をされたいのでしたら、以下のように 最初に『addattacktime <= 20 && addattacktime > 0』の条件を満たした場合のみ --addattacktime を実行するようにする必要があります if (addattacktime <= 20 && addattacktime > 0) { --addattacktime; } もしどうしても if文の1行の中で --addattacktime を実行されたいとのことでしたら、 以下のようにする必要があります if ((addattacktime <= 20 && addattacktime > 0) && (--addattacktime, true)) ↑の意味は、まず addattacktime <= 20 && addattacktime > 0 が成立するか判断して、 成立する場合は --addattacktime を実行して、且つ if文の結果としては真とするために true を記述、という式です ただ、こんな式を書くと変人扱いされるので、普通に if (addattacktime <= 20 && addattacktime > 0) { --addattacktime; } とした方が良いです… if (addattacktime >= 0 && ++addattacktime < 20) ↑こちらも同じ理由で if (addattacktime >= 0 && addattacktime < 20) { ++addattacktime; } とすれば意図する動作になると思います
メンテ
Re: 一定の時間内に連続攻撃したいです。 ( No.8 )
名前:マーク42 日時:2019/09/27 01:28

いつもいつもありがとうございます。 管理人様の解答を参考に自分なりに書いてみたところうまく機能しました! 本当にありがとうございます。 ですが、少し問題が起きてしまって、ロックオンして攻撃して、addattcktimeを利用して追加攻撃をした後に元の位置に戻るのですが、 なぜか前のマスに進めません。 何度も確認しているのですが、座標が固定されるような書き方はしていないので原因がわかりません。 ただ、今回の問題は解決したので新しい問題として投稿させて頂きます。 どうもありがとうございました。
メンテ
Re: 一定の時間内に連続攻撃したいです。 ( No.9 )
名前:マーク42 日時:2019/10/09 16:27

以下は追加攻撃できるようにしたコードです。 ロックオンして追加攻撃して、その後再びAを押すと攻撃できます。 if (Key[KEY_INPUT_A] == 1 && count <= 50&& count >= 10 ) { //殴る//(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; // 俺は敵の眼前へ if (playerX == enemyX - 1) { preplayerX; playerImage = playerGHandle[4]; }//敵の前に言ったら、移動する前の残像が残る。 //after = 1;//アタック状態 ここまでをアタックとしてafter = 1と置いた。 enemyImage = enemyGHandle[5];//攻撃を食らうと右向きになるようにする count = count - 10;//キーAを押すたびに10だけ引く addattacktime = 500; zannzou = 20; if (enemyGHandle[5]) { enemyHP = enemyHP - 50; }//if (Key[KEY_INPUT_A] == 1 && count <= 500)に直接enemyHP = enemyHP - 50;を書き込むか、殴るが成立した時にif (enemyGHandle[5]) { enemyHP = enemyHP - 50; }と書いても良い。 } if (Key[KEY_INPUT_K] == 1 && Kcount == 50) {//攻撃がキックだった場合 lock = 0;//lock = 1の時の「lock!!」の描画を消すためにlockの値を0に変更。 lockonMove = 0;//アタックする時 ロックオンの画像が消えるように値を0にする。 preplayerX = playerX; // 元の位置を保持 playerX = enemyX - 1; // 俺は敵の眼前へ if (playerX == enemyX - 1) { preplayerX; playerImage = playerGHandle[4]; }//敵の前に言ったら、移動する前の残像が残る。 enemyImage = enemyGHandle[5]; Kcount = Kcount - 50;//キーKを押すたびに50だけ引く enemyHP = enemyHP - 50; addattacktime = 500; } }//if (Key[KEY_INPUT_A] == 1 && count == 50)と条件が被ると重複して10を引いてしまうのでそれ以外で押された場合として書いた。 //上のif文が成り立たなくても成り立つように、かつ被らないようにするためにelse ifで書いた。 else if (Key[KEY_INPUT_A] == 1 && enemyImage == enemyGHandle[5]&& count >= 10)//敵が右向きの時に続けてAを押すと連続攻撃ができる//相手がenemyImage == enemyGHandle[5]状態の時に他の攻撃もできるように他のキーも&&すればいい { count = count - 10; playerX = enemyX - 1; // 俺は敵の眼前へ addattacktime = 500; enemyHP = enemyHP - 50; //after = 1;//アタック状態 ここまでをアタックとしてafter = 1と置いた。 }
メンテ

Page: 1 |