游戏主界面:

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

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. 不妨试试更快更小更灵活Java开发框架Solon

    @ 目录 概述 定义 性能 架构 实战 Solon Web示例 Solon Mybatis-Plus示例 Solon WebSocket示例 Solon Remoting RPC示例 Solon Cl ...

  2. 二、Celery执行一步任务

    二.Celery执行异步任务 2.1.基本使用 创建项目celerypro 创建异步任务执行文件celery_task: import celery import time backend='redi ...

  3. Java中math类的常用函数

    Java中math类的常用函数 在 Java 中 Math 类封装了常用的数学运算,提供了基本的数学操作,如指数.对数.平方根和三角函数等 只要在源文件的顶部加上下面这行代码就不必在数学方法名和常量名 ...

  4. Multi-Channel PCIe QDMA Subsystem

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

  5. Xpath 高级用法

    xpath 高级用法 1. 匹配当前节点下的所有: .// . 表示当前 // 表示当前标签下的所有标签 注: 要配合使用 2. 匹配某标签的属性值: /@属性名称 这里以input里的value值为 ...

  6. python基础类型,字符串

    python基本类型小结 # str,可以用索引取值,但是不能通过索引改变值, # a = "123" a[0]=10,直接TypeError因为字符串是不可变类型 # list, ...

  7. P6492 STEP(线段树维护左右区间pushup)

    题目链接 题目描述: 给定一个长度为\(~\)n\(~\)的字符序列\(~\)a,初始时序列中全部都是字符\(~\)L. 有\(~\)q\(~\)次修改,每次给定一个\(~\)x,做出如下变化: \( ...

  8. netty系列之:来,手把手教你使用netty搭建一个DNS tcp服务器

    目录 简介 搭建netty服务器 DNS服务器的消息处理 DNS客户端消息请求 总结 简介 在前面的文章中,我们提到了使用netty构建tcp和udp的客户端向已经公布的DNS服务器进行域名请求服务. ...

  9. nginx转发到uwsgi的配置

    server{ server_name ; listen 80 default_server; add_header Access-Control-Allow-Origin *; add_header ...

  10. 【Java并发001】使用级别:线程相关知识

    一.前言 本文介绍Java线程相关知识(不包括线程同步+线程通信,这个内容在笔者的另一篇博客中介绍过了),包括:线程生命周期.线程优先级.线程礼让.后台线程.联合线程. 二.线程生命周期 2.1 引子 ...