练手WPF(四)——贪吃蛇小游戏的简易实现(下)
八、生成新的单节蛇身
我们这里先说说游戏小原理好了,游戏运行后,通过计时器事件不断生成新的单节蛇身类SnakeNode,添加到List中的0位置,原来的蛇头变成了第二节。该节新蛇头的坐标通过蛇头前进方向Direct进行判断,即如果原蛇头往左运行,则新蛇头在原蛇头位置的左一格生成,其他方向以此类推。最后将该节添加到SnakeNodes列表中,并将相应图形添加到游戏区。
private void GenNewSnakeNode()
{
SnakeNode snakeNode = null;
switch (Direct)
{
case Direction.UP:
snakeNode = new SnakeNode(new Point(SnakeNodes[SnakeHead]._pos.X,
SnakeNodes[SnakeHead]._pos.Y - ));
break; case Direction.DOWN:
snakeNode = new SnakeNode(new Point(SnakeNodes[SnakeHead]._pos.X,
SnakeNodes[SnakeHead]._pos.Y + ));
break; case Direction.LEFT:
snakeNode = new SnakeNode(new Point(SnakeNodes[SnakeHead]._pos.X - ,
SnakeNodes[SnakeHead]._pos.Y));
break; case Direction.RIGHT:
snakeNode = new SnakeNode(new Point(SnakeNodes[SnakeHead]._pos.X + ,
SnakeNodes[SnakeHead]._pos.Y));
break;
} if (snakeNode != null)
{
SnakeNodes.Insert(, snakeNode);
myCanvas.Children.Add(SnakeNodes[]._rect);
}
}
九、随机水果位置
注意该新位置不得与蛇身任何一节重叠,如果重叠则另外生成新位置,直到成功为止。
private Point SetFruitToRandomPos()
{
bool flag = true;
Point pos = new Point();
while (flag)
{
flag = false;
pos = new Point(rnd.Next(, CellWidth), rnd.Next(, CellHeight));
foreach (var node in SnakeNodes)
{
if (pos.X == node._pos.X && pos.Y == node._pos.Y)
{
flag = true;
break;
}
}
} return pos;
}
十、碰撞检测(蛇头与水果)
因为只有蛇头会最先触碰到水果,所以只需判断蛇头坐标与水果坐标是否相同即可。如果撞到水果,则将水果随机生成新位置;如果没有碰到,则删除蛇尾一节(因为之后会通过计时器会生成新一节蛇头,这样就会保存蛇身长度,感觉位置前进了一格)。
private void CheckCollision()
{
if (SnakeNodes[SnakeHead]._pos.X == fruit._pos.X && SnakeNodes[SnakeHead]._pos.Y == fruit._pos.Y)
{
fruit.SetPostion(SetFruitToRandomPos());
}
else
{
if (myCanvas.Children.Contains(SnakeNodes[SnakeNodes.Count - ]._rect))
myCanvas.Children.Remove(SnakeNodes[SnakeNodes.Count - ]._rect); SnakeNodes.RemoveAt(SnakeNodes.Count - );
}
}
十一、判断是否游戏结束
很简单,看看蛇头是否触碰游戏区四边或蛇身的任何一节,如果是则返回true。
注意蛇身循环是从1开始的,如果从0开始你知道会出现什么情况。
private bool IsGameOver()
{
if (SnakeNodes[SnakeHead]._pos.X == - || SnakeNodes[SnakeHead]._pos.X == CellWidth
|| SnakeNodes[SnakeHead]._pos.Y == - || SnakeNodes[SnakeHead]._pos.Y == CellHeight)
{
return true;
} foreach (var node in SnakeNodes)
{
if (node == SnakeNodes[SnakeHead])
continue; if (node._pos.X == SnakeNodes[SnakeHead]._pos.X && node._pos.Y == SnakeNodes[SnakeHead]._pos.Y)
{
return true;
}
} return false;
}
十三、删除游戏区的所有蛇身节
这个会在重新开始游戏时使用到:
private void RemoveSnakeNodeAll()
{
for (int i = ; i < SnakeNodes.Count; i++)
{
if (myCanvas.Children.Contains(SnakeNodes[i]._rect))
{
myCanvas.Children.Remove(SnakeNodes[i]._rect);
}
}
}
顺便再来一发删除游戏区的水果:
private void RemoveFruit()
{
if (fruit == null)
{
return;
} if (myCanvas.Children.Contains(fruit._ellipse))
{
myCanvas.Children.Remove(fruit._ellipse);
}
}
十四、按键操作
通过方向键,设置Direct值即可。
private void MyCanvas_PreviewKeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.Left:
if (Direct != Direction.RIGHT)
{
Direct = Direction.LEFT;
}
break; case Key.Right:
if (Direct != Direction.LEFT)
{
Direct = Direction.RIGHT;
}
break; case Key.Up:
if (Direct != Direction.DOWN)
{
Direct = Direction.UP;
}
break; case Key.Down:
if (Direct != Direction.UP)
{
Direct = Direction.DOWN;
}
break; case Key.Escape:
Application.Current.Shutdown();
break; case Key.Space:
if (CurrGameState == GameState.NONE)
return; if (CurrGameState == GameState.PAUSE)
{
CurrGameState = GameState.GAMEING;
timer.Start();
MenuControl_Pause.Header = "暂停";
}
else if (CurrGameState == GameState.GAMEING)
{
CurrGameState = GameState.PAUSE;
timer.Stop();
MenuControl_Pause.Header = "继续";
}
break;
}
}
十四、定义开始游戏方法
先删除界面中的蛇身和水果(保留底部暗格),随机位置生成水果和三节蛇身。
private void StartGame()
{
RemoveSnakeNodeAll();
RemoveFruit(); int startX = rnd.Next(, CellWidth - );
int startY = rnd.Next(, CellHeight - );
Direct = Direction.RIGHT; fruit = new Fruit(SetFruitToRandomPos(), myCanvas); SnakeNodes = new List<SnakeNode>();
SnakeNodes.Add(new SnakeNode(new Point(startX, startY)));
GenNewSnakeNode();
GenNewSnakeNode();
}
十五、开始游戏菜单
调用StartGame()方法,并设定计时器开始。
private void MenuFile_NewGame_Click(object sender, RoutedEventArgs e)
{
StartGame();
timer.Start();
CurrGameState = GameState.GAMEING;
MenuControl_Pause.Header = "暂停";
}
十六、暂停与继续
直接上代码,没有要说的了。
private void MenuControl_Pause_Click(object sender, RoutedEventArgs e)
{
if (CurrGameState == GameState.GAMEING)
{
CurrGameState = GameState.PAUSE;
timer.Stop();
MenuControl_Pause.Header = "继续";
}
else if (CurrGameState == GameState.PAUSE)
{
CurrGameState = GameState.GAMEING;
timer.Start();
MenuControl_Pause.Header = "暂停";
}
}
十七、退出游戏
private void MenuFile_Exit_Click(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
十八、其他菜单功能
自己实现好了
private void MenuHelp_About_Click(object sender, RoutedEventArgs e)
{
}


[2019.12.23]更新:添加计时器事件代码(我不知道这个方法上次没有贴出来)
十九、计时器事件
/// <summary>
/// 计时器事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Timer_Tick(object sender, EventArgs e)
{
CheckCollision();
GenNewSnakeNode(); if (IsGameOver())
{
CurrGameState = GameState.STOP;
timer.Stop();
MessageBox.Show("游戏结束", "警告", MessageBoxButton.OK); return;
}
}
练手WPF(四)——贪吃蛇小游戏的简易实现(下)的更多相关文章
- 练手WPF(四)——贪吃蛇小游戏的简易实现(上)
一. 游戏界面首先,按照惯例,编辑MainWindow.xaml,先将游戏界面制作好.非常简单:(1)主游戏区依然使用我们熟悉的Canvas控件,大小为640X480像素,设定每小格子为20px,所以 ...
- 练手WPF(二)——2048游戏的简易实现(上)
1.创建游戏界面编辑MainWindow.xaml,修改代码如下: <Window.Resources> <Style TargetType="Label"> ...
- 练手WPF(二)——2048游戏的简易实现(下)
接着上一篇继续~~~ 6.动画显示增加分数 /// <summary> /// 动画显示增加得分 /// </summary> /// <param name=" ...
- C++ 简单的控制台贪吃蛇小游戏
由于比较懒,所以不怎么写,觉得这样不应该.我应该对自己学的做出整理,不管是高端低端,写出来是自己的. // 贪吃蛇.cpp : 定义控制台应用程序的入口点. // #include "std ...
- 贪吃蛇小游戏-----C语言实现
1.分析 众所周知,贪吃蛇游戏是一款经典的益智游戏,有PC和手机等多平台版本,既简单又耐玩.该游戏通过控制蛇头方向吃食物,从而使得蛇变得越来越长,蛇不能撞墙,也不能装到自己,否则游戏结束.玩过贪吃蛇的 ...
- JS高级---案例:贪吃蛇小游戏
案例:贪吃蛇小游戏 可以玩的小游戏,略复杂,过了2遍,先pass吧 先创建构造函数,再给原型添加方法.分别创建食物,小蛇和游戏对象. 食物,小蛇的横纵坐标,设置最大最小值,运动起来的函数,按上下左右键 ...
- Java GUI学习,贪吃蛇小游戏
JAVA GUI练习 贪吃蛇小游戏 前几天虽然生病了,但还是跟着狂神学习了GUI的方面,跟着练习了贪吃蛇的小项目,这里有狂神写的源码点我下载,还有我跟着敲的点我下载,嘿嘿,也就注释了下重要的地方,这方 ...
- 用GUI实现java版贪吃蛇小游戏
项目结构 新建一个JFrame窗口,作为程序入口 public class GameStart{ public static void main(String[] args) { JFrame jFr ...
- Java 用java GUI写一个贪吃蛇小游戏
目录 主要用到 swing 包下的一些类 上代码 游戏启动类 游戏数据类 游戏面板类 代码地址 主要用到 swing 包下的一些类 JFrame 窗口类 JPanel 面板类 KeyListener ...
随机推荐
- C# ZedGraph实时多条曲线数据更新实例
C# ZedGraph实时多条曲线数据更新实例 先看展示效果 1.创建曲线实例添加必要的元素 public class LineChannel { public LineChannel(int id, ...
- SSM框架之Mybatis(3)dao层开发
Mybatis(3)dao层开发 以实现类完成CRUD操作 1.持久层dao层接口的书写 src\main\java\dao\IUserDao.java package dao; import dom ...
- flex弹性布局没有生效
display: -webkit-flex; /* 新版本语法: Chrome 21+ */ display: -webkit-box; /* 老版本语法: Safari, iOS, Android ...
- 禁止ViewPager滑动
实现如下: public class NoScrollViewPager extends ViewPager { public NoScrollViewPager (Context context) ...
- window下操作jenkins查看页面的几种方式
原文:https://blog.csdn.net/kennin19840715/article/details/78782505 前几天通过jenkins本机执行selenium cases, 发现浏 ...
- [b0028] python 归纳 (十三)_队列Queue在多线程中使用
# -*- coding: UTF-8 -*- """ 多线程同时读队列 总结: 1. 会阻塞 if self._jobq.qsize() > 0 进入逻辑,此时被 ...
- 将Docker容器转移至另一服务器
1 把当前的容器提交为一个镜像: docker commit 容器名 镜像名 2 将镜像存为tar文件 docker save 镜像名 >备份文件.tar 3将 备份文件.tar 复制到目的主机 ...
- liteos MMU(十八)
1. 概述 1.1 基本概念 MMU全称"Memory Management Unit",顾名思义就是"内存管理单元". 1.2 运作机制 建立页表描述符号表, ...
- for循环结构
循环结构: 在程序当中总有一些需要反复/重复的执行的代码,假设没有循环结构,那么这段需要重复知心的需要重复执行的代码自然是需要重复编写的,代码无法得到重复使用.所以多数变成语言都是支持循环结构的.将来 ...
- scrapy爬虫具体案例详细分析
scrapy爬虫具体案例详细分析 scrapy,它是一个整合了的爬虫框架, 有着非常健全的管理系统. 而且它也是分布式爬虫, 它的管理体系非常复杂. 但是特别高效.用途广泛,主要用于数据挖掘.检测以及 ...