重回童年的经典系列☀️|贪吃蛇小游戏近两万字完整制作过程+解析+源码 建议收藏学习
Posted 呆呆敲代码的小Y
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重回童年的经典系列☀️|贪吃蛇小游戏近两万字完整制作过程+解析+源码 建议收藏学习相关的知识,希望对你有一定的参考价值。
- 📢博客主页:https://blog.csdn.net/zhangay1998
- 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
- 📢本文由 呆呆敲代码的小Y 原创,首发于 CSDN🙉
- 📢未来很长,值得我们全力奔赴更美好的生活✨
目录
📣前言
- 今天给大家带来一款经典的贪吃蛇小游戏,相信大家应该都应该玩过
- 包括小时候在经典的诺基亚手机上,也是百玩不厌,算是最经典的游戏之一了!
- 那今天就来学习一下怎样制作这个经典的贪吃蛇小游戏吧!
🎬贪吃蛇小游戏制作
🎥游戏介绍
-
本篇小游戏使用Unity引擎制作一款经典的贪吃蛇小游戏
-
跟小时候玩过诺基亚手机上的玩法类似,然后使用一套自己的素材制作
-
有两种游戏模式 和 两款小蛇的皮肤,每当吃到食物就会变长!
-
本篇教程使用的Unity的版本是2018.4.24,不同版本可能会出现略微差异
-
文章字数挺多,其实整个游戏只用了四个脚本,直接结合源码看文章效果更佳!
🏳️🌈打开Unity 新建一个项目,导入素材资源包
第一步还是老样子,先打开UnityHub
,新建一个项目
这里要注意的是选择一个2D项目
,因为贪吃蛇是一个2D游戏
所以我们只需要创建一个 2D项目 而不需要 3D项目!如下所示
创建完了之后我们需要导入一个贪吃蛇的素材包,这个素材包
在文章后面我会和源码
一起分享!
先来看看导入之后这个资源包中都有什么内容吧!
导入之后工程目录结构如下:
有一个声音文件夹
、模型文件夹
、文字文件夹
和精灵图片文件夹
里面都包含几个简单的贪吃蛇
会用到的对应文件
🏳️🌈新建一个场景,设置 开始场景 的界面
在工程下新建一个场景Sence
然后新建一个Image
,然后将画布的渲染模式改为摄像机渲染
将Image
设置跟画布一个大小
把资源包中的这个背景拖到Image
上,这样的话Image
就会作为一个游戏背景来显示~
- 然后把
image
改名为bg
,然后再新建一个Image
,改名为ControllerPanel
- 这个新建的
Image
作为一个开始场景中的侧边栏,调整一下位置,放到Canvas左侧! - 然后还要新建一个
Text
文本组件,调整一下Text
的位置,放到Canvas上边侧就好 - 然后输入
贪吃蛇
,改个字体大小,字体选择我们资源包中的效果。效果如下:
然后还需要加一个Button
作为一个 开始按钮
那就来新建一个Button
,然后选择资源包中的这个Go
图片作为点击按钮,并将Button
下的Text
本文改为开始
。效果如下:
然后还可以给这个开始按钮加一个outline
和shadow
组件来做一个阴影效果!
如下所示:
然后我们可以在背景图bg
下面新建一些Image
加一些小图片做一个点缀效果
当然这不是必须要做的哈,知识单纯的让看起来可以更美观一些,要不然有些空空的
图片都是资源包中的,只需要更换一下图片素材就好了。效果如下:
🏳️🌈设置 开始场景 的 侧边栏
这个侧边栏会用来显示皮肤
、模式选择
和分数显示
,在一开始的游戏展示中我们也看到了,所以这里需要来设置一下
我们在ControPanle
下新建一个Text文本框
,输入皮肤两个字,然后调整一下字体大小和位置
如果不知道设置多少比较好,可以参考下我设置的,参数和效果如下:
然后照葫芦画瓢,继续加一个模式选择
和 分数显示
,效果如下:
三个标题添加好了,但是里面还有小标题,再来继续设置一下
先来设置一下分数
在分数Store
下新建一个Text
文本作为上次成。,输入:上次:长度0,分数0
然后调整一下大小和位置,参数和效果如下:
然后继续照葫芦画瓢,添加一个最好成绩,参数和效果如下:
然后接下来搞一下模式
的设置
我们在模式Mode
下新建一个Toggle选择框
,用于做模式选择
的时候使用
改一下名字为:Border
,然后设置一下文字大小等参数,效果如下:
然后照葫芦画瓢再来整一个自由模式
,参数效果如下:
这里只是为了做一个UI效果,具体怎样设置都可以,只是作为一个参考!
然后还没完,因为正常游戏中两种模式只能选择一个,所以我们在这里需要添加一个组件用于控制
那就是Toggle Group
组件,这是UGUI自带的一个组件,目的就是遇到这多个选择框只能选择一个的时候使用
我们给Mode对象身上添加一个Toggle Group组件
,然后在两个边界模式的Toggle组件
属性中的Group
设置成父物体身上的Toggle Group组件
,效果如下:
然后还有一个皮肤选择
没有设置,再来设置一下
同理也是需要添加一个Toggle
组件,然后设置一下位置和大小
然后我们对这个Toggle
组件做一个简单的配置,使用我们的素材给他装饰的好看一些
这一步也是自己看兴趣设置,哪怕使用一个默认的Toggle
组件不做装饰也是可以的!
配置好了之后如下图所示:
如果详细的配置信息没有看明白,可以结合后面的源码来进行更详细的参数设置
因为在文中可能有地方语言描述真的很费劲,所以结合源码工程观看,学习体验效果更佳!
然后照葫芦画瓢再来配置一个其他颜色的,直接复制一个,然后调整位置修改一下
如下所示:
然后同模式选择一样,皮肤也只能选择一个来进行游戏
所以这里还是需要添加一个Toggle Group
组件给Skin
对象添加上
然后给两个小蛇的对象Bule和yellow
的Group
属性中将父物体添加上,效果如下:
然后开始界面的UI基本上算是搭建完毕了,接下来就是下一步了!
🏳️🌈新建一个场景,设置 游戏场景 的界面
开始场景我们设置完了,还需要一个进行游戏的场景设置
我们在Sence文件夹
中新建一个场景Main
作为游戏场景
然后跟开始场景中一样,对侧边栏
进行设置,设置的参数和开始场景并没有很大的区别
直接来看一下我设置的即可,就是单纯的UI大小位置设置,查看更详细的设置参照源码即可,很简单就不赘述了!
🏳️🌈给游戏场景添加可视化边界
基本的游戏场景
设置完了,在我们的小蛇碰到边界的时候是会触发不同的效果的
- 在
边界模式
中,碰到边界就会死亡,结束游戏 - 在
自由模式
中,碰到边界会进行一个穿透传送效果
那接下来就来设置一下游戏的边界处理
我们在bg
下新建一个Image
作为上边界,给这个Image
添加一个碰撞体BoxCollider
然后调整图片和碰撞体的大小
参数和效果如下所示:
这里的话不同的电脑可能参数会有略微差异,根据自己的视图大小调整这个边界的位置和大小即可
最终效果是让这个游戏视图的上下所有边界都完整覆盖即可!如下所示:
🏳️🌈制作小蛇并让其移动
现在我们游戏场景有了,那接下来就需要一条小蛇来进行游戏了
所以我们在Canvas
下新建一个Image
命名为SnakeHead
并将我们素材中的一个小蛇头的图片拖上去
调整一下这个Image的大小为45即可,如下所示
然后就是编写一个SnakeHead脚本代码让小蛇动起来,新建一个脚本,将一下代码放进去即可!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SnakeHead : MonoBehaviour
{
public float velocity = 0.35f;
public int step;
private int x;
private int y;
private Vector3 headPos;
void Start()
{
InvokeRepeating("Move", 0, velocity);
x = 0; y = step;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space) )
{
CancelInvoke();
InvokeRepeating("Move", 0, velocity - 0.2f);
}
if (Input.GetKeyUp(KeyCode.Space))
{
CancelInvoke();
InvokeRepeating("Move", 0, velocity);
}
if (Input.GetKey(KeyCode.W) && y != -step )
{
gameObject.transform.localRotation = Quaternion.Euler(0, 0, 0);
x = 0; y = step;
}
if (Input.GetKey(KeyCode.S) && y != step )
{
gameObject.transform.localRotation = Quaternion.Euler(0, 0, 180);
x = 0; y = -step;
}
if (Input.GetKey(KeyCode.A) && x != step )
{
gameObject.transform.localRotation = Quaternion.Euler(0, 0, 90);
x = -step; y = 0;
}
if (Input.GetKey(KeyCode.D) && x != -step )
{
gameObject.transform.localRotation = Quaternion.Euler(0, 0, -90);
x = step; y = 0;
}
}
void Move()
{
headPos = gameObject.transform.localPosition; //保存下来蛇头移动前的位置
gameObject.transform.localPosition = new Vector3(headPos.x + x, headPos.y + y, headPos.z); //蛇头向期望位置移动
}
}
通过键盘按键来让小蛇进行不同方向的移动,并设置一个时间和一个移动速度即可,效果如下:
🏳️🌈随机生成食物、食物被吃掉 和 生成新的食物
现在小蛇可以进行移动了,还需要添加一个食物的自动生成
,所以再接着来做这个食物的随机生成
随机生成食物也很简单,先来判断一下食物可以生成的范围,肯定就是游戏边界内,不能生成到游戏场景外面
新建一个脚本 FoodMaker
用来随机生成一个食物
using UnityEngine;
using UnityEngine.UI;
public class FoodMaker : MonoBehaviour
{
public int xlimit = 21;
public int ylimit = 11;
public int xoffset = 7;
public GameObject foodPrefab;
public Sprite[] foodSprites;
private Transform foodHolder;
void Start()
{
foodHolder = GameObject.Find("FoodHolder").transform;
MakeFood();
}
public void MakeFood()
{
int index = Random.Range(0, foodSprites.Length);
GameObject food = Instantiate(foodPrefab);
food.GetComponent<Image>().sprite = foodSprites[index];
food.transform.SetParent(foodHolder, false);
int x = Random.Range(-xlimit + xoffset, xlimit);
int y = Random.Range(-ylimit, ylimit);
food.transform.localPosition = new Vector3(x * 30, y * 30, 0);
}
}
使用ylimit 和xlimit
来控制一个随机生成的边界
通过foodSprites
数组来控制随机生成食物的图片
然后这样就可以随机生成食物了,后面会写方法,当小蛇吃掉一个食物的时候再生成新的食物就好了!
上面说了食物的一个随机生成
,那接下来要对食物被吃掉和生成一个新的食物来进行逻辑处理
我们要从蛇头这边来介入,因为只有当蛇头碰到食物之后,食物才会消失,是通过碰撞检测来完成的
所以要给蛇头添加一个碰撞体
和刚体
,来进行一个碰撞检测
!
然后在SnakeHead
脚本中添加代码用来检测食物
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.CompareTag("Food"))
{
Destroy(collision.gameObject);
FoodMaker.Instance.MakeFood((Random.Range(0, 100) < 20) ? true : false);
}
}
这样的话当蛇头碰到食物之后,食物就会消失,然后调用生成食物的方法继续生成新的食物啦!
🏳️🌈小蛇吃食物变长 和 蛇身的移动
现在小蛇可以进行吃食物了,而且食物也会被吃掉之后随机生成新的,但是蛇身还没有变长
所以现在来写一下蛇身变长的逻辑和代码,还是在SnakeHead
脚本中添加代码
声明一个List
用来蛇身的处理,后续蛇身移动的时候会用到
public List<Transform> bodyList = new List<Transform>();
void Grow()
{
int index = (bodyList.Count % 2 == 0) ? 0 : 1;
GameObject body = Instantiate(bodyPrefab, new Vector3(2000, 2000, 0), Quaternion.identity);
body.GetComponent<Image>().sprite = bodySprites[index];
body.transform.SetParent(canvas, false);
bodyList.Add(body.transform);
}
将这段代码在蛇吃到食物之后调用即可,这样的话就可以在吃到食物之后蛇身变长了!
然后是蛇身的移动代码,使用List
存储蛇身,然后让蛇身的每一个后边的蛇身位置换到蛇身前边的位置
这样就可以形成一个蛇不断移动的效果,蛇身的后一个节点和前一个节点之间就可以正常跟随蛇头移动了!
void Move()
{
headPos = gameObject.transform.localPosition; //保存下来蛇头移动前的位置
gameObject.transform.localPosition = new Vector3(headPos.x + x, headPos.y + y, headPos.z); //蛇头向期望位置移动
if (bodyList.Count > 0)
{
//由于我们是双色蛇身,使用此方法达到显示目的
for (int i = bodyList.Count - 2; i >= 0; i--) //从后往前开始移动蛇身
{
bodyList[i + 1].localPosition = bodyList[i].localPosition; //每一个蛇身都移动到它前面一个节点的位置
}
bodyList[0].localPosition = headPos; //第一个蛇身移动到蛇头移动前的位置
}
}
🏳️🌈蛇身边界传送效果
在边界模式
下,当蛇碰到边界时就是触发死亡,这个操作很简单
我们在边界设置了碰撞体
,所以当蛇碰到边界时就会触发一个回调
因为我们蛇身移动的逻辑是跟随前一个结点移动,所以只需要蛇头的边界传送,蛇身就会自动跟随达到我们想要的效果
所以我们只需要判断蛇头到达边界的时候,改动一下蛇头的位置就好了!
还是在SnakeHead
脚本中添加代码,关键代码如下
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.CompareTag("Food"))
{
Destroy(collision.gameObject);
MainUIController.Instance.UpdateUI();
Grow();
FoodMaker.Instance.MakeFood((Random.Range(0, 100) < 20) ? true : false);
}
else
{
switch (collision.gameObject.name)
{
case "Up":
transform.localPosition = new Vector3(transform.localPosition.x, -transform.localPosition.y + 30, transform.localPosition.z);
break;
case "Down":
transform.localPosition = new Vector3(transform.localPosition.x, -transform.localPosition.y - 30, transform.localPosition.z);
break;
case "Left":
transform.localPosition = new Vector3(-transform.localPosition.x + 180, transform.localPosition.y, transform.localPosition.z);
break;
case "Right":
transform.localPosition = new Vector3(-transform.localPosition.x + 240, transform.localPosition.y, transform.localPosition.z);
break;
}
}
}
🏳️🌈分数和长度的记录
现在蛇的基本移动
、变长
和食物生成
等等都做好了
那接下来就是分数的增加
了,只需要在吃掉食物的时候调用一下就好了!
新建一个脚本MainUIController
,用于 控制分数的增加
和 等级的判定
代码也很简单,当吃掉食物就进行调用即可!
public int score = 0;
public int length = 0;
public Text scoreText;
public Text lengthText;
public void UpdateUI(int s = 5, int l = 1)
{
score += s;
length += l;
scoreText.text = "得分:\\n" + score;
lengthText.text = "长度:\\n" + length;
}
然后在这个脚本中在写一下根据不同的分数阶段,进行场景背景的一个变化
这就是一个游戏玩法
的增加了,代码如下:
switch (score / 100)
{
case 0:
case 1:
case 2:
break;
case 3:
case 4:
ColorUtility.TryParsehtmlString("#CCEEFFFF", out tempColor);
bgImage.color = tempColor;
msgText.text = "阶段" + 2;
break;
case 5:
case 6:
ColorUtility.TryParseHtmlString("#CCFFDBFF", out tempColor);
bgImage.color = tempColor;
msgText.text = "阶段" + 3;
break;
case 7:
case 8:
ColorUtility.TryParseHtmlString("#EBFFCCFF", out tempColor);
bgImage.color = tempColor;
msgText.text = "阶段" + 4;
break;
case 9:
case 10:
ColorUtility.TryParseHtmlString("#FFF3CCFF", out tempColor);
bgImage.color = tempColor;
msgText.text = "阶段" + 5;
break;
default:
ColorUtility.TryParseHtmlString("#FFDACCFF", out tempColor);
bgImage.color = tempColor;
msgText.text = "无尽阶段";
break;
}
🏳️🌈游戏暂停 和 菜单键 的设置
到这里的话游戏基本功能
就是完成了,这一步是将游戏场景中的暂停键
和返回菜单键
的功能给加上
之前知识添加了UI,并没有写实际的方法,所以这里给加上
还是在MainUIController
脚本进行编写代码,因为MainUIController
脚本就是一个处理UI相关内容的
public void Pause()
{
isPause以上是关于重回童年的经典系列☀️|贪吃蛇小游戏近两万字完整制作过程+解析+源码 建议收藏学习的主要内容,如果未能解决你的问题,请参考以下文章
重回童年的经典系列☀️|炸弹人小游戏制作过程+解析 | 收藏起来跟曾经的小伙伴一起梦回童年!
曾经被诺基亚作为卖点的游戏,无数玩家的童年游戏,它就是...
重回童年的经典系列 |捕鱼达人小游戏来啦~ 有源码下载文末送书