質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

2698閲覧

Dxlib アニメーションの切り替え実装について

退会済みユーザー

退会済みユーザー

総合スコア0

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2019/08/07 07:48

1,Animation関数の部分なのですがMain.cppで60フレームに固定していてif(s_anime == ewalk){}部で左右キーを押している間だけフレーム数を足しているのですがこの切り替え方法はわかりやすいのでしょうか?自分ではこの実装ほうしか思いつかんずもっとわかりやすい方法などありますでしょうか?

2、ある一定のフレーム数で変数を再初期化?1に戻さないと値がおかしくなる?なんか不安なので1に戻しているのですがこれはいいのでしょうか?

3,なんか変わりづらく作ってる気がしてならないのですが慎重にわかりやすく作りたいのですが何かヒントがあったら教えてもらいたいです。

PLayer.cpp

1#include <iostream> 2#include <fstream> 3#include "Input.h" 4#include "Player.h" 5#include "DxLib.h" 6#include "Map.h" 7 8#define MOVE_SPD 5 9/*コンストラクタ*/ 10Player::Player(const char* str, int xx, int yy) :pos{xx,yy} 11{ 12 LoadDivGraph(str,7,7,1,64,64,g_handle); 13 14 15 16} 17 18/*計算更新*/ 19void Player::Update() 20{ 21 input_key(); 22 //gravity(); 23 24} 25bool isCollision = false; 26bool jump_c = false; 27 28/*描画更新*/ 29void Player::Draw_Update() 30{ 31 /* 32 0 待機 33 1,2,3//走る 34 */ 35 //DrawFormatString(100,100,GetColor(255,255,255),"Debug"); 36 37 /*←左*/ 38 if (key == -1) 39 { 40 //DrawTurnGraph(gPos_x(), gPos_y(), g_handle[0], true); 41 DrawTurnGraph(gPos_x(), gPos_y(), g_handle[Animation()], true); 42 43 } 44 /*右→*/ 45 if (key == 1) 46 { 47 DrawGraph(gPos_x(), gPos_y(), g_handle[Animation()], true); 48 } 49 50} 51 52 53bool isJump = false;//ジャンプボタンを押したかどうか 54bool isJumpNow = false;//ジャンプ中かどうか 55 56/*キー入力*/ 57void Player::input_key() 58{ 59 if (keybord(KEY_INPUT_LEFT) > 0) 60 { 61 key = -1; 62 s_anime = ewalk; 63 64 sPos_x(-MOVE_SPD); 65 66 }else if (keybord(KEY_INPUT_RIGHT) > 0) 67 { 68 key = 1; 69 s_anime = ewalk; 70 71 sPos_x(+MOVE_SPD); 72 73 }else if (keybord(KEY_INPUT_UP) > 0) 74 { 75 sPos_y(+MOVE_SPD); 76 77 }else if (keybord(KEY_INPUT_DOWN) > 0) 78 { 79 sPos_y(-MOVE_SPD); 80 } 81 else if (keybord(KEY_INPUT_SPACE) > 0) 82 { 83 /*ジャンプできる時isJump false*/ 84 if (isCollision == true) 85 { 86 isJump = true; 87 } 88 } 89 else//何も押していない時 90 { 91 s_anime = ewait; 92 } 93 94 95 96 jump_up(); 97 gravity(); 98 99} 100/*アニメーション管理*/ 101int Player::Animation() 102{ 103#define ANIME_SPD 20 104 105 anime_f++; 106 if (s_anime == ewait) 107 { 108 anime_f = 0; 109 return 0; 110 111 } 112 113 if (s_anime == ewalk) 114 { 115 if (anime_f % ANIME_SPD == 0) 116 { 117 Nanime += 1; 118 if (Nanime > 3) 119 { 120 Nanime = 1; 121 } 122 } 123 124 125 if (anime_f > 120) 126 { 127 anime_f = 1; 128 } 129 return Nanime; 130 131 } 132 133} 134 135/*ジャンプ管理*/ 136void Player::jump_up() 137{ 138 if (isJump == true) 139 { 140 DrawFormatString(0, 0, GetColor(255, 255, 255), "%d ", jump_c); 141 142 n = (n - 2); 143 144 if (n <= 0) 145 { 146 isJump = false; 147 n = 0; 148 } 149 150 //j = n; 151 152 sPos_y(n); 153 154 } 155 else if(isJump == false && n == 0) { 156 n = jump_range; 157 } 158 159 160} 161 162 163/*重力効果*/ 164void Player::gravity()//ジャンプしてるかどうかと当たり判定を比較 165{ 166 167 isCollision = Map::col(pos.x,pos.y); 168 const char filename[100] = { "Debug_Log.txt" }; 169 //std::fstream ofs(filename, std::ios::app); 170 std::fstream ofs(filename, std::ios::app); 171 172 173 if (!ofs) 174 { 175 176 } 177 else { 178 DrawFormatString(0, 100, GetColor(255, 255, 255), "isCollision %d", isCollision); 179 180 //ofs << "aaaa"<< std::endl; 181 182 char b[100];//バッファ 183 char str[100]; 184 sprintf_s(str,sizeof(b), "[x: %d , y: %d] : isCollsion %d\n", pos.x,pos.y,isCollision); 185 186 //= "x: \n" + (string)pos.x;//+ "y: " + pos.y + "\n"; 187 ofs << str; 188 //ofs << "x: " + pos.x << "y: " + pos.y<<std::endl; 189 } 190 191 if (isJump == false) { 192 193 194 195 gn = (gn + 2); 196 if (gn >= 6) { 197 gn = 10; 198 } 199 200 //sPos_y(-gn); 201 //sPos_y(-2); 202 /*当たっていない時ジャンプボタンを押した時*/ 203 if (isCollision == false) 204 { 205 206 sPos_y(-gn); 207 } 208 else if (isCollision == true) 209 { 210 sPos_y(1); 211 212 213 // isJump = false; 214 } 215 } 216 if (jump == true) 217 { 218 219 220 } 221 222} 223 224/*座標の取得と設定*/ 225void Player::sPos_x(int xx)//加算 226{ 227 pos.x += xx; 228} 229 230void Player::sPos_y(int yy)//加算 231{ 232 pos.y += -yy; 233} 234 235int& Player::gPos_x() 236{ 237 return pos.x; 238} 239 240int& Player::gPos_y() 241{ 242 return pos.y; 243} 244 245

