[Untiy]贪吃蛇大作战(四)——游戏主界面
游戏主界面:

由于这个场景比较复杂,需要分几个部分实现:
1、游戏背景
首先我们的游戏场景上包括了一个大的背景图片,之外再包围一个红色的区域。中间的区域才是可活动的区域,周围通过碰撞检测盒来检测是否有蛇撞到了墙壁。
2、食物生成
食物生成通过一个单例脚本来实现,创建一个食物的内存池(脚本中的idleFood并没有使用),内存池中有200个食物随机生成在游戏的活动区域中,当食物被蛇吃掉之后不是销毁对象,而是简单改变食物的位置,下面是脚本代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FoodPoolManager : MonoBehaviour {
private static FoodPoolManager _instance;
public static FoodPoolManager Instance {
get
{
if (_instance == null)
_instance = FindObjectOfType<FoodPoolManager>() as FoodPoolManager;
if(_instance==null)
{
GameObject gj = new GameObject("FoodPoolManager");
_instance = gj.AddComponent<FoodPoolManager>();
}
return _instance;
}
}
[Tooltip("食物创建的位置限制")]
public Vector2 leftButtomPosition, rightUpPosition;
[Tooltip("食物的prefab")]
public GameObject[] foods;
[Tooltip("屏幕食物的数量")]
public int foodCount;
//[Tooltip("使用中的食物")]
public List<GameObject> workFood;
//[SerializeField][Tooltip("未使用的食物")]
public List<GameObject> idleFood;
//使用中的食物挂载的父类
private GameObject workObj;
//空闲的食物挂载的父类
private GameObject idleObj;
public void Awake()
{
InitListAndTwoObj();
InitFood();
}
/// <summary>
/// 创建食物
/// </summary>
/// <returns>返回食物</returns>
public GameObject CreateFood()
{
GameObject food = GameObject.Instantiate(foods[Random.Range(0, foods.Length)]);
Vector2 position = new Vector2(Random.Range(leftButtomPosition.x, rightUpPosition.x), Random.Range(leftButtomPosition.y, rightUpPosition.y));
food.transform.position = position;
food.layer = 3;
return food;
}
/// <summary>
/// 初始化两个链表以及挂载所需的两个gameobject
/// </summary>
public void InitListAndTwoObj()
{
workFood = new List<GameObject>();
idleFood = new List<GameObject>();
workObj = new GameObject("work");
idleObj = new GameObject("idle");
workObj.transform.SetParent(this.transform);
idleObj.transform.SetParent(this.transform);
idleObj.SetActive(false);
}
/// <summary>
/// 根据foodCount创建食物
/// </summary>
public void InitFood()
{
for (int i=0;i<foodCount;i++)
{
GameObject go=CreateFood();
workFood.Add(go);
//go.transform.SetParent(workObj.transform);
go.transform.SetParent(workObj.transform);
}
}
public void changeFoodState(GameObject food)
{
food.transform.position = new Vector2(Random.Range(leftButtomPosition.x, rightUpPosition.x), Random.Range(leftButtomPosition.y, rightUpPosition.y));
}
}
3、主角控制移动以及摄像机跟随
主角通过使用EasyTouch插件来实现蛇头的移动,而蛇身体通过一个存储了蛇头移动过的坐标的集合来改变自己的坐标;摄像头的跟随就很简单了,这里给出实现代码:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class SnakeController : MonoBehaviour {
[Tooltip("左侧虚拟摇杆")]
public EasyJoystick easyJoystick;
[Tooltip("蛇移动的速度")]
public int speed;
[Tooltip("蛇头")]
public Sprite[] snakeHeads;
[Tooltip("蛇身体")]
public Sprite[] snakeBodys;
[Tooltip("初始身体的数量")]
public int initBodyNum=4;
[Tooltip("蛇身体对象")]
public GameObject snakeBody;
private Quaternion direction;
//蛇头产生的一些坐标
private List<Vector2> oldPositionList;
//蛇身体移动的步数
private int positionLength=5;
//生成的蛇身体
public List<GameObject> _bodys;
//皮肤的编号
private int skinNum;
// Use this for initialization
public int addLengthNeedFood = 10;
public int addLengthNeedFoodReset = 10;
[Tooltip("击杀的敌人")]
public int killEnemyNum = 0;
public bool isSpeedUp=false;
public Text gameOverLengthText;
public Text killEnemyText;
void Start () {
//Debug.Log("游戏开始了,蛇头的名字是" + "skin" + StaticData.Instance.usingSkinName + "head");
InitHead();
InitBody();
}
// Update is called once per frame
void Update ()
{
GameObject gj=GameObject.Find("length_text");
GameObject gj2= GameObject.Find("kill_text");
Text text=gj.GetComponent<Text>();
Text text2 = gj2.GetComponent<Text>();
text.text = "长度: " + @"<color=blue>"+_bodys.Count.ToString()+@"</color>";
text2.text = "击杀: " + @"<color=blue>" + killEnemyNum.ToString() + @"</color>";
}
private void FixedUpdate()
{
if (GameController.Instance.isGameOver)
{
return;
}
UpdateRotationAndMove();
}
/// <summary>
/// 更新头部的旋转角度
/// </summary>
private void UpdateRotationAndMove()
{
Vector3 joystickAxis = easyJoystick.JoystickAxis;
int tempRunTime = 1;
if (isSpeedUp == true)
tempRunTime = 2;
for (int i=0;i<tempRunTime;i++)
{
oldPositionList.Insert(0, transform.position);
if (joystickAxis == Vector3.zero)
{
Vector3 vec = direction * Vector3.up;
transform.position += vec.normalized * speed * Time.deltaTime;
}
else
{
transform.position += joystickAxis.normalized * speed * Time.deltaTime;
direction = Quaternion.FromToRotation(Vector2.up, joystickAxis);
transform.rotation = direction;
}
FollowHead();
}
}
/// <summary>
/// 初始化头部
/// </summary>
private void InitHead()
{
skinNum = System.Int32.Parse(StaticData.Instance.usingSkinName);
var sprite = GetComponent<SpriteRenderer>().sprite;
GetComponent<SpriteRenderer>().sprite = snakeHeads[System.Int32.Parse(StaticData.Instance.usingSkinName) - 1];
if (skinNum == 2 || skinNum == 4)
transform.localScale = new Vector3(1f, 1f, 1);
else
transform.localScale = new Vector3(0.5f, 0.5f, 1);
GetComponent<SpriteRenderer>().sortingOrder = 1;
//创建蛇身体的存储
oldPositionList = new List<Vector2>();
//一开始有5个蛇身体,每个身体的间隔为positionLength个单元
for (int i = 0; i < 6* positionLength + 1; i++)
{
oldPositionList.Add(new Vector2(transform.position.x, transform.position.y - 0.07f * (i + 1) ));
}
}
/// <summary>
/// 初始化身体
/// </summary>
private void InitBody()
{
_bodys = new List<GameObject>();
for (int i=0;i<initBodyNum;i++)
{
GameObject go = new GameObject("body");
var comp = go.AddComponent<SpriteRenderer>();
comp.sprite = snakeBodys[skinNum - 1];
//因为父类对象缩小了0.5,所以这里要除以2
go.transform.SetParent(snakeBody.transform);
//go.transform.position = new Vector3(transform.position.x,
//go.transform.position=new Vector3(transform.position.x,
//-0.5f * (i + 1),
//0);
// , transform.position.z);
comp.sortingLayerName = "character";
if (skinNum == 2 || skinNum == 4)
go.transform.localScale = new Vector3(1f, 1f, 1f);
else
go.transform.localScale = new Vector3(0.5f, 0.5f, 1f);
var collider = go.AddComponent<CircleCollider2D>();
go.tag = "Player";
_bodys.Add(go);
}
//for (int i = 0; i < _bodys.Count; i++)
//{
// Debug.Log(oldPositionList[(i + 1) * positionLength-1]);
//}
}
/// <summary>
/// 增加身体
/// </summary>
private void AddBody()
{
GameObject go = new GameObject("body");
var comp = go.AddComponent<SpriteRenderer>();
comp.sprite = snakeBodys[skinNum - 1];
//因为父类对象缩小了0.5,所以这里要除以2
go.transform.SetParent(snakeBody.transform);
comp.sortingLayerName = "character";
if (skinNum == 2||skinNum==4)
go.transform.localScale = new Vector3(1f, 1f, 1f);
else
go.transform.localScale = new Vector3(0.5f, 0.5f, 1f);
go.transform.position = transform.position;
var collider = go.AddComponent<CircleCollider2D>();
go.tag = "Player";
// AddAIBody(go.transform);
_bodys.Add(go);
}
/// <summary>
/// 跟随头部
/// </summary>
private void FollowHead()
{
for (int i = 0; i < _bodys.Count; i++)
{
_bodys[i].transform.position = oldPositionList[(i + 1) *( positionLength)];
}
if (oldPositionList.Count>_bodys.Count*positionLength+40)
{
oldPositionList.RemoveAt(oldPositionList.Count - 1);
}
//}
//if ((_bodys.Count+2)*positionLength> oldPositionList.Count)
}
/// <summary>
/// 碰撞检测
/// </summary>
/// <param name="collision"></param>
private void OnTriggerEnter2D(Collider2D collision)
{
//撞到墙,游戏结束
if (collision.tag=="Border")
{
gameOverLengthText.text = "长度 " + "<color=red>" + _bodys.Count.ToString() + "</color>";
killEnemyText.text = "击杀 " + "<color=red>" + _bodys.Count.ToString() + "</color>";
GameController.Instance.GameOver();
}else if (collision.tag=="Food")
{
addLengthNeedFood--;
FoodPoolManager.Instance.changeFoodState(collision.gameObject);
if (addLengthNeedFood == 0)
{
AddBody();
addLengthNeedFood = addLengthNeedFoodReset;
}
}else if (collision.tag == "Player")
{
if (_bodys.Contains(collision.gameObject))
return;
Debug.Log(gameOverLengthText.text);
gameOverLengthText.text = "长度 " + "<color=red>" + _bodys.Count.ToString() + "</color>";
killEnemyText.text = "击杀 " + "<color=red>" + _bodys.Count.ToString() + "</color>";
var sc = collision.transform.parent.parent.GetChild(0).GetComponent<AISnakeController>();
sc.KillEnemy();
GameController.Instance.GameOver();
}
else if(collision.tag=="AIBorder")
{
}
else if (collision.tag == "BigFood")
{
addLengthNeedFood -= 3;
Destroy(collision.gameObject);
if (addLengthNeedFood <= 0)
{
AddBody();
addLengthNeedFood = addLengthNeedFoodReset;
}
}
}
/// <summary>
/// 击杀了敌人
/// </summary>
public void KillEnemy()
{
this.killEnemyNum++;
}
public void SetSpeedUp(bool result)
{
isSpeedUp = result;
}
//public void AddAIBody(Transform parent)
//{
// var go=new GameObject("AIBody");
// go.tag = "AIBody";
// go.transform.localScale = new Vector3(1, 1, 1);
// go.AddComponent<TriggerEnter>();
// var cc=go.AddComponent<CircleCollider2D>();
// cc.radius = 1;
// cc.isTrigger = true;
// go.transform.parent = parent;
// go.transform.localPosition = new Vector3(0f, 0f, 0f);
//}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraFollow : MonoBehaviour {
[Tooltip("蛇头")]
public GameObject snakeHead;
private void LateUpdate()
{
Vector3 vec = snakeHead.transform.position;
transform.position = new Vector3(vec.x,vec.y,-10);
}
}
这样蛇移动以及摄像机跟随的方法就实现了。
第五章节:https://blog.csdn.net/m0_37316917/article/details/81286186
[Untiy]贪吃蛇大作战(四)——游戏主界面的更多相关文章
- Unity3D游戏贪吃蛇大作战源码休闲益智手机小游戏完整项目
<贪吃蛇大作战>一款休闲竞技游戏,不仅比拼手速,更考验玩家的策略. 视频演示: http://player.youku.com/player.php/sid/XMzc5ODA2Njg1Ng ...
- 贪吃蛇大作战canvas实现(手机触屏操作)--地图逻辑
//html部分 <!DOCTYPE html><html><head lang="en"> <meta charset="UT ...
- Expo大作战(四十一)【完】--expo sdk 之 Assets,BarCodeScanner,AppLoading
Expo大作战系列完结! 简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与 ...
- Expo大作战(四十)--expo sdk api之 Calendar,Constants
简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人 ...
- Expo大作战(四)--快速用expo构建一个app,expo中的关键术语
简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人 ...
- 用cocos2d-html5做的消除类游戏《英雄爱消除》(3)——游戏主界面
游戏主界面,同时也是主程序,包括sprite的生成加入以及游戏状态的控制. 下面同样贴下源码再讲解; /** * Power by html5中文网(html5china.com) * author: ...
- [知了堂学习笔记]_用JS制作《飞机大作战》游戏_第3讲(玩家发射子弹)
一.公布上一讲中玩家飞机上.下.右移动实现的代码: /*=========================键盘按下事件 keycode为得到键盘相应键对应的数字==================== ...
- 用JS制作《飞机大作战》游戏_第3讲(玩家发射子弹)-陈远波
一.公布上一讲中玩家飞机上.下.右移动实现的代码: /*=========================键盘按下事件 keycode为得到键盘相应键对应的数字==================== ...
- 刺猬大作战(游戏引擎用Free Pascal写成,GUI用C++写成,使用SDL和Qt4)
游戏特性[编辑] 游戏引擎用Free Pascal写成,GUI用C++写成,使用SDL和Qt4[2]. 0.9.12开始支持实时动态缩放游戏画面. 个性化[编辑] 刺猬大作战有着高度定制性 游戏模式: ...
- [知了堂学习笔记]_用JS制作《飞机大作战》游戏_第2讲(四大界面之间的跳转与玩家飞机的移动)
一.通过点击按钮事件,实现四大界面之间的跳转: (一)跳转的思路: 1.打开软件,只显示登录界面(隐藏游戏界面.暂停界面.玩家死亡界面) 2.点击微信登录(QQ登录)跳转到游戏界面,隐藏登录界面 3. ...
随机推荐
- 折腾黑苹果-小新Pro13
最近在闲鱼上购入了一台2020版的联想小新 Pro13,i5 10200u 16g 512g配置,Ax201网卡.这台机子原生硬件就可以完美黑苹果了,不需要更换配件.只是Ax201网卡不能随航和隔空投 ...
- 云小课|MRS基础原理之MapReduce介绍
阅识风云是华为云信息大咖,擅长将复杂信息多元化呈现,其出品的一张图(云图说).深入浅出的博文(云小课)或短视频(云视厅)总有一款能让您快速上手华为云.更多精彩内容请单击此处. 摘要:MapReduce ...
- Elasticsearch Analyzer 内置分词器
Elasticsearch Analyzer 内置分词器 篇主要介绍一下 Elasticsearch中 Analyzer 分词器的构成 和一些Es中内置的分词器 以及如何使用它们 前置知识 es 提供 ...
- Linux--网络基础(概念+协议的了解+OSI七层模型,TCP/IP五层协议,网络数据传输流程)
网络的发展 网络的发展有下面几个阶段: 独立模式:计算机最开始是以单机模式被广泛使用的.每一台计算机都是独立的,之间不能够进行数据共享与通信 网络互联: 计算机之间可以链接在一起,完成数据共享,计算机 ...
- Java学习之Filter与Listener
0x00前言 web中的Filiter:当客户端访问服务端资源的时候,过率器可以把请求拦截下来,完成一些特殊的功能 完成的操作一般都是通用的作用:列如登录验证. web中的Listener一般用于加载 ...
- fastjson远程代码执行漏洞
fastjson漏洞学习记录 免责声明: Fastjson 1.2.24 远程代码执行漏洞 漏洞说明 前提条件 影响范围 漏洞复现 Fastjson<=1.2.47 远程代码执行漏洞 Fastj ...
- XTDrone和PX4学习期间问题记录(一)
XTDrone和PX4学习期间问题记录(一) Written By PiscesAlpaca 前言: 出现问题可以去官方网站http://ceres-solver.org/index.html查看文档 ...
- std C++11 生成随机数组
#include <algorithm> #include <array> #include <iostream> #include <iterator> ...
- ubuntu 下安装串口终端
查看串口设备 # Ubuntu 22.04自动卸载CH341串口 sudo apt remove brltty ls -l /dev/ttyUSB0 # 查看串口设备添加信息 sudo dmesg | ...
- Aspose.Cells设置单元格背景色不生效
Style.BackgroundColor property 获取或设置样式的背景颜色.public Color BackgroundColor { get; set; } 评论 如果要设置单元格的颜 ...