如何用C#完成一个有趣的有趣小游戏大全

> C#游戏编程:《控制台小游戏系列》之《6、贪吃蛇实例》
C#游戏编程:《控制台小游戏系列》之《6、贪吃蛇实例》
lancersky & &
发布时间: & &
浏览:60 & &
回复:0 & &
悬赏:0.0希赛币
C#游戏编程:《控制台小游戏系列》之《六、贪吃蛇实例》  一、游戏分析
  1976年,Gremlin平台推出一款经典街机游戏Blockade,则为贪吃蛇的原型,这款简单的小游戏很受欢迎,给80后这代人带来不可磨灭的记忆。作为未来程序员的我们,玩自己设计出的贪吃蛇比玩现有的更加有趣,我们可以添加我们所想到的各种特征,即使游戏多么另类都不觉得奇怪,我的游戏我做主!
  贪吃蛇的设计并不复杂,是很多游戏编程爱好者入门的首选项目之一,老衲也一样。整观这个游戏,屏蔽掉其他花俏的特征,让我们把焦点放到这个游戏的两个主要对象上:蛇和食物。玩过这款小游戏的人(难道有人没玩过的?)都知道,为了让自己的小蛇疯狂生长,就必须东西南北寻找食物来吃,前提是不要碰上障碍物,否则蛇就挂了。蛇由玩家通过键盘方向键来控制爬行方向,而食物在蛇视野范围内随机生成,当蛇吃掉食物之后,蛇长一节,食物再次随机生成,当然,食物不会落到蛇身上,否则蛇也只好自断了结了。
  通过上述,我们不难发现玩家的主要操作是控制蛇的爬行,对于蛇对象来说,它的特征就是会爬能爬,所以如何设计蛇的爬行并且如何反馈到画面上就是我们现在需要考虑的地方。蛇的爬行方法多种多样,但在这之前,我们还必须考虑蛇的表示方法,如何用数据结构表达一条蛇?
  ■或许可以想到用线性表来存储蛇的各个节点,当蛇移动时遍厉每个节点,更新为对应爬行方向之后的新值,这样每次蛇移动一步,则动全身:所有节点都要访问一次,可以看出最后的效率一定不会太高;
  ■或许可以想到用线性表来存储蛇的各个节点,当蛇移动时根据爬行方向把新的坐标节点添加到线性表中,然后把相对的“蛇尾”节点删除,最后遍历每个节点,调整各个节点在线形表的位置,防止线形表前后出现空缺的问题。这个方法还是避免不了要动全身,效率也不高。
  ■或许可以想到用链表来存储蛇的各个节点,当蛇移动时只需要操作链头链尾指针,其他节点无须逐一访问,效率相对前面两种来说提升不少。
  然而在C#中,我们没必要考虑这么多,List$<$就能很好的解决这个问题了,用List$<$表达一条蛇,当蛇爬行的时候插入一个新节点,而删除相对尾端的尾节点,从而实现蛇的爬行效果;当蛇吃到食物时,只管往里添新节点即可,无须删除旧节点操作,这样蛇的身体就会生长一节。对于如何渲染蛇到画面上也是同样的思路(或许这是因为我们的蛇每个节点都是相同样式的情况),我们没有必要遍历每个节点然后把它们逐个渲染到画面上,而是采取“画头擦尾”的方式,只画改变的节点,不变的节点不需要考虑,从而使游戏性能大大提升,即使蛇的节点几千几万个,最终需要考虑的只有前后两个节点,蛇爬行起来腰不累了,吃嘛嘛香!以下用图来表达这种思想:
  二、游戏实现
  根据上面的分析,我们很清晰的知道我们这个游戏主要的对象是什么了,万事开头难,分析清楚以后我们就很容易实现我们所需要的东西了,首先来看蛇类的实现。
  ///Snake类实现
  using S
