练手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 ...
随机推荐
- 用python执行Linux命令
例1:在python中包装ls命令 #!/usr/bin/env python #python wapper for the ls command import subprocess subproce ...
- vue-父组件和路由
父子组件之间传值 <div id="app"> <com1 v-bind:parentmsg="msg" @func="getMsg ...
- C# Spire简单实现导出word(去水印)
今天老姐打电话,说:下个月一号要换到其他岗位上,到时需要对word操作,小弟我随口答应,这个简单,我给你开发一款小程序,你直接在我程序上录入一些数据,我给你导出到word中. 利用中午空闲时间,百度了 ...
- 登陆远程服务器的Tomcat 8的manger的页面403
访问远程服务器Tomcat 8的管理页面报错 在远程服务器上安装了一个tomcat8.5,配置好用户后重新启动tomcat ,发现:8080可以访问,但是进入:8080/manager/html页面报 ...
- nuget 包管理器
nuget 是.Net平台上的包管理器, 对于包的发布(打包 package)和消费(下载依赖管理)都有很好的支持, 本文仅仅关注消费端, =======================nuget项目 ...
- 记录C#泛型
常见的泛型类型 泛型类 class MyClass<T> { //...... } 泛型接口 interface GenericInterface<T> { void Gene ...
- 编译安装 proxychains-ng proxychains4
下载 [root@localhost html]# git clone https://github.com/rofl0r/proxychains-ng.git 编译安装 [root@localhos ...
- 初始FPGA
FPGA和单片机的区别 单片机 FPGA 哈佛总线结构,或者冯诺依曼结构 查找表 串行执行 并行执行 软件范畴 硬件范畴 C/汇编语言编程 Verilog HDL/ VHDL硬件描述语言编程 FPGA ...
- JAVA学习方法之——费曼学习法
理查德·费曼 费曼简介 理查德·菲利普斯·费曼(Richard Phillips Feynman),出生于1918年5月11日,是美籍犹太裔物理学家,曾在1965年获得诺贝尔物理学奖,也被认为是继爱因 ...
- C# 内存管理(一)
引用地址:https://blog.csdn.net/libohuiyuan/article/details/81030010 一.变量类型 C#的变量类型分为值类型,引用类型.指针类型和指令类型.所 ...