美文网首页
大三上学期c#结课项目《经典游戏》—— 推箱子

大三上学期c#结课项目《经典游戏》—— 推箱子

作者: 木羽 | 来源:发表于2020-01-04 22:49 被阅读0次

经典游戏

c#这科是由赵大伟老师教的,并且打分方式是根据这个项目。而我素来对游戏比较感兴趣,而且Visual Studio操作很方便,所以当知道需要做一个结课项目的时候,我就开始构思制作一个游戏了。

  • 使用语言:c#
  • 制作工具:·Visual Studio 2010·

推箱子

推箱子
游戏规则:通过键盘控制移动我的箱子,并且在碰撞到其他箱子的时候,与被撞到的箱子一起移动。而在撞到地形的时候,则不能移动,当目标箱子到达指定底线,游戏结束。
思路:整体显示用PictureBox控件显示图片,然后通过键盘进行操作。

移动

  • 在构思的时候,一个游戏,我首先想到的是移动问题。
    在窗体程序里,显示一个我能控制的箱子,然后移动它,在这里我用到了PictureBox的控件。更改了他的背景颜色和名字(myBox)。
我的箱子
  • 然后就要移动这个箱子了,在学习的时候,学习过textBox的keyDown事件,我想能不能用这种方法控制图片的移动,但是PictureBox并没有这个事件,所以用了一个取巧的方法,

设置一个textBox控件,用键盘的keyDown事件控制textBox的移动,并且在移动事件里控制PictureBox的位置与textBox的位置一致,并且,PictureBox始终在textBox的上方将其盖住。

下面是源代码,以向左移动为例子


用到的两个控件
  private void textBox1_KeyDown(object sender, KeyEventArgs e)
        {
            //设置移动距离
            int rightLocal = myBox.Width - 1;
            int bottomLocal = myBox.Width + 2;
            //用switch语句判断键盘按下的是哪个键
            switch (e.KeyCode)
            {
                case Keys.Left:
                    //检查碰撞 没撞到的情况下返回的是true
                    if (checkLeftCrash(myBox))
                    {
                        //向左移动textBox1
                        textBox1.Left = textBox1.Left - rightLocal;
                        //判断是否撞到箱子
                        if (checkBoxLeftCrash(rightLocal, targetBox1, targetBox2))
                        {
                            //判断能不能移动目标箱子,如果可以,直接移动
                            checkLeftMove(rightLocal, targetBox1);
                        }
                        else
                        {
                            //将textBox1的位置调整回来
                            textBox1.Left = textBox1.Left + rightLocal;
                            break;
                        }
                        if (checkBoxLeftCrash(rightLocal, targetBox2, targetBox1))
                        {
                            checkLeftMove(rightLocal, targetBox2);
                        }
                        else
                        {
                            textBox1.Left = textBox1.Left + rightLocal;
                            break;
                        }
                    }
                    break;
              }
            myBox.Left = textBox1.Left;
            myBox.Top = textBox1.Top;
            showBuShu();
            showStatus();
            checkSuccess();
        }

地图设置

  • 而后,我建立了地图,用方法比较笨拙,从设计页面挨个设置了每一个pictureBox,然后向PictureBox中添加地图的图片。其实可以用更简便的方法,从代码load事件中,foreach遍历添加PictureBox。

难点

  • 在设置地图的时候,我发现在设计视图中设定的Size值,与在代码里的width,与height是不同的。
    例如,设置size为50,50 然而width和height会变成其他比较奇怪的值。这对后面的碰撞验证造成了影响。
    设计页面添加pictureBox的缺点再次体现,用代码生成将会避免此缺陷。

碰撞检测

  • 碰撞检测一共分为三类

地图边缘检测

  • 这部分的检测比较简单,只需要检测,四面最边缘的墙壁。

其他墙面检测

  • 其他墙面的检测,则需要挨个写入墙的位置。很麻烦,很蠢。
    下面是代码