using System.Collections.G
namespace Snake
/// &summary&
/// 贪吃蛇类
/// &/summary&
internal class Snake
#region 字段
/// &summary&
/// &/summary&
private List&CPoint& m_
/// &summary&
/// 爬行方向
/// &/summary&
private CDirection m_
/// &summary&
/// &/summary&
private CPoint m_
/// &summary&
/// &/summary&
private CPoint m_
#endregion
#region 构造函数
/// &summary&
/// 构造函数
/// &/summary&
/// &param name=&len&$>$/param&
/// &param name=&dir&$>$/param&
public Snake(Int32 len, CDirection dir)
this.m_dir =
this.m_body = new List&CPoint&();
for (Int32 i = 0; i &= i++)
m_body.Add(new CPoint(i+1, 2));
if (m_body.Count & 0)
m_head = m_body[m_body.Count - 1];
m_tail = m_body[0];
#endregion
#region 方法
/// &summary&
/// 设置方向
/// &/summary&
/// &param name=&dir&$>$/param&
public void setDirection(CDirection dir)
this.m_dir =
/// &summary&
/// 获取方向
/// &/summary&
/// &returns$>$/returns&
public CDirection getDirection()
return this.m_
/// &summary&
/// 获取蛇头
/// &/summary&
/// &returns$>$/returns&
public CPoint getHead()
return m_body[m_body.Count - 1];
/// &summary&
/// 获取蛇尾
/// &/summary&
/// &returns$>$/returns&
private CPoint getTail()
return m_body[0];
/// &summary&
/// 添加蛇body节点
/// &/summary&
/// &param name=&point&&新节点&/param&
/// &param name=&food&&是否是食物节点&/param&
public void addBodyNode(CPoint point, bool food)
//添加新节点
this.m_body.Add(point);
//非食物节点则移除尾巴
if (!food)
if (this.m_body.Count & 0)
this.m_body.Remove(getTail());
/// &summary&
/// 是否在某位置发生碰撞
/// &/summary&
/// &param name=&point&$>$/param&
/// &returns$>$/returns&
public Boolean isCollision(CPoint point)
Boolean flag =
foreach (CPoint p in m_body)
if (p == point)
/// &summary&
/// 是否与自身发生碰撞
/// &/summary&
/// &returns$>$/returns&
public Boolean isSeftCollision()
Boolean flag =
for (Int32 i = 0; i &m_body.Count-1; i++)
if (m_body[i] == getHead())
/// &summary&
/// 蛇移动
/// &/summary&
/// &returns$>$/returns&
public bool move()
CPoint head = getHead();
switch (m_dir)
case CDirection.Left:
if (head.getX() == 1)
head.setX(head.getX() - 1);
case CDirection.Right:
if (head.getX() == 28)
head.setX(head.getX() + 1);
case CDirection.Up:
if (head.getY() == 1)
head.setY(head.getY() - 1);
case CDirection.Down:
if (head.getY() == 23)
head.setY(head.getY() + 1);
addBodyNode(head, false);
/// &summary&
/// 绘制蛇
/// &/summary&
/// &param name=&draw&$>$/param&
public void draw(CDraw draw)
draw.setDrawSymbol(CSymbol.RING_SOLID);
draw.fillRect(getHead().getX(), getHead().getY(), 1, 1, ConsoleColor.Yellow);
draw.setDrawSymbol(CSymbol.DEFAULT);
draw.fillRect(getTail().getX(), getTail().getY(), 1, 1, ConsoleColor.Black);
#endregion
}&&蛇方向是一个枚举&#20540;,具体实现为下:
  ///CDirection枚举实现
  using S
namespace CEngine
public enum CDirection
Left = 0x01,
Right = 0x02,
Up = 0x04,
Down = 0x08,
}&&蛇类主要处理的是蛇的爬行、蛇是否吃到吃到食物、蛇是否自残和蛇的绘制等,此蛇类相对比较简单,就不必过多讨论了,接下来是食物类,鉴于此游戏DEMO是测试这个游戏框架的特征,所以以简为主,就不必讨论不同食物间的特征等问题,这只是一个游戏DEMO,不是一个完整的游戏,知道这一点是必须的。
  ///Food类实现
  using S
