栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

WinForm —小鸡快跑游戏开发

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

WinForm —小鸡快跑游戏开发

首先,了解下WinForm做游戏的基本思路:

做游戏需要的最基本的两个元素,一个是屏幕,另一个就是在屏幕的移动的对象了。

然后,了解下parint事件,WinForm的对象都是继承至Control类的,而Control类中包含一个事件PaintEventHandler Paint,paint翻译过来就是喷绘,类似于绘画,当容器刷新时,就等于重新喷绘一次图像,就会触发此事件。

有了这些,就可以开始做游戏了。

先是定义一个元素(本文是小鸡),这个元素包含一张图片,和X坐标和Y坐标,然后将元素按其坐标,添加进屏幕(WinForm窗口或者其他容器,本文使用PictureBox)中,这样就屏幕就会在刚才定义的X坐标和Y坐标处,出现一个元素的图像。

然后,定义一个定时器timer,每30毫秒运行一次,每次运行都要刷新屏幕。自然屏幕刷新就会触发paint事件啦,本文中的paint事件为GamepictureBox_Paint

那么怎么移动小鸡呢?很简单,在定时器timer的事件里(本文为timer1_Tick)将元素的X坐标改变一下就可以了,然后timer里会进行容器刷新,容器刷新就会触发

paint事件,然后在paint事件里,重新定位下小鸡的X坐标就行了。

不多说了,上代码。

Form页面代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Chicken.Properties;

namespace Chicken
{
    public partial class MyG : Form
    {
 Element Chicken;//小鸡类
 Road GameRoad;//陆块类
 public int RoadCount;//陆块数
 public int Length;//陆块长度
 int EndX;//设置终点X
 EventHandler TimerHandler;//时间控制手柄
 bool TimerHandlerbool;//是否已传递时间手柄
 EventHandler AgainGame;//时间控制手柄
 int GamePicX;
 int GamePicY;
 public MyG()
 {
     InitializeComponent();

     Initial(20, Resources.Bird.Width + 10);//陆块长度为小鸡长度加10 50个陆块
 }

 private void Initial(int Rcount, int Len)
 {
     AgainGame += new EventHandler(AgainGame_Start);//实例化重新开始手柄
     TimerHandler += new EventHandler(Timer_Enabled);//实例化时间手柄
     RoadCount = Rcount;//陆块数
     Length = Len;//陆块长度
     TimerHandlerbool = false;//未已传递时间手柄
     Chicken = new Element(0, 100-Resources.Bird.Height);
     GameRoad = new Road(RoadCount, Len);
     GamePicX = 0;
     GamePicY = 0;
     Point p = new Point();
     p.Offset(GamePicX, GamePicY);
     GamepictureBox.Location = p;

 }
 private void InitialLand(Graphics g)
 {
     //Pen pen = new Pen(Color.Green);
     for (int i = 0; i < GameRoad.ListRoad.Count; i++)
     {
  RoadItem Item = GameRoad.ListRoad[i];
  if (Item.type == 1)//如果类型为1 是陆块是陆地
  {

      Image img = GameRoad.LandImgList[Item.imageIndex];

      g.DrawImage(img,
 new Rectangle(
  Item.start.X,
  Item.end.Y,
  Item.end.X - Item.start.X,
  img.Height
  )
   );//画陆块
  }
     }
     EndX = GameRoad.ListRoad.ElementAt(RoadCount - 1).end.X;//设置终点X
     this.GamepictureBox.Width = EndX;
 }
 /// 
 /// 时间控制函数
 /// 
 /// 
 /// 
 private void Timer_Enabled(object sender, EventArgs e)
 {
     TimerHandler -= new EventHandler(Timer_Enabled);
     timer1.Enabled = false;
     Dead D = new Dead(AgainGame);
     D.Show();
 }
 /// 
 /// 游戏开始控制函数
 /// 
 /// 
 /// 
 private void AgainGame_Start(object sender, EventArgs e)
 {
     AgainGame -= new EventHandler(AgainGame_Start);
     Initial(RoadCount, Length);
     timer1.Enabled = true;
 }

