VC# ExpressでWindows Mobile開発 (2)に参加しました

先週(11/15)のことで遅ればせのレポートですが前回に引き続き、七誌さん主催の「VC# ExpressでWindows Mobile開発 (2)」に参加しました

第2回では第1回で作成途中だったものを引き続き作成しました
作っていたものは簡単なゲームです
0〜9までの数字が4回点滅するので、続けてその数字をタッチします
前回ではその数字をボタンコントロールで実装していましたが、今回はGraphicで描画するようにしました


できればそのときに配布された資料にあったダブルバッファリングで描画するようにしたかったのですが、
残念ながらそこもまではたどり着けませんでした


とりあえずボタンの色がポップな感じになったのでよしとしましょう



fslashtさんがDroid端末ゲームをWinMo端末をJoystickにして動かしていたのは面白かった
まともな速度でJoystickの入力に反応していて実用になっていました


それにしても携帯端末2台使って自作ゲームとは、なんとういう贅沢!!


fslashtのブログの方でも今回の勉強会のレポートされてて
写真がいっぱいで様子がよくわかってこっちよりいいですねw



また今回から参加された方もいて、質問を受けたりしていました
みんなで集まって作っていると、あーでもない、こーでもない言いながら開発できて楽しいですね
「勉強会というより合宿だ」と誰かが言っていた気がしますが、まさにそうでした



とりあえず作ったゲームのソースをまとめて↓に掲載しました
まずい、消すの忘れてる部分がある....orz

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.IO;

namespace wmee
{
    public class Status
    {
        public int AsCount;
        public string[] Qs = new string[5];
        public string[] As = new string[5];
        public int Score = 0;

        public Status()
        {
            Clear();
        }

        public void Clear()
        {
            AsCount = 0;
            ClearArray(Qs);
            ClearArray(As);
        }

        public void ClearArray(string[] ss)
        {
            for (int i = 0; i < ss.Length; i++)
            {
                ss[i] = " " + "_";
            }
        }

        public void SetA(string s)
        {
            if (AsCount >= As.Length) return;
            As[AsCount] = " " + s;
            AsCount++;
        }

        public string ToInline(string[] ss)
        {
            StringBuilder b = new StringBuilder();
            for (int i = 0; i < ss.Length; i++)
            {

                b.Append(ss[i]);
            }
            return b.ToString();
        }

        public bool IsMatch(int idx)
        {
            if (idx < 0 || idx >= Qs.Length) return false;
            return Qs[idx].Trim() == As[idx].Trim();
        }

        public string GetQs(int idx)
        {
            if (idx < 0 || idx >= Qs.Length) return "";
            return Qs[idx].Trim();
        }

        public override string ToString()
        {
            return ToInline(Qs) + " | " + ToInline(As) + " | Score: " + Score.ToString();
        }
    }

    public class MyPanel
    {
        public Rectangle Bounds;
        public Brush Bg;
        public Brush Fore;
        public string Text;
    }

    public class MyButton
    {
        public Rectangle Bounds;
        public Brush Bg;
        public Brush Fore;
        public string Text;
        public string Clicks;
        public Brush ClickBrush;
    }

    public partial class Form1 : Form
    {
        public Form1()
        {
            Text = "アプリ";
            Size = new Size(240, 320);
            MinimizeBox = false;
            SuspendLayout();
            AutoScaleDimensions = new SizeF(96, 96);
            // emobile S21HT だと AutoScaleMode.Inheritにしないと画面サイズに調整されなかった
//            AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
            AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
            Menu = new MainMenu();
            InitializeComponent();       
            ResumeLayout(false);
        }

        enum Phase { Splash, Play, Farewell }
        enum State { Presentaion, Input }

        private MyButton[] bs = new MyButton[9];
        private Label StateLabel;

        private Random rnd;

        private State ThisState;
        private int TickCount;
        private List<string> Qs;
        private List<string> As;
        private Status Status;
        private Font LFont;
        private Font MFont;
        private Font SFont;
        private Brush OrgBrush;
        private MyButton prevBtn2;
        private Brush BlinkBrush;
        private MyPanel Splash;
        private Phase ThisPhase = Phase.Splash;
        private int Round = 1;
        private int RoundMax = 5;
        private int Ticks = 4;

