net: [[../BehaviorTracking/else/笔记系统构建]]

实验九

完成捉猴子游戏的设计与开发,实现以下基本功能:

(1) 小猴子随机出现在某个位置;

(2) 在一个给定的时间内,玩家可以用鼠标左键来点击该猴子,若击中,则该小猴子立即“变脸”;

(3) 在给定时间结束时,若玩家还没有击中,该小猴子就会逃走,随机出现在另外的位置……;

(4) 利用菜单开始游戏、设置猴子数量和时间间隔。

(5) 给游戏添加背景音乐和音效。

实验过程

  1. 设计UI界面,包括游戏主窗体及菜单项,并添加必要的控件,如Label、Button等。

    2. 设计一个猴子类,包括以下几个属性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

class Monkey

    {

        public int X { get; set; } // 猴子X坐标

        public int Y { get; set; } // 猴子Y坐标

        public bool IsCaptured { get; set; } // 是否被抓住

        public Image FreeImage { get; set; } // 自由状态下的猴子图片

        public Image CapturedImage { get; set; } // 被抓住状态下的猴子图片

    }

3. 进行一些初始变量的声明,包括猴子数量、时间间隔等

1
2
3
4
5
6
7
8
9

        private int monkeyCount = 1; //猴子数量

        private int timeInterval = 1000; //时间间隔,单位为毫秒

        private List<Monkey> monkeys = new List<Monkey>();

        private Timer timer = new Timer(); // 计时器

4. 对窗体进行一些初始化设置,具体代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

        public Form1()

        {

            InitializeComponent();

         }

        private void Form1_Load(object sender, EventArgs e)

        {

            InitializeComponent();

            timer.Interval = timeInterval;

            timer.Tick += timer_Tick;

        }

5. 定义生成猴子函数,用于相应数量的猴子生成,这里用到了tag将monkey类与picbox相关联。

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

        private void GenerateMonkeys(int num)

        {

            Random ran = new Random();

            for (int i = 0; i < num; i++)

            {

                Monkey monkey = new Monkey();

                monkey.FreeImage = Image.FromFile("monkey_normal.png");

                monkey.CapturedImage = Image.FromFile("monkey_hit.png");

                monkey.X = ran.Next(0, this.ClientSize.Width - monkey.FreeImage.Width);

                monkey.Y = ran.Next(0, this.ClientSize.Height - monkey.FreeImage.Height);

                monkeys.Add(monkey);

                PictureBox picBox = new PictureBox();

                picBox.Location = new Point(monkey.X, monkey.Y);

                picBox.Image = monkey.FreeImage;

                picBox.Size = new Size(monkey.FreeImage.Width, monkey.FreeImage.Height);

                picBox.Tag = monkey; // 将box与monkey关联

                picBox.Click += PicBox_Click;

                this.Controls.Add(picBox);

            }

        }

这里注意:要先将猴子的图片放在项目中的“游戏技术基础:实验九\游戏技术基础:实验九\bin\Debug”目录中

6. 利用picturebox的点击事件,检测鼠标左键的点击动作,判断是否击中猴子,并更新猴子的图案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

        private void PicBox_Click(object sender, EventArgs e)

        {

            PictureBox picBox = sender as PictureBox;

            Monkey monkey = picBox.Tag as Monkey;

            if (!monkey.IsCaptured)

            {

                monkey.IsCaptured = true;

                picBox.Image = monkey.CapturedImage;

                score.Text = (int.Parse(score.Text) + 1).ToString();

            }

        }

7. 设置定时器,控制猴子的移动与刷新

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

        private void timer_Tick(object sender, EventArgs e)

        {

            Random ran = new Random();

            foreach (var picBox in this.Controls.OfType<PictureBox>())

            {

                Monkey monkey = picBox.Tag as Monkey;

                if (!monkey.IsCaptured)

                {

                    // 随机更换坐标

                    monkey.X = ran.Next(0, this.ClientSize.Width - monkey.FreeImage.Width);

                    monkey.Y = ran.Next(0, this.ClientSize.Height - monkey.FreeImage.Height);

                    // 更新box的坐标

                    picBox.Location = new Point(monkey.X, monkey.Y);

                    picBox.Image = monkey.FreeImage;

                }

            }

        }

  1. 添加菜单项,实现游戏开始、重置猴子数量和时间间隔等功能,使用Dialog窗体进行设置。

