C#基于图像碰撞检测的推箱子小游戏

所有游戏对象的父类代码

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 推箱子
{
    enum Direction //上下左右和无方向
    {
        Up,
        Down,
        Left,
        Right
    }
   /// <summary>
   /// 定义所有游戏对象的父类
   /// </summary>
    abstract class GameObject
    {
        #region   X,Y坐标 高宽 方向
        public int X
        {
            set;
            get;
        }
        
        public int Y
        {
            set;
            get;
        }

        public int Width
        {
            set;
            get;
        }

        public int Height
        {
            set;
            get;
        }

        public Direction Dir
        {
            get;
            set;
        }
        #endregion

        public GameObject(int x,int y,int height,int width,Direction dir)
        {
            this.X = x;
            this.Y = y;
            this.Height = height;
            this.Width = width;
            this.Dir = dir;
        }

        public abstract void Draw(Graphics g);
        public virtual void Move()
        {
            switch (Dir)
            {
                case Direction.Up:
                    this.Y -= 35;
                    break;
                case Direction.Down:
                    this.Y += 35;
                    break;
                case Direction.Left:
                    this.X -= 35;
                    break;
                case Direction.Right:
                    this.X += 35;
                    break;
                default:
                    break;
            }
        }
        /// <summary>
        /// 获取该游戏对象的矩形范围
        /// </summary>
        /// <returns></returns>
        public virtual Rectangle GetRectangle()
        {
            return new Rectangle(this.X, this.Y, this.Width, this.Height);
        }


        public Rectangle GetNextRe()
        {
            switch (Dir)
            {
                case Direction.Right:
                    return new Rectangle(this.X + this.Width, this.Y + this.Height / 2, 1, 1);
                case Direction.Left:
                    return new Rectangle(this.X - 1, this.Y + this.Height / 2, 1, 1);
                case Direction.Up:
                    return new Rectangle(this.X + this.Width / 2, this.Y - 1, 1, 1);
                case Direction.Down:
                    return new Rectangle(this.X + this.Width / 2, this.Y + this.Height, 1, 1);

            }
            return new Rectangle(this.X, this.Y, this.Width, this.Height);
        }

    }
}

玩家类代码

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 推箱子.Properties;
namespace 推箱子
{
    /// <summary>
    /// 玩家类
    /// </summary>
    class Player:GameObject
    {
        //玩家图片
        private static Image imgPlayer=Resources.player;  


      /// <summary>
        /// 初始化父类的属性并缩小图片尺寸
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="dir"></param>
        public Player(int x,int y,Direction dir):base(x,y,35,35,dir)
        { }

      /// <summary>
        /// 绘制当前人物并按照当前的朝向
        /// </summary>
        /// <param name="g"></param>
        public override void Draw(Graphics g)
        {
            switch (Dir)
            {
                case Direction.Right:
                    imgPlayer = Resources.player;
                    break;
                case Direction.Down:
                        imgPlayer = Resources.player;
                        RotateFlipType type = RotateFlipType.Rotate90FlipNone;
                        imgPlayer.RotateFlip(type);
                    break;
                case Direction.Left:
                        imgPlayer = Resources.player;
                        type = RotateFlipType.Rotate180FlipY;
                        imgPlayer.RotateFlip(type);
                    break;
                case Direction.Up:
                        imgPlayer = Resources.player;
                        type = RotateFlipType.Rotate270FlipNone;
                        imgPlayer.RotateFlip(type);
                    break;
            }
            g.DrawImage(imgPlayer, this.X,this.Y,this.Width,this.Height);
            Pen p = new Pen(Color.Blue, 2);//定义了一个蓝色,宽度为的画笔
            g.DrawRectangle(p, this.X, this.Y, this.Width, this.Height);
        }


        public int clikcnt = 0;

        public override void Move()
        {
            if (clikcnt == 2)
            {
                base.Move();
                clikcnt = 0;
            }

        }



    }
}