Player.h

1#ifndef ___PLAYER_H 2#define ___PLAYER_H 3#include <iostream> 4#include <fstream> 5using namespace std; 6#include "Chr.h" 7#include "Map.h" 8 9#define JUMP_RANGE 30 10class Player : Chr 11{ 12private: 13 14 enum anime_s 15 { 16 ewait, 17 ewalk, 18 ejump, 19 egame_over, 20 21 }; 22 23 anime_s s_anime = ewait;//アニメ管理 24 position pos; 25 int g_handle[8];//画像格納ハンドル 26 27 /*座標の取得と設定*/ 28 void Chr::sPos_x(int xx); 29 void Chr::sPos_y(int yy); 30 31 int& Chr::gPos_x(); 32 int& Chr::gPos_y(); 33 34 void input_key();//キー入力 35 void gravity();//重力落下 36 void jump_up();//ジャンプ上昇 37 38 int prev = 0;//前の座標 39 int gn = 0;//落下速度 40 int Nanime = 0; 41 int anime_f = 0; 42 bool jump = false; 43 const int jump_range = 30;//ジャンプ最大値 44 int n = jump_range; 45 int j = 1; 46 int key = 1;//向き管理 47 48 int Chr::Animation(); 49 50public: 51 52 Player(const char* str,int xx,int yy); 53 54 55 void Chr::Update(); 56 void Chr::Draw_Update(); 57 58}; 59 60#endif

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

1,Animation関数の部分なのですがMain.cppで60フレームに固定していてif(s_anime == ewalk){}部で左右キーを押している間だけフレーム数を足しているのですがこの切り替え方法はわかりやすいのでしょうか?自分ではこの実装ほうしか思いつかんずもっとわかりやすい方法などありますでしょうか?

