游戏主界面:

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

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. 集合元素的遍历操作,使用迭代器Iterator接口

    1.内部的方法:hasNext() 和 next() 推荐的方式: //hasNext():判断是否还有下一个元素while(iterator.hasNext()){ //next():①指针下移 ② ...

  2. JavaScript基础复盘补缺

    语法规范 JavaScript严格区分大小写,对空格.换行.缩进不敏感,建议语句结束加':' JavaScript 会忽略多个空格.您可以向脚本添加空格,以增强可读性. JavaScript 程序员倾 ...

  3. 三十一、kubernetes网络介绍

    Kubernetes 网络介绍 Service是Kubernetes的核心概念,通过创建Service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并且将请求负载分发到后端的各个容器应用上 ...

  4. webpack4--按需加载

    在做单页面应用的过程中,通常利用webpack打包文件,将依赖的外部问价单独打一个vendor.js.这样就会有个问题,这个文件会随着你引用的包的增多,体积会越来越大.在路由中利用import 引用文 ...

  5. js和jquery页面初始化加载函数的方法及顺序

    运行下面代码.弹出A.B.C.D.E的顺序:A=B=C>D=E. <html> <head> <title>首页</title> <scri ...

  6. gdb不能使用mac

    先说问题:1.gdb不能使用,重新用homebrew install 了gdb 2.brew装的gdb可以用了,但是等start调试的时候报这些错误:        dyld: Library not ...

  7. docker和docker-compose便捷安装

    安装docker: curl -fsSL get.docker.com -o get-docker.sh&&sh get-docker.sh 或: curl -sSL https:// ...

  8. 同步与异步、阻塞与非阻塞、创建进程的多种方式、进程间数据隔离、进程的join方法、IPC机制等

    目录 同步与异步 阻塞与非阻塞 综合使用 创建进程的多种方式 进程间数据隔离 进程的join方法 IPC机制 生产者消费者模型 进程对象的多种方法 守护进程 僵尸进程与孤儿进程 多进程数据错乱问题 同 ...

  9. 如何在 K8S 集群范围使用 imagePullSecret?

    在这篇文章中,我将向你展示如何在 Kubernetes 中使用 imagePullSecrets. imagePullSecrets 简介 Kubernetes 在每个 Pod 或每个 Namespa ...

  10. 【大数据面试】【框架】Hive:架构、计算引擎、比较、内外部表、by、函数、优化、数据倾斜、动静态分区

    一.组成 1.架构 源数据原本是存在dubby数据库,存在MySQL可以支持多个客户端 客户端.数据存储(HDFS).MR计算引擎 2.计算引擎的选择 MR引擎:基于磁盘,计算时间长,但一定能算出结果 ...