奖品类代码(被箱子盖住的)

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 推箱子.Properties;

namespace 推箱子
{
    class Reward:GameObject
    {
        public static Image imgRew=Resources.reward;
        public Reward(int x, int y) : base(x, y, 35, 35, Direction.Down)
        { }

        public bool IsOver
        {
            set;
            get;
        } = false;

        public override void Draw(Graphics g)
        {
            g.DrawImage(imgRew,this.X, this.Y, this.Width, this.Height);
        }
    }
}

箱子类代码

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 推箱子.Properties;
namespace 推箱子
{
    class Box : GameObject
    {
        public static Image imgBox=Resources.box;
        public Box(int x, int y) : base(x, y, 35, 35, Direction.Up)
        {}

        public bool ismove = false;

        public override void Draw(Graphics g)
        {
            g.DrawImage(imgBox,this.X, this.Y,this.Width,this.Height);
        }

    }
}

墙类代码

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 推箱子.Properties;
namespace 推箱子
{
    class Wall:GameObject
    {
        public static Image imgWall = Resources.wall;

        public Wall(int x, int y) : base(x, y, 35, 35, Direction.Down)
        { }
        public override void Draw(Graphics g)
        {
            g.DrawImage(imgWall, this.X, this.Y, this.Width, this.Height);
        }
    }
}

