[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
https://github.com/li-zheng-hao