前提・実現したいこと
【環境】
Microsoft Visual Studio
Windows フォームアプリケーション(.NET Framework) C#
プログラミング学校の卒業制作で野球盤のようなゲームを制作しています。
g.FillEllipseで描画したボールをTimerを用いてY軸をずらしながら再描画することで飛ばし
配列に設置した10枚のバットの画像をパラパラ漫画のようにコマ送りする事で
バットのスイングを表現しています。
このバットの連続描画をカクカクせずできる限り高速で行いたいです。
発生している問題・エラーメッセージ
ボールが描画されていない状態でバットをスイングさせると
問題なく高速で画像が入れ替わるのですが
フォームに直接描かれた球がフォーム上を移動している時にスイングさせると
画像の入れ替え速度が遅くなりスロー再生のようになってしまいます。
(球の速度はスイング中でもほとんど変わりません)
該当のソースコード
C#
1ソースコード(処理に関連していそうなコードのみ抽出して貼り付けてあります) 2 3public partial class Form1 : Form 4 { 5 //【球の描画関連】 6 //----------------------------------------------------------- 7 private Ball[] ball = new Ball[1]; //表示する球の数 8 //----------------------------------------------------------- 9 //【バットスイング関連】 10 //------------------------------------------------------------------------------ 11 public int batSwingFlg = 0; //この数値が1の時にバットをアニメーションする 12 public int hitFlg = 0; //球がバットに当たったかどうかのフラグ 13 int count; //今何枚目かをカウントする変数 14 Image[] pic = new Image[10]; //用意した10個のコマ(bat0~9.png)を配列に設置 15 //------------------------------------------------------------------------------ 16 17public Form1() 18 { 19 int i; 20 InitializeComponent(); 21 22 //【座標と色のインスタンス作成】 23 //-------------------------------------------------- 24 Point p = new Point(); 25 Color c = new Color(); 26 //-------------------------------------------------- 27 28 // 【バットスイングのパラパラ】 29 // ファイル名末尾の数字が9になるまで 30 // 1ずつ末尾番号を増やしていく事で 31 // タイマーが進むごとに自動で1ページずつ送っていく 32 //-------------------------------------------------------------------------- 33 34 for (int n = 0; n < pic.Length; n++) 35 { 36 pic[n] = Image.FromFile 37 (@"....\Resources\bat" + n + ".png"); 38 } 39 //-------------------------------------------------------------------------- 40 41 42 //【球の初期設定】 43 //-------------------------------------------------------------------------- 44 for (i = 0; i < ball.Length; i++) 45 { 46 //球の初期座標 47 p.X = pitcher.Left + 30; 48 p.Y = pitcher.Top; 49 //球の色 50 c = Color.FromArgb(255, 255, 255, 255); 51 52 //球のインスタンス 53 ball[i] = new Ball(); 54 ball[i].cond = 0; //球のステータス(1の時に球を描画) 55 ball[i].point = p; //球の座標取得 56 ball[i].color = c; //球の色取得 57 58 //球の移動量(初期値) 59 ball[i].movX = 0; //横軸(今回は角度なし) 60 ball[i].movY = 20; //縦軸(球の速度) 61 } 62 } 63private void Form1_Load(object sender, EventArgs e) 64 { 65 // 画面のちらつき防止 66 this.SetStyle(ControlStyles.DoubleBuffer, true); 67 this.SetStyle(ControlStyles.UserPaint, true); 68 this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); 69 } 70private void timer1_Tick(object sender, EventArgs e) 71 { 72 //球の判定の移動速度タイマー 73 int i; 74 Point p; 75 for(i = 0; i < ball.Length; i++) 76 { 77 if (hitFlg == 1) //もし球がスイング中のバット判定に命中した場合 78 { 79 p = ball[0].point; 80 p.Y = p.Y - ball[0].movY; //球の進行方向を反転させる 81 ball[0].point = p; 82 } 83 else //それ以外はY軸正方向へ進む 84 { 85 p = ball[0].point; //球の位置変数 86 p.X = p.X + ball[0].movX; //球の横軸移動量 87 p.Y = p.Y + ball[0].movY; //球の縦軸移動量 88 ball[0].point = p; //球の位置情報書き換え 89 } 90 } 91 this.Invalidate(); //ここで再描画処理 92 } 93private void timer4_Tick(object sender, EventArgs e) 94 { 95 //バットのアニメーションタイマー 96 //bat.ImageのbatはPictureBoxの名前(name) 97 if (batSwingFlg == 1) 98 { 99 bat.Image = pic[count]; 100 count++; 101 if(count == 10) 102 { 103 // 最後のページ(10枚目)までカウントが進んだら 104 // 最初のページ(1枚目)までカウントを戻し 105 // バットのスイングフラグもオフにする 106 batSwingFlg = 0; 107 count = 0; 108 bat.Image = pic[coun] 109 } 110 } 111 } 112private void Form1_Paint(object sender, PaintEventArgs e) 113 { 114 //描画処理関連 115 //最初に位置や色の変数を宣言 116 int i, j; 117 Point p = new Point(); 118 Color c = new Color(); 119 Graphics g = e.Graphics; 120 121 for(i = 0; i < ball.Length; i++) 122 { 123 if(ball[i].cond != 1) 124 { 125 //球のcond値が1以外の時は処理しない 126 continue; 127 } 128 for(j = 0; j < ball.Length; j++) 129 { 130 if (i == j || ball[i].cond != 0) 131 { 132 //同じ球の処理はしない 133 continue; 134 } 135 } 136 137 for(i = 0; i < ball.Length; i++) 138 { 139 p = ball[0].point; //球の座標データ取得 140 c = ball[0].color; //球の色データ取得 141 142 //球のcond値が1の場合のみ球を描画 143 if (ball[0].cond == 1) 144 { 145 SolidBrush br = new SolidBrush(c); 146 g.FillEllipse(br, p.X, p.Y, 12, 12); 147 } 148 } 149 150 //球がバットを通り抜けた時 151 if (ball[0].point.Y > (bat.Bottom - 10)) 152 { 153 //球のインデックスとcond値をリセットし 154 //球の位置をピッチャーの座標まで戻す 155 ball[0].cond = 0; 156 ball[0].point.X = pitcher.Left + 30; 157 ball[0].point.Y = pitcher.Top; 158 159 //球の移動タイマーをストップする 160 timer1.Stop(); 161 break; 162 } 163 164 //球が画面上端を通り抜けた時 165 else if(ball[0].point.Y < (label1.Top - 50)) 166 { 167 //同じく球位置とステータスのリセット 168 //ついでにhitFlgもオフにする 169 ball[0].cond = 0; 170 ball[0].point.X = pitcher.Left + 30; 171 ball[0].point.Y = pitcher.Top; 172 hitFlg = 0; 173 174 //球の動きを止める 175 timer1.Stop(); 176 break; 177 } 178 179 //球とバットの当たり判定 180 //Atariは当たり判定用の画像なしPictureBox 181 Point bp = new Point(); 182 bp = bat.Location; 183 if (Math.Abs(ball[0].point.Y ) >= (Atari.Top) 184 && (ball[0].point.Y) <= (Atari.Bottom) 185 && batSwingFlg == 1) 186 { 187 hitFlg = 1; 188 } 189 } 190 } 191private void Form1_MouseClick(object sender, MouseEventArgs e) 192 { 193 //ヒットフラグがオフの時にフォーム上で左クリックすると 194 //バットのスイングが始まる 195 if (e.Button == MouseButtons.Left && hitFlg == 0) 196 { 197 timer4.Start(); 198 batSwingFlg = 1; 199 } 200 } 201 } 202internal class Ball 203 { 204 public Point point; //表示位置 205 public Color color; //球の色 206 public int cond; //球のステータス 207 public int movX; //X軸移動量 208 public int movY; //Y軸移動量 209 }
試したこと
最初はバットの画像を絶対パスを指定する事で取得していましたが
リソースに入れる事で処理の手間を減らしました。
また、画像枚数も21枚あったものを半数以下の10枚まで減らしました。
それでも球の描画とバットのスイングを同時にしようとすると
バットのみ処理が遅れてしまいます。
おそらく根本的な描画方法に問題があるのかもしれませんが
当方初心者の為それも含めて効率的な描画方法をわかりやすく教えていただけると幸いです。
補足情報(FW/ツールのバージョンなど)
あくまでC#とWindowsフォームアプリケーションを使って作成するという条件の課題なので
直接UnityやXamarin、WPFを使うことはできません(これらと互換性のあるコードの流用は可)
厄介な縛りかもしれませんがよろしくお願いします。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。