7.1 开始游戏菜单设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

        private void 开始ToolStripMenuItem_Click(object sender, EventArgs e)

        {

            // 重置计分板

            score.Text = "0";

            // 删除所有猴子

            this.Controls.OfType<PictureBox>().ToList().ForEach(x => this.Controls.Remove(x));

            this.monkeys.Clear();

            // 重新生成猴子

            GenerateMonkeys(monkeyCount);

            timer.Start();

        }

7.2 猴子数量的菜单设置,这里新建了一个窗口用来接收猴子数量

#主窗口函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

        private void 猴子数量ToolStripMenuItem_Click(object sender, EventArgs e)

        {

            //设置猴子数量,使用Dialog窗体

            MonkeyCountDialog dlg = new MonkeyCountDialog(monkeyCount);

            if (dlg.ShowDialog() == DialogResult.OK)

            {

                monkeyCount = dlg.MonkeyCount;

                GenerateMonkeys(monkeyCount);

            }

        }

#新建窗口form2

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

    public partial class MonkeyCountDialog : Form

    {

        public int MonkeyCount { get; private set; }

        public MonkeyCountDialog(int count)

        {

            InitializeComponent();

            //初始化文本框

            txtCount.Text = count.ToString();

            txtCount.SelectAll();

            txtCount.Focus();

        }

        private void MonkeyCountDialog_Load(object sender, EventArgs e)

        {

        }

        private void button1_Click(object sender, EventArgs e)

        {

            //验证输入的猴子数量是否为有效数字

            if (int.TryParse(txtCount.Text.Trim(), out int count))

            {

                //猴子数量必须在1~10之间

                if (count >= 1 && count <= 10)

                {

                    MonkeyCount = count;

                    DialogResult = DialogResult.OK;

                    Close();

                }

                else

                {

                    MessageBox.Show("猴子数量应在1~10之间!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);

                    txtCount.Focus();

                    txtCount.SelectAll();

                }

            }

            else

            {

                MessageBox.Show("请输入有效的猴子数量!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);

                txtCount.Focus();

                txtCount.SelectAll();

            }

        }

    }

7.3 时间间隔菜单设置,与猴子数量的设置实现思路一致

#主窗口函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

        private void 时间间隔ToolStripMenuItem_Click(object sender, EventArgs e)

        {

            // 设置时间间隔,使用Dialog窗体

            TimeIntervalDialog dlg = new TimeIntervalDialog(timeInterval);

            if (dlg.ShowDialog() == DialogResult.OK)

            {

                timeInterval = dlg.TimeInterval;

                timer.Interval = timeInterval;

            }

        }

#新建窗口TimeIntervalDialog

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

    public partial class TimeIntervalDialog : Form

    {

        public int TimeInterval { get; private set; }

        public TimeIntervalDialog(int interval)

        {

            InitializeComponent();

            txtInterval.Text = interval.ToString();

            txtInterval.SelectAll();

            txtInterval.Focus();

        }

        private void button1_Click(object sender, EventArgs e)

        {

            //验证输入的时间间隔是否为有效数字

            if (int.TryParse(txtInterval.Text.Trim(), out int interval))

            {

                //时间间隔必须在1~10之间

                if (interval >= 1000 && interval <= 10000)

                {

                    TimeInterval = interval;

                    DialogResult = DialogResult.OK;

                    Close();

                }

                else

                {

                    MessageBox.Show("时间间隔应在1s~10s之间!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);

                    txtInterval.Focus();

                    txtInterval.SelectAll();

                }

            }

            else

            {

                MessageBox.Show("请输入有效的时间间隔!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);

                txtInterval.Focus();

                txtInterval.SelectAll();

            }

        }

    }

8. 最后在代码中添加播放背景音乐和音效的功能,同样需要把音效和音乐文件放在与图片文件相同的地方。

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

public partial class Form1 : Form

{

    private SoundPlayer captureSound;

    private SoundPlayer bgm;

    private void Form1_Load(object sender, EventArgs e)

    {

        // 加载音效

        captureSound = new SoundPlayer("capture.wav");

        // 添加背景音乐

        bgm = new SoundPlayer("bgm.wav");

        bgm.PlayLooping();

    }

    private void PicBox_Click(object sender, EventArgs e)

    {

        PictureBox picBox = sender as PictureBox;

        Monkey monkey = picBox.Tag as Monkey;

        if (!monkey.IsCaptured)

        {

            monkey.IsCaptured = true;

            picBox.Image = monkey.CapturedImage;

            score.Text = (int.Parse(score.Text) + 1).ToString();

            // 播放抓捕音效

            captureSound.Play();

        }

    }

实现效果:


References