Contents
地形をつくる
ゲーム・スクランブルでは地形があります。最初にでてくる地形はこんな感じ。山あり谷ありで地上部分にはミサイルや燃料タンクが設置されています。地上構造物は後回しにして地形(の一部)だけ作成します。
幅は45ブロックで高さは15ブロックです。
それではこれを利用してみましょう。
□は空白部分、■は地面、▲は登りの傾斜、△は下りの傾斜がある部分とします。サイズは20ピクセルとします。
Topographyクラスの作成
地形を描画するためのクラスを作成します。
まずはコンストラクタから。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Topography { protected Form1 MainForm = null; public Topography(Form1 form) { MainForm = form; } public Topography() { } } |
ブロックの大きさは20×20ピクセルです。地形を表現するための文字列をフィールド変数として用意します。これをforeach文で処理するのでリストに変換します。これをするために作成したのがGetListTopography()メソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
class Topography { // ブロックの大きさは20×20ピクセルとする static Size blockSize = new Size(20, 20); public static Size BlockSize { get { return blockSize; } } string topography0 = "□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□"; string topography1 = "□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□"; string topography2 = "□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□"; string topography3 = "□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□"; string topography4 = "□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□"; string topography5 = "□□□□□□□□□□▲△□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□"; string topography6 = "□□□□□□□□□▲■■△□□□□□□□□□□□□□□□□▲△□□□□□□□□□□□□□□"; string topography7 = "□□□□□□□□▲■■■■△□□□□□□□□□□□□□□▲■■△□□□□□□□□□□□□□"; string topography8 = "□□□□□□□▲■■■■■■△□□□□□□□□□□□□▲■■■■△□□□□□□□□□□□□"; string topography9 = "□□□□□□▲■■■■■■■■■■■■■■■■■■■■■■■■■■△□□□□□□□□□□□"; string topography10 = "■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■△□□□□□□□□□□"; string topography11 = "■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■△□□□□□□□□□"; string topography12 = "■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■"; string topography13 = "■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■"; string topography14 = "■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■"; List<string> GetListTopography() { List<string> vs = new List<string>(); vs.Add(topography0); vs.Add(topography1); vs.Add(topography2); vs.Add(topography3); vs.Add(topography4); vs.Add(topography5); vs.Add(topography6); vs.Add(topography7); vs.Add(topography8); vs.Add(topography9); vs.Add(topography10); vs.Add(topography11); vs.Add(topography12); vs.Add(topography13); vs.Add(topography14); return vs; } } |
あとはこれをForm1クラスのイベントハンドラPanel1_Paint内で処理できるようにするだけです。Topography.Show(Graphics g)メソッドで表示させます。▲なら上り坂、△なら下り坂です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
class Topography { Point[] GetTreePointsUphill() { List<Point> pts1 = new List<Point>(); pts1.Add(new Point(blockSize.Width, 0)); pts1.Add(new Point(0, blockSize.Height)); pts1.Add(new Point(blockSize.Width, blockSize.Height)); return pts1.ToArray(); } Point[] GetTreePointsDownhill() { List<Point> pts1 = new List<Point>(); pts1.Add(new Point(0, 0)); pts1.Add(new Point(0, blockSize.Height)); pts1.Add(new Point(blockSize.Width, blockSize.Height)); return pts1.ToArray(); } // 上からぶら下がっている地形 protected Point[] GetTreePointsUphillUpperSide() { List<Point> pts1 = new List<Point>(); pts1.Add(new Point(0, 0)); pts1.Add(new Point(blockSize.Width, 0)); pts1.Add(new Point(blockSize.Width, blockSize.Height)); return pts1.ToArray(); } protected Point[] GetTreePointsDownhillUpperSide() { List<Point> pts1 = new List<Point>(); pts1.Add(new Point(0, 0)); pts1.Add(new Point(blockSize.Width, 0)); pts1.Add(new Point(0, blockSize.Height)); return pts1.ToArray(); } public void Show(Graphics g) { SolidBrush brush = new SolidBrush(Color.Red); List<string> listTopography = GetListTopography(); Point[] UphillTreePoints = GetTreePointsUphill(); Point[] DownhillTreePoints = GetTreePointsDownhill(); Point[] UphillUpperSideTreePoints = GetTreePointsUphillUpperSide(); Point[] DownhillUpperSideTreePoints = GetTreePointsDownhillUpperSide(); int displacement = MainForm.Jiki.Displacement; int y = 0; foreach(string str in listTopography) { Char[] vs = str.ToArray(); int x = 0; foreach(Char c in vs) { if(c == '■') { g.FillRectangle(brush, new Rectangle(new Point(x * blockSize.Width - displacement, y * blockSize.Height), blockSize)); } if(c == '▲') { Point[] pts = UphillTreePoints.Select(x1 => { x1.X += x * blockSize.Width; x1.Y += y * blockSize.Height; return x1; }).ToArray(); pts = pts.Select(x1 => { x1.X -= displacement; return x1; }).ToArray(); g.FillPolygon(brush, pts); } if(c == '△') { Point[] pts = DownhillTreePoints.Select(x1 => { x1.X += x * blockSize.Width; x1.Y += y * blockSize.Height; return x1; }).ToArray(); pts = pts.Select(x1 => { x1.X -= displacement; return x1; }).ToArray(); g.FillPolygon(brush, pts); } if(c == '▼') { Point[] pts = UphillUpperSideTreePoints.Select(x1 => { x1.X += x * blockSize.Width; x1.Y += y * blockSize.Height; return x1; }).ToArray(); pts = pts.Select(x1 => { x1.X -= displacement; return x1; }).ToArray(); g.FillPolygon(brush, pts); } if(c == '▽') { Point[] pts = DownhillUpperSideTreePoints.Select(x1 => { x1.X += x * blockSize.Width; x1.Y += y * blockSize.Height; return x1; }).ToArray(); pts = pts.Select(x1 => { x1.X -= displacement; return x1; }).ToArray(); g.FillPolygon(brush, pts); } x++; } y++; } } } |
ところでこれを描画しようとすると画面がチラチラします。そこでダブルバッファを使用したいのですが、DoubleBufferedプロパティはProtectedなので外部からは設定できません。そこでPanelを継承してPanelExクラスを作成します。これによってForm1クラスが若干変更されます。
まず、継承され新しく作成されたPanelExクラスです。
1 2 3 4 5 6 7 |
public class PanelEx : Panel { public PanelEx() { this.DoubleBuffered = true; } } |
Form1クラスのコンストラクタでPanelExとTimerを初期設定をしています。
1 2 3 4 5 6 7 8 9 10 |
public partial class Form1 : Form { public Form1() { InitializeComponent(); InitPanelEx(); InitTimer(); } } |
初期設定の内容ですが、フォームのサイズを変更すればPanelExのサイズも自動で変更できるようにしました。それから背景を黒にして、Paintイベントが発生した場合はイベントハンドラPanelEx1_Paintが呼び出されるようにしています。
一方、タイマーはIntervalプロパティを50に設定してTickイベントに対してイベントハンドラTimer_Tickが呼び出されるようにしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public partial class Form1 : Form { void InitPanelEx() { panelEx1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; panelEx1.BackColor = Color.Black; panelEx1.Paint += PanelEx1_Paint; } void InitTimer() { Timer.Interval = 50; Timer.Tick += Timer_Tick; } } |
ではイベントハンドラではどのような処理をしているのでしょうか?
Jiki.Showメソッドを呼び出すことで、自機を表示させる必要がある場合は表示されるようにすると同時に、地形も表示させることができるようにしています。
1 2 3 4 5 6 7 8 |
public partial class Form1 : Form { private void PanelEx1_Paint(object sender, PaintEventArgs e) { Jiki.Show(e.Graphics); Topography.Show(e.Graphics); } } |
一応、これで地形が表示されるようになったのですが、動きません。これではゲームにならないので、次回は自機を移動させることで地形が前から後ろに移動してみえるようにします。