//以向上为例
public Boolean checkUpCrash(PictureBox box)
        {
            Boolean b = true;
            //边缘
            if (box.Top == 40)
            {
                b = false;
            }
            //其他墙
            if ((box.Top == 80 && box.Left == 259) || (box.Top == 80 && box.Left == 296) || (box.Top == 120 && box.Left == 37) || (box.Top == 120 && box.Left == 111) || (box.Top == 120 && box.Left == 148) || (box.Top == 120 && box.Left == 185))
            {
                b = false;
            }
            return b;
        }
  • 在被这蠢方法折磨后,我想到了一个稍微聪明点的想法。
    如果当时墙壁是用代码生成的,那么也就可以生成一个墙壁,就把这个墙壁的位置放到一个数组里,当需要位置碰撞的判定时,遍历数组然后判断即可。

目标箱子碰撞检测

  • 先判断我的箱子移动后,位置是否与目标箱子重叠。如果重叠,则可以推这个箱子。
  • 接下来判断目标箱子移动后,是否会碰撞到墙。如果会碰撞到墙,那么此次移动不生效,将位置数值回调。
    实例代码
//此处以向右为例
//向右推箱子
        public void checkRightMove(int local,PictureBox box)
        {
            if (myBox.Left + local >= box.Left)
            {
                //判断是否碰撞
                if (box.Top < myBox.Top || box.Top > myBox.Top || box.Left < myBox.Left)
                {
                    //没碰撞则什么都不做
                }
                else
                {
                    //目标箱子的位置就更改为我的箱子的位置+两倍的移动长度
                    if (checkRightCrash(box))
                    {
                        //目标箱子移动
                        box.Left = myBox.Left + local * 2;
                    }
                    else
                    {
                        //位置回调
                        textBox1.Left = textBox1.Left - local; 
                    }
                }
            }
        }
  • 还有一种情况,则是两个目标箱子紧挨着的时候,这时碰撞,也不能移动。
    代码
 //检查两个箱子紧挨时向右的碰撞
        public Boolean checkBoxRightCrash(int local,PictureBox Fbox,PictureBox Sbox)
        {
            Boolean b = false;
            //判断是否碰撞
            if (myBox.Left + local != Fbox.Left || myBox.Top!=Fbox.Top)
            {
                b = true;
            }
            else
            {
                if (Fbox.Left + local != Sbox.Left || Fbox.Top != Sbox.Top)
                {
                    b = true;
                }
            }
            return b;
        }

胜利判断

当所有目标箱子都到达指定区域的时候,游戏结束,并提示恭喜过关。

//胜利判断
        public void checkSuccess()
        {
            if (((success1.Left == targetBox1.Left && success1.Top == targetBox1.Top) || (success2.Left == targetBox1.Left && success2.Top == targetBox1.Top)) && ((success1.Left == targetBox2.Left && success1.Top == targetBox2.Top) || (success2.Left == targetBox2.Left && success2.Top == targetBox2.Top)))
            {
                MessageBox.Show("恭喜你,过关了!");
                timer1.Stop();
                String conStr = "provider=microsoft.jet.oledb.4.0;data source=fx.mdb";
                OleDbConnection conn = new OleDbConnection(conStr);
                conn.Open();
                String sql = "insert into ranklist(username,[time],stepnum) values('"+Login.username+"',"+time+","+bushu+")";
                OleDbCommand cmd = new OleDbCommand(sql, conn);
                if (cmd.ExecuteNonQuery() > 0)
                {
                    MessageBox.Show("添加记录成功");
                }
                textBox1.Enabled = false;
                textBox1.Focus();
            }
        }

不足总结

  1. 地图的设置过于麻烦,可以通过foreach简化。
  2. 在设计页面添加PictureBox,细节不够准确,会对游戏的运行有影响。
  3. 通过使用数组来简化碰撞检测。
  4. 写方法时,Boolean值设置混乱,有的是碰撞到了是true,有的是碰撞到了是false,应该统一!
  5. 检测多个箱子紧挨着的时候,写法过于笨拙,应考虑更加实用的方法。

相关文章

网友评论

      本文标题:大三上学期c#结课项目《经典游戏》—— 推箱子

      本文链接:https://www.haomeiwen.com/subject/owwxactx.html