 private void timer1_Tick(object sender, EventArgs e)
 {
     //设置屏幕移动
     if ((Chicken.x + this.GamepictureBox.Location.X) > this.Width / 2 &&
  (this.GamepictureBox.Width + this.GamepictureBox.Location.X) > this.Width)
     {
  int OffX = 1;

  if (Chicken.IsSpeedUp)
  {
      OffX = 2;
  }
  GamePicX = GamePicX - OffX;

  Point p = GamepictureBox.Location;

  p.Offset(GamePicX, GamePicY);
  GamepictureBox.Location = p;

     }

     if (Chicken.x + Chicken.bmp.Width / 2 >= EndX)
     {
  timer1.Enabled = false;
  Replay R = new Replay(AgainGame);
  R.Show();

     }
     int CurrentRoadsIndex = Chicken.x / Length;//获取当前为第几个陆块
     if (CurrentRoadsIndex >= RoadCount) { CurrentRoadsIndex = RoadCount - 1; }//如果大于定义总陆块数 设置为最大数
     if (CurrentRoadsIndex < 0) { CurrentRoadsIndex = 0; }
     if (GameRoad.ListRoad.ElementAt(CurrentRoadsIndex).type == 0)//如果当前陆块为空 
     {
  // Y坐标等于空陆块Y坐标
  if ((Chicken.y + Chicken.bmp.Height) == GameRoad.ListRoad.ElementAt(CurrentRoadsIndex).start.Y)
  {
      int DepthEndX = GameRoad.ListRoad.ElementAt(CurrentRoadsIndex).end.X;//X下落点为当前陆块的X
      if (CurrentRoadsIndex + 1 <= RoadCount - 1)//如果下一个陆块存在
      {
   if (GameRoad.ListRoad.ElementAt(CurrentRoadsIndex + 1).type == 0)//如果下一个陆块也是空
   {
DepthEndX = GameRoad.ListRoad.ElementAt(CurrentRoadsIndex + 1).end.X;//X下落点为下一个陆块的X
   }
      }
      if (Chicken.x + Chicken.bmp.Width < DepthEndX)//对象的坐标加对象的宽度 小于空陆块的尾坐标
      {

   Chicken.IsFalling = true;//下降
   if (!TimerHandlerbool)
   {
Chicken.GetHandler(TimerHandler);//传递时间控制手柄
TimerHandlerbool = true;

   }
      }

  }

     }
     GamepictureBox.Refresh();

 }

 private void GamepictureBox_Paint(object sender, PaintEventArgs e)
 {
     Chicken.Draw(e.Graphics);
     InitialLand(e.Graphics);
 }

 private void MyG_KeyDown(object sender, KeyEventArgs e)
 {
     if (e.KeyData == Keys.Right)
     { Chicken.IsRuning = true; }
     if (e.KeyData == Keys.Space && Chicken.IsRuning)
     { Chicken.IsSpeedUp = true; }
     if (e.KeyData == Keys.Up)
     { Chicken.IsJumping = true; }
     int CurrentRoadsIndex = Chicken.point.X / Length;//当前陆块
     if (e.KeyData == Keys.Left)
     { Chicken.Back = true; }

 }

 private void MyG_KeyUp(object sender, KeyEventArgs e)
 {
     Chicken.IsRuning = false;
     Chicken.IsSpeedUp = false;
     Chicken.Back = false;
 }

 private void GamepictureBox_MouseDown(object sender, MouseEventArgs e)
 {
     Chicken.x = e.X;
     Chicken.y = e.Y;
 }
    }
}

元素类,定义几个变量来控制对象,注释还算比较多,就不一一解释了,如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using Chicken.Properties;

namespace Chicken
{
    class Element
    {
 public int x; 
 public int y;
 public int JumpHeight = 0;//跳跃高度 
 private bool JumpTop = false;//是否跳到最高点
 public int FallHeight = 0;//跳跃高度 
 public bool FallDepth = false;//是否跳到最高点
 public int BasicSpeed = 1;//基本速度
 public bool IsRuning = false;//是否移动
 public bool Back = false;//是否后退
 public bool IsJumping = false;//是否跳跃   
 public bool IsSpeedUp = false;//是否加速
 public bool IsFalling = false;//是否降落
 public Image bmp;//对象图形
 public Image img;//对象图形 暂不使用
 public Point point;//坐标 暂不使用
 public EventHandler TimerHandler;
 public Element(int x, int y)
 {
     bmp = Resources.Bird;
     this.x = x;
     this.y = y;
 }
 public Element(int x,int y,Image img)
 {
     bmp = Resources.Bird;
     this.x = x;
     this.y = y;
     this.img = img;
 }
 public void Draw(Graphics G)
 {
     G.DrawImage(bmp, x, y);
     Move();
 }
 public void Move()
 {
     if (IsFalling)
     {
  IsSpeedUp = false;
  IsJumping = false;
  IsRuning = false;
  if (!FallDepth)
  {
      this.y += BasicSpeed * 2;
      FallHeight += BasicSpeed * 2;
  }
  if (FallHeight == 50) 
  { 
      FallDepth = true; 
      IsFalling = false;
      TimerHandler(null, null);

  }//如果下降了50 则下降完成 不在下降

     }
     if (Back)
     {
  bmp = Resources.BirdBack;
  this.x -= BasicSpeed;

     }
     if (IsSpeedUp)
     {
  bmp = Resources.Bird;
  this.x += BasicSpeed*3;
     }
     else if (IsRuning)
     {
  bmp = Resources.Bird;
  this.x +=  BasicSpeed;
     }
     if (IsJumping)
     {
  if (!JumpTop)
  {
      this.y += BasicSpeed * (-2);
      JumpHeight += BasicSpeed * (2);
  }
  else
  {
      this.y += BasicSpeed * 2;
      JumpHeight += BasicSpeed * (-2);
  }
  if (JumpHeight == 30) { JumpTop = true; }//如果跳跃了30 则跳跃到顶部 不在上升
  if (JumpHeight == 0) { JumpTop = false; IsJumping = false; }//如果回到地面 不在下降 跳跃结束
     }

 }
 public void GetHandler(EventHandler TimerHandler)
 {
     this.TimerHandler = TimerHandler;
 }

    }
}