キーを押している間だけ、フレームを動かすのは考え方として間違っていません。むしろそれしかありません。しかし作り方がどうも、丁寧な作り方ではないように思えます。
Draw_Update()にこの処理を置くのではなく、Update()にこの処理を置いた方がいいように思えます。

DrawTurnGraph(gPos_x(), gPos_y(), g_handle[Animation()], true); //1.自分のクラス内でget関数を呼ぶ必要がない。pos.xで良い。 //2.g_handle[Animation()],ではなく、csv等の外部データにアニメパターンのデータを置いておくのがベスト。 //3.trueのみでは、後に読み直した時なんのことか分からなくなる可能性がある。

2、ある一定のフレーム数で変数を再初期化?1に戻さないと値がおかしくなる?なんか不安なので1に戻しているのですがこれはいいのでしょうか?

ここの事でしたら全体的に不安しかありません。

int Player::Animation() { #define ANIME_SPD 20//関数内で値を動かしたくない場合は、constexprまたはstatic constを使う。 anime_f++; if (s_anime == ewait) { anime_f = 0; return 0; } if (s_anime == ewalk) { if (anime_f % ANIME_SPD == 0) { Nanime += 1; if (Nanime > 3) { Nanime = 1;//上で0を返してしまっている以上仕方ない気がする。 } } if (anime_f > 120) { anime_f = 1; } return Nanime; } //一番最後のreturnがないのが超不安。 }

3,なんか変わりづらく作ってる気がしてならないのですが慎重にわかりやすく作りたいのですが何かヒントがあったら教えてもらいたいです。

それは「慣れろ」です。LEGOで上手く作るコツを聞くのと同じ質問です。
ヒントなんかありません。正解がないのが楽しいものに正解を求めてどうするのですか?
仕事ではそうは行きませんが、個人で作る場合は自由にやっていいと思います。
気に食わないならまた書き直せば良い。余力がないならそれはそれでいいではないかと思います。

投稿2019/08/07 22:49

stdio

総合スコア3307

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

animationの状態を直接Playerが持つのはちょっと汚いという思いがあります。クラスに出してしまいたいところです。anime_senum classにするほうがいいでしょう。

あとカウンター変数はintじゃなくてstd::uint64_tとかを使うほうがいいでしょう。少なくともunsignedであるほうが適切でしょう。


追記

時間不足で中保半端な解答になってしまったのでもう少し追記します。

まずanimationの状態を直接Playerが持つのは責任がぼやけているというのはすでに指摘したとおりです。なので新たにアニメーションクラスを作るわけですが、今回どういうアニメーションかというと、状態がサイクリックですよね?1->2->3->1みたいな。

とするとまずそういうイテレータを作るべきでしょう。つまり任意の閉区間[n1...n2]をサイクリックするイテレータです。イテレータの作り方は

イテレータの解説をするなんて今更佳代

を参照してください。

次に結局これらの数字は何だったかと言うと、画像ハンドルの配列の要素番号として使うのでしたね。

とするとこのイテレータをラップしたアニメーションクラスをつくりましょう。以下の物を少なくとも持つクラスです。

  1. 今は走っているのか待機しているのかのフラグ
  2. 走っている状態を表すイテレータ
  3. 画像ハンドルの配列

ところで現状Player::Draw_Update()では左右にキーが入力されているときのみ描画するようですが、これだと静止しているときに何も描画されないのでは?つねに何かは描画する必要があるでしょう。なぜなら通常

  1. 画面クリア
  2. なんか描画
  3. 裏画面を表画面に転送

を繰り返すはずだからです。

まあ何れにせよPlayer::Draw_Update()ではキーの状態によってアニメーションクラスの状態を更新し画像ハンドルをもらい、描画する処理になりますね。

さて、そう考えるとおかしなことがあります。なぜPlayerがキーの状態を持つのでしょうか?責任が広すぎます。動くものが一つだけならぎりぎりわかりますがちょっと読みにくいです。別クラスに追い出して、必要なキー状態はメンバ関数の引数経由で教えることにしましょう。

投稿2019/08/07 11:41

編集2019/08/07 13:47
yumetodo

総合スコア5850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/08/11 07:50 編集

質問ですがキーの情報とはキー入力でしょうか?Animeの切り替えのためのキー情報でしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問