namespace Snake
/// &summary&
/// 食物类
/// &/summary&
internal class Food
/// &summary&
/// &/summary&
private CPoint m_
/// &summary&
/// 构造函数
/// &/summary&
public Food()
public Food(CPoint point)
this.m_position =
/// &summary&
/// 获取位置
/// &/summary&
/// &returns$>$/returns&
public CPoint getPosition()
return this.m_
/// &summary&
/// 设置位置
/// &/summary&
/// &param name=&point&$>$/param&
public void setPosition(CPoint point)
this.m_position =
/// &summary&
/// 设置位置
/// &/summary&
/// &param name=&x&$>$/param&
/// &param name=&y&$>$/param&
public void setPosition(Int32 x, Int32 y)
this.m_position = new CPoint(x,y);
/// &summary&
/// 绘制食物
/// &/summary&
/// &param name=&draw&$>$/param&
public void draw(CDraw draw)
draw.setDrawSymbol(CSymbol.RING_SOLID);
draw.drawRect(m_position.getX(), m_position.getY(), 1,1,ConsoleColor.Green);
}&&接下来是处理游戏逻辑,也就是实现这个游戏的控制类,这个类继承我们的游戏框架类,拥有框架提供的各种功能,从而对游戏实行控制和渲染,实现如下:
  ///SnakeGame类实现:
  using S
