游戏主界面:

由于这个场景比较复杂,需要分几个部分实现:

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]贪吃蛇大作战(四)——游戏主界面的更多相关文章

  1. Unity3D游戏贪吃蛇大作战源码休闲益智手机小游戏完整项目

    <贪吃蛇大作战>一款休闲竞技游戏,不仅比拼手速,更考验玩家的策略. 视频演示: http://player.youku.com/player.php/sid/XMzc5ODA2Njg1Ng ...

  2. 贪吃蛇大作战canvas实现(手机触屏操作)--地图逻辑

    //html部分 <!DOCTYPE html><html><head lang="en"> <meta charset="UT ...

  3. Expo大作战(四十一)【完】--expo sdk 之 Assets,BarCodeScanner,AppLoading

    Expo大作战系列完结! 简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与 ...

  4. Expo大作战(四十)--expo sdk api之 Calendar,Constants

    简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人 ...

  5. Expo大作战(四)--快速用expo构建一个app,expo中的关键术语

    简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人 ...

  6. 用cocos2d-html5做的消除类游戏《英雄爱消除》(3)——游戏主界面

    游戏主界面,同时也是主程序,包括sprite的生成加入以及游戏状态的控制. 下面同样贴下源码再讲解; /** * Power by html5中文网(html5china.com) * author: ...

  7. [知了堂学习笔记]_用JS制作《飞机大作战》游戏_第3讲(玩家发射子弹)

    一.公布上一讲中玩家飞机上.下.右移动实现的代码: /*=========================键盘按下事件 keycode为得到键盘相应键对应的数字==================== ...

  8. 用JS制作《飞机大作战》游戏_第3讲(玩家发射子弹)-陈远波

    一.公布上一讲中玩家飞机上.下.右移动实现的代码: /*=========================键盘按下事件 keycode为得到键盘相应键对应的数字==================== ...

  9. 刺猬大作战(游戏引擎用Free Pascal写成,GUI用C++写成,使用SDL和Qt4)

    游戏特性[编辑] 游戏引擎用Free Pascal写成,GUI用C++写成,使用SDL和Qt4[2]. 0.9.12开始支持实时动态缩放游戏画面. 个性化[编辑] 刺猬大作战有着高度定制性 游戏模式: ...

  10. [知了堂学习笔记]_用JS制作《飞机大作战》游戏_第2讲(四大界面之间的跳转与玩家飞机的移动)

    一.通过点击按钮事件,实现四大界面之间的跳转: (一)跳转的思路: 1.打开软件,只显示登录界面(隐藏游戏界面.暂停界面.玩家死亡界面) 2.点击微信登录(QQ登录)跳转到游戏界面,隐藏登录界面 3. ...

随机推荐

  1. http://localhost:8282/user/findsomeuser[object%20Object]

    查看vue中的方法的访问路径是否填写正确. 后端:

  2. LeetCode------合并两个有序数组(4)【数组】

    来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/merge-sorted-array 1.题目 给你两个按 非递减顺序 排列的整数数组 nums ...

  3. go-zero docker-compose 搭建课件服务(三):编写courseware api服务

    0.转载 go-zero docker-compose 搭建课件服务(三):编写courseware api服务 0.1源码地址 https://github.com/liuyuede123/go-z ...

  4. 更改DataFrame列顺序

    使用pandas进行数据分析的时候,有时会由于各种需求添加了一些列.可是列的顺序并不能符合自己的期望.这个时候就需要对于列的顺序进行调整. import numpy as np import pand ...

  5. Multi-Channel PCIe QDMA Subsystem

    可交付资料: 详细的用户手册 Design File:Post-synthesis EDIF netlist or RTL Source Timing and layout constraints,T ...

  6. FHQ Treap 详解

    鲜花 一些鲜花放在前面,平衡树学了很久,但是每学一遍都忘,原因就在于我只能 70% 理解 + 30% 背板子,所以每次都忘.这次我采取了截然不同的策略,自己按照自己的理解打一遍,大获成功(?),大概打 ...

  7. cowsay和ansible

    简介 cowsay是一款有趣的ascii图案输出工具,通过它可以方便的输出一头说话的牛牛(马?): # cowsay hello frankming _________________ < he ...

  8. oracle常用查看命令

    select sum(bytes/1024/1024/1024) from dba_segments;   #注:查看表空间大小,除以3个1024后的大小为GB du instance_name(实例 ...

  9. vue3.0使用tui.image-editor图片编辑组件报错TypeError: Cannot convert undefined or null to object

    在vue3.0的项目中使用tui.image-editor组件.一直都是报错.查看报错位置发现代码 addEventListener() { Object.keys(this.$listeners). ...

  10. springboot +mybatis (@autowried 注入mapper :爆红)

    问题描述:Could not autowire. No beans of XXXXmapper' type found 问题相关页面: 解决方式一:@mapper  接口计入@Repository 解 ...