然后,创建陆块类,如下:

using System;
using System.Collections.Generic;

using System.Text;
using System.Drawing;
using Chicken.Properties;

namespace Chicken
{
    class Road
    {
 private Random rand = new Random();

 public List LandImgList = new List();
 public List ListRoad = new List();
 public int RoadY = 100;//陆地的Y坐标
 /// 
 /// 构建陆地
 /// 
 /// 陆块数量 必须大于2
 /// 陆块长度
 public Road(int Number, int  Length)
 {
     if (Length < 2)
  return;

     RoadItem StartItem = new RoadItem(0, Length);
     StartItem.imageIndex = 0;//选择陆块的图像 0为第一个平地 1为第二个左倾斜 2为第三个右倾斜
     StartItem.type = 1;
     ListRoad.Add(StartItem);//先添加一个陆块 第一个路块必须是陆地

     for (int i = 0; i < Number - 2; i++)
     {
  int Temp = rand.Next(0, 3);
  int Index = 0;//选择陆块的图像 0为第一个平地 1为第二个左倾斜 2为第三个右倾斜 这里暂时不使用
  int Ang = 0;
  if (Temp == 0)
  {
      Ang = -20;
      Index = 2;
  }
  else if (Temp == 1)
  {
      Ang = 0;
      Index = 0;
  }
  else
  {
      Ang = 20;
      Index = 1;
  }
  RoadItem CItem = new RoadItem(Ang, Length);
  //CItem.imageIndex = Index;获取随机陆块的图片 这样获取Y值需要写一个一元一次方程获取
  CItem.imageIndex = 0;//这里设置全为第一个图像 这样获取Y值比较方便
  if (rand.Next(0, 4) == 1)//4分之1的可能性为空陆块
      CItem.type = 0;
  else
      CItem.type = 1;

  ListRoad.Add(CItem);//添加中间的陆块 添加进陆块列表
     }

     RoadItem EndItem = new RoadItem(0, Length);
     EndItem.imageIndex = 0;//选择陆块的图像 0为第一个平地 1为第二个左倾斜 2为第三个右倾斜 
     EndItem.type = 1;
     ListRoad.Add(EndItem);//添加最后一个陆块

     for (int i = 0; i < ListRoad.Count; i++)
     {
  RoadItem DrawItem = ListRoad[i];
  if (i == 0)
  { DrawItem.start = new Point(0, RoadY); }
  else
  { DrawItem.start = ListRoad[i - 1].end; }

  DrawItem.end = new Point(DrawItem.start.X + DrawItem.length, RoadY);
     }
     //为每一个陆块 定义 起始和终止向量坐标

     LandImgList.Add(Resources.land);

    //为陆块使用的图片列表 赋值
 }
    }

    public class RoadItem
    {
 public int angle;
 public int length;//陆块长度
 public int type;//0为空,1为陆地
 public int imageIndex = 0;//使用的图片
 /// 
 /// 构建路块
 /// 
 /// 
 /// 陆块长度
 public RoadItem(int angle, int length)
 {
     this.angle = angle;
     this.length = length;
 }
 public Point start;//陆块起始坐标
 public Point end;//陆块终止坐标

    }
}

辅助类,这两个类是两个窗口,我闲MessageBox不太好看,就换了个窗口,但貌似也没好看到那里去。。。哈哈

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

namespace Chicken
{
    public partial class Replay : Form
    {
  EventHandler Again;
  public Replay(EventHandler Again)
 {
     this.Again = Again;
     InitializeComponent();
 }

 private void button1_Click(object sender, EventArgs e)
 {
     this.Close();
     Again(null, null);
 }
    }
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Chicken
{
    public partial class Dead : Form
    {
 EventHandler Again;
 public Dead(EventHandler Again)
 {
     this.Again = Again;
     InitializeComponent();
 }

 private void button1_Click(object sender, EventArgs e)
 {
     this.Close();
     Again(null, null);
 }
    }
}

这两个类是死亡窗口和重新开始窗口。
源代码下载地址http://download.csdn.net/detail/kiba518/4355712

源代码中,和文中的代码稍微有点不一样,如果我记得没错是这里,如下:

if (Chicken.x + Chicken.bmp.Width / 2 >= EndX)

是修改,如果鸡身的一半以上超过终点,到达终点,游戏结束。这个源码上传时没修改这里。

不过不影响运行啦,但是还有一些小BUG。。

如果想升级这个游戏也很简答,比如,定义一个炮弹类,随机发一个。

当炮弹的矩形和小鸡的矩形相碰撞了,就死亡啦,矩形相撞有函数的,有兴趣的朋友可以自己扩展。

补充:上是跳跃,左右可以移动,空格是加速,鼠标全屏飞。。。。

开发环境:VS2008。

代码很简单,可以复制到别的环境中运行。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/231266.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号