单例设计模式的单例类代码

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 推箱子
{
    class SingleObject
    {
        //单例设计模式
        //1、构造函数私有化
        private SingleObject()
        { }
        //2、声明全局唯一的对象
        private static SingleObject _single = null;
        //3、提供一个静态函数用于返回一个唯一的对象
        public static SingleObject GetSingle()
        {
            if (_single == null)
            {
                _single = new SingleObject();
            }
            return _single;
        }


        #region 游戏所有对象的声明
        public Player P1
            {
                get;
                set;
            }
        
        public List<Box> listBox = new List<Box>();
        public List<Wall> listWall = new List<Wall>();
        public List<Reward> listRew = new List<Reward>();
        #endregion


        //声明地图数组
       static int[,] map = new int[10, 10]
        {
         {0 ,0 ,0 ,1 ,1 ,1 ,1 ,0 ,0 ,0 },
         {0 ,0 ,0 ,1 ,0 ,0 ,1 ,0 ,0 ,0 },
         {1 ,1 ,1 ,1 ,0 ,0 ,1 ,0 ,0 ,0 },
         {1 ,0 ,0 ,0 ,0 ,0 ,1 ,0 ,0 ,0 },
         {1 ,0 ,2 ,2 ,0 ,0 ,1 ,0 ,0 ,0 },
         {1 ,0 ,0 ,0 ,0 ,0 ,1 ,0 ,0 ,0 },
         {1 ,0 ,0 ,0 ,0 ,0 ,1 ,1 ,1 ,1 },
         {1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,3 ,1 },
         {1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,3 ,1 },
         {1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 }
        };

        /// <summary>
        /// 按照map数组创建地图,1为墙 2为箱子 3为奖励
        /// </summary>
        public void CreatMap()
        {
            for(int i=0;i<10;i++)
            for(int j=0;j<10;j++)
                {
                    if (map[i, j] == 1) SingleObject.GetSingle().AddGameObject(new Wall(j * 35, i * 35));
                    if (map[i, j] == 2) SingleObject.GetSingle().AddGameObject(new Box(j * 35, i * 35));
                    if (map[i, j] == 3) SingleObject.GetSingle().AddGameObject(new Reward(j * 35, i * 35));
                }
        }


        /// <summary>
        /// 添加游戏对象的实例存入list
        /// </summary>
        /// <param name="go"></param>
        public void AddGameObject(GameObject go)
        {
            if (go is Player)
            {
                this.P1= go as Player;
            }
            if(go is Box)
            {
                listBox.Add(go as Box);
            }
            if (go is Wall)
            {
                listWall.Add(go as Wall);
            }
            if(go is Reward)
            {
                listRew.Add(go as Reward);
            }
        }

        /// <summary>
        /// 绘出所有游戏对象
        /// </summary>
        /// <param name="g"></param>
        public void Draw(Graphics g)
        {
            //绘画顺序不同 就会产生不同的覆盖效果,越最后画优先级越高,优先级越高就不会被覆盖
            for (int i = 0; i < listRew.Count; i++)
            {
                listRew[i].Draw(g);
            }

            this.P1.Draw(g);

            for (int i=0;i<listBox.Count;i++)
            {
                listBox[i].Draw(g);
            }
            for (int i = 0; i < listWall.Count; i++)
            {
                listWall[i].Draw(g);
            }


            if(SingleObject.GetSingle().IsPass())
            g.DrawString("顺利通关", new Font("宋体", 20, FontStyle.Bold), Brushes.Red, new Point(0, 0));

        }


        /// <summary>
        /// 检测人物当前朝向是否发生碰撞
        /// </summary>
        /// <returns></returns>
        public bool CheckP1()
        {
            for (int i = 0; i < listBox.Count; i++)
            {
                if (listBox[i].ismove) continue;
                if (listBox[i].GetRectangle().IntersectsWith(P1.GetNextRe()))
                {
                    return true;
                }
            }
            for (int i = 0; i < listWall.Count; i++)
            {
                if (listWall[i].GetRectangle().IntersectsWith(P1.GetNextRe()))
                {
                    return true;

                }
            }
            return false;
        }

        /// <summary>
        /// 检测箱子与墙,人物与箱子是否发生碰撞,
        /// </summary>
        public void CheckPZ()
        {
            //判断箱子
            for (int i = 0; i < listBox.Count; i++)
            {
                //判断奖励是否全部被挡住
                for (int j = 0; j < listRew.Count; j++)
                {
                    //如果有一个奖励没有被挡住 
                    if (listRew[j].GetRectangle().IntersectsWith(listBox[i].GetRectangle()))
                        listRew[j].IsOver = true;
                }

                //判断人物朝向是否有箱子存在,如果有就将箱子朝向=人物朝向
                if (listBox[i].GetRectangle().IntersectsWith(P1.GetNextRe())) listBox[i].Dir = P1.Dir; 

                //判断当前箱子朝向有无墙壁,是否可以继续移动  true:可以 false:不可以
                for (int j = 0; j < listWall.Count; j++)
                {
                    if (listBox[i].GetNextRe().IntersectsWith(listWall[j].GetRectangle()))
                    {
                        //只要有一个墙与箱子朝向相接就不能移动,直接跳出循坏
                        listBox[i].ismove = false;
                        break;
                    }
                    else
                    {
                        listBox[i].ismove = true;
                    }
                }
                //如果当前箱子朝向不能移动,跳出循环判断下一个箱子
                if (!listBox[i].ismove) continue;


                //判断当前箱子朝向有无其他箱子,是否可以继续移动  true:可以 false:不可以
                for (int j = 0; j < listBox.Count; j++)
                {
                    if (j == i) continue;//如果是箱子本身与本身进行判断则continue
                    if (listBox[i].GetNextRe().IntersectsWith(listBox[j].GetRectangle()))
                    {
                        //只要朝向有一个箱子相接就不能移动,直接跳出循坏
                        listBox[i].ismove = false;
                        break;
                    }
                    else
                    {
                        listBox[i].ismove = true;
                    }
                }

                //如果当前箱子朝向不能移动,跳出循环判断下一个箱子
                if (!listBox[i].ismove) continue;

                //这时箱子是可以移动的,当人物前进时箱子会同向移动
                if (listBox[i].GetRectangle().IntersectsWith(P1.GetRectangle()))
                {
                    listBox[i].Dir = P1.Dir;
                    listBox[i].Move();
                    listBox[i].ismove = false;//防止检测意外,人物出现移动bug(冲进箱子里)
                }
            }

      

        }


        /// <summary>
        /// 用于检测所有奖励是否被箱子盖住
        /// </summary>
        /// <returns></returns>
        public bool IsPass()
        {
            for(int i=0;i<listRew.Count;i++)
            {
                if (!listRew[i].IsOver) return false;
            }
            return true;
        }
    }
}