namespace Snake
/// &summary&
/// 贪吃蛇游戏类
/// &/summary&
public sealed class SnakeGame : CGame
/// &summary&
/// 游戏状态
/// &/summary&
public enum GameState
/// &summary&
/// 初始化
/// &/summary&
/// &summary&
/// 开始游戏
/// &/summary&
/// &summary&
/// 暂停游戏
/// &/summary&
/// &summary&
/// 结束游戏
/// &/summary&
/// &summary&
/// 贪吃蛇
/// &/summary&
private Snake g_
/// &summary&
/// &/summary&
private Food g_
/// &summary&
/// 随机数
/// &/summary&
private Random g_
/// &summary&
/// &/summary&
private Int32 g_
/// &summary&
/// &/summary&
private Int32 g_
/// &summary&
/// &/summary&
private GameState g_
#region 游戏运行函数
/// &summary&
/// 游戏初始化
/// &/summary&
protected override void gameInit()
base.setTitle(&控制台游戏之——简易贪吃蛇v1.0&);
base.setCursorVisible(false);
base.setUpdateRate(50);
this.g_random = new Random();
this.g_snake = new Snake(3, CDirection.Right);
this.g_food = new Food();
this.g_lifes = 3;
this.g_state = GameState.I
this.drawInitUI();
/// &summary&
/// 游戏重绘时响应
/// &/summary&
/// &param name=&e&$>$/param&
protected override void onRedraw(CPaintEventArgs e)
base.onRedraw(e);
CDraw draw = e.getDraw();
//绘制食物
g_food.draw(draw);
//绘制数据
draw.drawText(&得分:& + g_score.ToString(), 63, 2, ConsoleColor.Green);
draw.drawText(&生命:& + g_lifes.ToString(), 63, 4, ConsoleColor.Red);
/// &summary&
/// 游戏渲染
/// &/summary&
/// &param name=&draw&$>$/param&
protected override void gameDraw(CGraphics.CDraw draw)
if (g_state == GameState.Start)
g_snake.draw(draw);
draw.drawText(&FPS:& + getFPS(), 63, 6, ConsoleColor.Blue);
/// &summary&
/// 游戏逻辑
/// &/summary&
protected override void gameLoop()
//游戏开始状态
if (g_state == GameState.Start)
//如果蛇能爬行或者没有自残则爬行
if (g_snake.move() && !g_snake.isSeftCollision())
//吃到食物
if (g_snake.getHead() == g_food.getPosition())
this.g_score += 10;
g_snake.addBodyNode(g_food.getPosition(), true);
//创建新食物
createFood();
//蛇死亡,减一条生命
this.g_lifes--;
//扣分算法
if (this.g_score & 20)
this.g_score -= 20;
//延时一秒钟
base.delay(1000);
//蛇回到原始状态
this.g_snake = new Snake(3, CDirection.Right);
//更新导致重绘区域
base.update(new CRect(1, 1, 28, 23));
//游戏结束
if (this.g_lifes == 0)
this.g_state = GameState.E
this.setGameOver(true);
/// &summary&
/// 游戏结束
/// &/summary&
protected override void gameExit()
drawEndUI();
/// &summary&
/// 键盘事件
/// &/summary&
/// &param name=&e&$>$/param&
protected override void gameKeyDown(CKeyboardEventArgs e)
if (g_snake != null)
if (e.getKey() == CKeys.Left)
if (g_snake.getDirection() != CDirection.Right)
g_snake.setDirection(CDirection.Left);
else if (e.getKey() == CKeys.Right)
if (g_snake.getDirection() != CDirection.Left)
g_snake.setDirection(CDirection.Right);
else if (e.getKey() == CKeys.Up)
if (g_snake.getDirection() != CDirection.Down)
g_snake.setDirection(CDirection.Up);
else if (e.getKey() == CKeys.Down)
if (g_snake.getDirection() != CDirection.Up)
g_snake.setDirection(CDirection.Down);
else if (e.getKey() == CKeys.Space)
if (g_state == GameState.Init)
g_state = GameState.S
drawStartUI();
else if (g_state == GameState.Pause)
g_state = GameState.S
else if (g_state == GameState.Start)
g_state = GameState.P
else if (e.getKey() == CKeys.Escape)
setGameOver(true);
#endregion
/// &summary&
/// 创建食物
/// &/summary&
private void createFood()
CPoint point = new CPoint(g_random.Next(1, 29), g_random.Next(1, 24));
//防止食物出现在蛇身
while (g_snake.isCollision(point))
point.setX(g_random.Next(1, 29));
point.setY(g_random.Next(1, 24));
g_food.setPosition(point);
//调用更新函数导致控制台重绘
base.update(new CRect(point.getX(), point.getY(), 1, 1));
#region 绘制界面
//绘制游戏初始界面
private void drawInitUI()
CDraw draw = base.getDraw();
draw.clear(ConsoleColor.Black);
draw.setDrawSymbol(CSymbol.RECT_EMPTY);
draw.drawRect(6, 4, 29, 12, ConsoleColor.DarkBlue);
draw.fillRect(7, 5, 27, 10, ConsoleColor.Blue);
draw.drawText(&$>$, 16, 5, ConsoleColor.White);
draw.drawText(&简 易 贪 吃 蛇&, 34, 9, ConsoleColor.Yellow);
draw.drawText(&Copyright. D-Zone Studio&, 42, 14, ConsoleColor.Gray);
draw.drawText(&Space to Play&, 35, 20, ConsoleColor.White);
//绘制游戏开始界面
private void drawStartUI()
CDraw draw = base.getDraw();
//绘制界面
draw.clear(ConsoleColor.Black);
draw.setDrawSymbol(CSymbol.RECT_EMPTY);
draw.drawRect(0, 0, 30, 25, ConsoleColor.White);
draw.setDrawSymbol(CSymbol.RHOMB_SOLID);
draw.drawRect(30, 0, 10, 25, ConsoleColor.DarkYellow);
draw.drawText(&操作:键盘操作,方向键控制贪吃蛇爬行方向,空格键控制开始游戏和暂停游戏,ESC键退出游戏。&, new CRect(32, 14, 6, 10), ConsoleColor.DarkGreen);
this.createFood();
//绘制游戏结束界面
private void drawEndUI()
CDraw draw = base.getDraw();
//绘制界面
draw.clear(ConsoleColor.Black);
draw.drawText(&Game over, &, 30, 10, ConsoleColor.White);
draw.drawText(&score:& + g_score.ToString(), 42, 10, ConsoleColor.White);
Console.ReadLine();
#endregion
}&&与以往编写小游戏的经验比较,我们发现没有必要每次都要编写代码驱动和维护游戏的运行,在这里,游戏框架类已为我们封装这些特征,我们制作游戏时只需要考虑游戏如何玩法等设计上的问题,而不需要考虑其他细节问题,一定程度上提高我们的开发效率。尽管这个小游戏是一个DEMO版本,但它也具备一定的完整性,比如拥有了游戏必须的几个界面,然而它还不是完整的,没有关卡的设计,没有信息的保存,也没有参数的配置,但对于说明游戏框架如何使用已经足够了。
  接下来让我们欣赏一下我们的劳动成果:
  试玩链接:
  三、结语
  终于完成了这个DEMO,如果读者也制作了贪吃蛇,不防给个链接,让我们娱乐娱乐!
本问题标题:
本问题地址:
温馨提示:本问题已经关闭,不能解答。
暂无合适的专家
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&C#开发俄罗斯方块小游戏_图文_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
C#开发俄罗斯方块小游戏
上传于|0|0|文档简介
&&详细讲解开发过程,包学会。
阅读已结束,如果下载本文需要使用1下载券
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,查找使用更方便
还剩30页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢}

我要回帖

更多关于 有趣小游戏 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信