        private void InitializeComponent()
        {
            LFont = new System.Drawing.Font("MS ゴシック", 45.0F, FontStyle.Bold);
            MFont = new System.Drawing.Font("MS ゴシック", 20.0F, FontStyle.Bold);
            SFont = new System.Drawing.Font("MS ゴシック", 15.0F, FontStyle.Bold);
            
            MyButton b;
            Brush fore, regular0, regular1, br, clickBrush;
            fore = new SolidBrush(Color.Green);
            regular0 = new SolidBrush(Color.LightYellow);
            regular1 = new SolidBrush(Color.LightCoral);
            BlinkBrush = new SolidBrush(Color.Yellow);
            clickBrush = new SolidBrush(Color.LightGreen);
            OrgBrush = regular0;
            BackColor = Color.LightYellow;

            Splash = new MyPanel();
            int unit = 11;
            Splash.Bounds = new Rectangle(Width / unit, Height / unit, Width * (unit - 2) / unit, Height * (unit - 2) / unit);
            Splash.Bg = regular0;
            Splash.Fore = new SolidBrush(Color.Black);
            Splash.Text = 
@"数字が" + Ticks + @"回点滅するので、続けてその数字をタッチして下さい

チャンスは" + RoundMax + @"回

画面をタッチでゲームスタート
";

            int idx;
            int size;
            int x, y, w, h;

            size = Width / 3;
            for (int r = 0; r < 3; r++)
            {
                for (int c = 0; c < 3; c++)
                {
                    b = new MyButton();
                    x = c * size;
                    y = r * size;
                    w = size;
                    h = size;


                    idx = c + r * 3;


                    br = (r * 3 + c) % 2 == 0 ? regular0 : regular1;
                    b.Bounds = new Rectangle(x, y, w, h);
                    b.Bg = br;
                    b.Fore = fore;
                    b.Text = "" + idx;
                    b.Clicks = "";
                    b.ClickBrush = clickBrush;
                    bs[idx] = b;
                }
            }

            prevBtn2 = bs[0];

            StateLabel = new Label();
            StateLabel.Left = 0;
            StateLabel.Top = size * 3;
            StateLabel.Width = Width;
            StateLabel.Text = "";

            Controls.Add(StateLabel);

            rnd = new Random(DateTime.Now.Millisecond);
            ThisState = Form1.State.Presentaion;
            TickCount = 0;
            Qs = new List<string>();
            As = new List<string>();
            Status = new Status();
            Status.As = new string[Ticks];
            Status.Qs = new string[Ticks];
            Status.Clear();
        }

        private Timer timer;

        private void PrepareTimer()
        {
            timer = new Timer();
            timer.Interval = 700;
            timer.Tick += new EventHandler(timer_Tick);
        }

        protected override void OnClick(EventArgs e)
        {
            if (ThisPhase == Phase.Splash)
            {
                ThisPhase = Phase.Play;
                Invalidate();
                PrepareTimer();
                timer.Enabled = true;
                return;
            }

            if (ThisPhase == Phase.Farewell)
            {
                Close();
                return;
            }


            MyButton b;
            for (int i = 0; i < bs.Length; i++)
            {
                b = bs[i];
                if (false == b.Bounds.Contains(PointToClient(MousePosition))) continue;

                As.Add(b.Text);
                Status.SetA(" " + b.Text);
                b.Clicks += "●";
                Invalidate(b.Bounds);
                break;
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            Graphics g;
            g = e.Graphics;
            if (ThisPhase == Phase.Play)
            {
                MyButton b;
                for (int i = 0; i < bs.Length; i++)
                {
                    b = bs[i];
                    g.FillRectangle(b.Bg, b.Bounds);
                    g.DrawString(b.Clicks, MFont, b.ClickBrush, b.Bounds);
                    g.DrawString(b.Text, LFont, b.Fore, b.Bounds.X + 15, b.Bounds.Y + 15);
                }
                return;
            }

            if (ThisPhase == Phase.Splash || ThisPhase == Phase.Farewell)
            {
                g.FillRectangle(Splash.Bg, Splash.Bounds);
                g.DrawString(Splash.Text, SFont, Splash.Fore, Splash.Bounds);
                return;
            }
        }

        void ClearButtons()
        {
            MyButton b;
            for (int i = 0; i < bs.Length; i++)
            {
                b = bs[i];
                b.Clicks = "";
            }
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            Rectangle r1, r2;
            prevBtn2.Bg = OrgBrush;
            r1 = prevBtn2.Bounds;
            r2 = Rectangle.Empty;

            if (TickCount >= Ticks)
            {
                if (ThisState == State.Presentaion)
                {
                    // to input
                    ThisState = State.Input;
                }
                else
                {
                    // to presentation
                    Round += 1;
                    ThisState = State.Presentaion;
                    Qs.Clear();
                    As.Clear();
                    Status.Clear();
                    ClearButtons();
                    if (Round > RoundMax)
                    {
                        ThisPhase = Phase.Farewell;
                        timer.Enabled = false;
                        Splash.Text = "" + Status.Score + @"点でした


おしまい";
                    }
                    Invalidate();

                }
                TickCount = 0;
            }

            if (ThisState == State.Presentaion)
            {
                int idx;
                idx = rnd.Next(9);
                prevBtn2 = bs[idx];
                OrgBrush = prevBtn2.Bg;
                prevBtn2.Bg = BlinkBrush;
                r2 = prevBtn2.Bounds;

                Status.Qs[TickCount] = " " + " " + idx.ToString();

                Qs.Add(idx.ToString());
            }
            else
            {
                MyButton b;
                b = bs[int.Parse(Status.GetQs(TickCount))];
                int pos;
                if ((pos = b.Clicks.IndexOf("●")) >= 0)
                {
                    b.Clicks = b.Clicks.Remove(pos, 1)
                                        .Insert(pos, "○");
                    Invalidate(b.Bounds);
                    Status.Score++;
                }

                if (Status.IsMatch(TickCount))
                {
                    Status.As[TickCount] = " ○";
                }
                else
                {
                    Status.As[TickCount] = " ×";
                }
            }

            Invalidate(r1);
            if (r2 != Rectangle.Empty) Invalidate(r2);

            TickCount++;
        }
    }

}