窗口界面事件代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 推箱子
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            InitialGame();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //在窗体加载的时候 解决窗体闪烁问题
            //将图像绘制到缓冲区减少闪烁
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.AllPaintingInWmPaint, true);

        }
        public void InitialGame()
        {
            SingleObject.GetSingle().AddGameObject(new Player(105, 105, Direction.Up));
            SingleObject.GetSingle().CreatMap();
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            SingleObject.GetSingle().Draw(e.Graphics);
         
        }


        /// <summary>
        /// 控制人物上下左右移动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Up)
            {
                //实现二次按压才会移动,第一次按键只会改变人物的朝向,当clickcnt为2时 才会move()
                SingleObject.GetSingle().P1.clikcnt = 0;
                if (SingleObject.GetSingle().P1.Dir == Direction.Up) SingleObject.GetSingle().P1.clikcnt = 1;
                SingleObject.GetSingle().P1.Dir = Direction.Up;
                SingleObject.GetSingle().P1.clikcnt++;

                //检测当前到朝向是否有不可移动的障碍物,发生碰撞时不能继续向前
                if (SingleObject.GetSingle().CheckP1())
                {
                    if (SingleObject.GetSingle().P1.Dir == Direction.Up) return;
                }
              SingleObject.GetSingle().P1.Move();
            }
            if (e.KeyCode == Keys.Down)
            {
                //实现二次按压才会移动,第一次按键只会改变人物的朝向,当clickcnt为2时 才会move()
                SingleObject.GetSingle().P1.clikcnt = 0;
                if (SingleObject.GetSingle().P1.Dir == Direction.Down) SingleObject.GetSingle().P1.clikcnt = 1;
                SingleObject.GetSingle().P1.Dir = Direction.Down;
                SingleObject.GetSingle().P1.clikcnt++;

                //检测当前到朝向是否有不可移动的障碍物,发生碰撞时不能继续向前
                if (SingleObject.GetSingle().CheckP1())
                {
                    if (SingleObject.GetSingle().P1.Dir == Direction.Down) return;
                }
                SingleObject.GetSingle().P1.Move();
            }
            if (e.KeyCode == Keys.Left)
            {
                SingleObject.GetSingle().P1.clikcnt = 0;
                if (SingleObject.GetSingle().P1.Dir == Direction.Left) SingleObject.GetSingle().P1.clikcnt = 1;
                SingleObject.GetSingle().P1.Dir = Direction.Left;
                SingleObject.GetSingle().P1.clikcnt++;
                if (SingleObject.GetSingle().CheckP1())
                {
                    if (SingleObject.GetSingle().P1.Dir == Direction.Left) return;
                }
                SingleObject.GetSingle().P1.Move();
            }
            if (e.KeyCode == Keys.Right)
            {
                SingleObject.GetSingle().P1.clikcnt = 0;
                if (SingleObject.GetSingle().P1.Dir == Direction.Right) SingleObject.GetSingle().P1.clikcnt = 1;
                SingleObject.GetSingle().P1.Dir = Direction.Right;
                SingleObject.GetSingle().P1.clikcnt++;
                if (SingleObject.GetSingle().CheckP1())
                {
                    if (SingleObject.GetSingle().P1.Dir == Direction.Right) return;
                }
                SingleObject.GetSingle().P1.Move();
            }
        }

        private void Timer1_Tick_1(object sender, EventArgs e)
        {
            this.Invalidate();
            SingleObject.GetSingle().CheckPZ();
            
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值