接着上一节:

4、AI蛇的设计

这里AI蛇大部分代码都可以参照主角的代码,我这里的实现其实还可以进行改进。基本原理就是蛇创建之后给蛇一个随机方向的单位向量,AI蛇的蛇头添加一个比蛇头大两三倍大小的碰撞检测盒,效果如图:

当蛇头的碰撞检测盒子与墙壁或者其他蛇的身体碰撞时,给蛇一个反向160-200度的向量,这样AI蛇就不会碰撞到墙壁或者其他蛇的身体上死亡了。代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class AISnakeController : MonoBehaviour {[Tooltip("蛇移动的速度")]public int speed;[Tooltip("蛇头")]public Sprite[] snakeHeads;[Tooltip("蛇身体")]public Sprite[] snakeBodys;[Tooltip("初始身体的数量")]public int initBodyNum = 4;[Tooltip("蛇身体对象")]public GameObject snakeBody;public Quaternion direction;//蛇头产生的一些坐标private List<Vector2> oldPositionList;//蛇身体移动的步数private int positionLength = 5;//生成的蛇身体public List<GameObject> _bodys;//皮肤的编号public int skinNum;// Use this for initializationpublic int addLengthNeedFood = 10;public int addLengthNeedFoodReset = 10;[Tooltip("击杀的敌人")]public int killEnemyNum = 0;void Start(){//Debug.Log("游戏开始了,蛇头的名字是" + "skin" + StaticData.Instance.usingSkinName + "head");direction = Quaternion.Euler(new Vector3(0,0,Random.Range(0f,360f)));InitHead();InitBody();AddAIBody(transform);}// Update is called once per framevoid Update(){}private void FixedUpdate(){if (GameController.Instance.isGameOver){return;}UpdateRotationAndMove();}/// <summary>/// 更新头部的旋转角度/// </summary>private void UpdateRotationAndMove(){oldPositionList.Insert(0, transform.position);Vector3 vec =direction * Vector3.up;transform.position += vec* speed * Time.deltaTime;transform.rotation = direction;FollowHead();}/// <summary>/// 初始化头部/// </summary>private void InitHead(){skinNum = Random.Range(1,5);var sprite = GetComponent<SpriteRenderer>().sprite;GetComponent<SpriteRenderer>().sprite = snakeHeads[skinNum - 1];if (skinNum == 2 || skinNum == 4)transform.localScale = new Vector3(1f, 1f, 1);elsetransform.localScale = new Vector3(0.5f, 0.5f, 1);transform.localPosition = new Vector3(0, 0, 0);GetComponent<SpriteRenderer>().sortingOrder = 1;var cc=gameObject.AddComponent<CircleCollider2D>();var rb = gameObject.AddComponent<Rigidbody2D>();cc.radius = 0.5f;cc.isTrigger = true;rb.gravityScale = 0;//创建蛇身体的存储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,所以这里要除以2go.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);elsego.transform.localScale = new Vector3(0.5f, 0.5f, 1f);go.transform.position = transform.position;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,所以这里要除以2go.transform.SetParent(snakeBody.transform);comp.sortingLayerName = "character";if (skinNum == 2 || skinNum == 4)go.transform.localScale = new Vector3(1f, 1f, 1f);elsego.transform.localScale = new Vector3(0.5f, 0.5f, 1f);go.transform.position = transform.position;var collider = go.AddComponent<CircleCollider2D>();go.tag = "Player";_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 == "Food"){FoodPoolManager.Instance.changeFoodState(collision.gameObject);addLengthNeedFood--;if (addLengthNeedFood <= 0){AddBody();addLengthNeedFood = addLengthNeedFoodReset;}}else if (collision.tag == "Border"){Dead();}else if (collision.tag == "BigFood"){addLengthNeedFood -= 3;Destroy(collision.gameObject);if (addLengthNeedFood <= 0){AddBody();addLengthNeedFood = addLengthNeedFoodReset;}}//}else if (collision .tag=="AIBody")//{//    //if (_bodys.Contains(collision.gameObject))//    //    return;//    //var vec3 = direction.eulerAngles;//    //vec3.z = Random.Range(vec3.z + 180 - 10, vec3.z+ 180 + 10);//    //direction = Quaternion.Euler(vec3);//}else if (collision.tag == "Player"){if (_bodys.Contains(collision.gameObject))return;if (collision.transform.parent.tag == "AI"){AISnakeController sc = collision.transform.parent.parent.gameObject.GetComponent<AISnakeController>();sc.KillEnemy();}else{SnakeController sc2;if (collision.transform.parent.name == "SnakeBody")sc2 = collision.transform.parent.gameObject.GetComponent<SnakeController>();elsesc2 = collision.gameObject.GetComponent<SnakeController>();sc2.KillEnemy();}Dead();}}/// <summary>/// 击杀了敌人/// </summary>public void KillEnemy(){this.killEnemyNum++;}public void ResetState(){foreach (var i in _bodys){Destroy(i);}oldPositionList.Clear();_bodys.Clear();//蛇身体移动的步数positionLength = 5;//生成的蛇身体//皮肤的编号skinNum = Random.Range(1, 5);// Use this for initializationaddLengthNeedFood = 10;addLengthNeedFoodReset = 10;killEnemyNum = 0;var sprite = GetComponent<SpriteRenderer>().sprite;GetComponent<SpriteRenderer>().sprite = snakeHeads[skinNum - 1];if (skinNum == 2 || skinNum == 4)transform.localScale = new Vector3(1f, 1f, 1f);elsetransform.localScale = new Vector3(0.5f, 0.5f, 1f);this.transform.localPosition = new Vector3(0, 0, 0);direction = Quaternion.Euler(new Vector3(0, 0, Random.Range(0f, 360f)));//一开始有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)));}InitBody();}public void AddAIBody(Transform parent){var go = new GameObject("AIBody");go.tag = "AIBody";go.transform.parent = parent;if (skinNum == 2 || skinNum == 4)go.transform.localScale = new Vector3(1f, 1f, 1f);elsego.transform.localScale = new Vector3(2f, 2f, 1f);//go.transform.localScale = new Vector3(2f, 2f, 1);go.transform.localPosition = new Vector3(0f, 0f, 0f);var rb=go.AddComponent<Rigidbody2D>();rb.gravityScale = 0;var cc = go.AddComponent<CircleCollider2D>();cc.radius = 1f;cc.isTrigger = true;go.AddComponent<TriggerEnter>();}public void Dead(){List<Vector2> pos = new List<Vector2>();foreach (var i in _bodys){pos.Add(i.transform.position);}var gj = GameObject.Find("BigFoodSpawner");gj.GetComponent<BigFoodSpawner>().CreateBigFood(pos);ResetState();}
}

5、分数排行的实现

这里的排行榜我们通过脚本获取到每个蛇身上的分数属性来进行随时调整,这里我们需要使用一个排序算法来按照蛇的长度进行排序,排序之后即可按照顺序将蛇的长度和名字显示在排行榜的UI元素上,代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class RankListUpdate : MonoBehaviour {[Tooltip("排行榜的标签")]public GameObject[] rankList;[Tooltip("所有的蛇")]public GameObject[] snakes;// Update is called once per framevoid Update () {}private void LateUpdate(){// Debug.Log(snakes[4].transform.GetChild(0).GetComponent<SnakeController>()._bodys.Count);Sort();UpdateList();}private void Sort(){for (int i=0;i<snakes.Length;i++){for (int j=i+1;j<snakes.Length;j++){//if (snakes[j].name == "Snake")//{//    Debug.LogError("没错啊,输出了4啊");//}//Debug.LogError(i + ":::" + j);int lengthOne = (snakes[i].name=="Snake"? snakes[i].transform.GetChild(0).GetComponent<SnakeController>()._bodys.Count : snakes[i].transform.GetChild(0).GetComponent<AISnakeController>()._bodys.Count);int lengthTwo=(snakes[j].name == "Snake" ? snakes[j].transform.GetChild(0).GetComponent<SnakeController>()._bodys.Count : snakes[j].transform.GetChild(0).GetComponent<AISnakeController>()._bodys.Count);if (lengthOne<lengthTwo){var temp = snakes[i];snakes[i] = snakes[j];snakes[j] = temp;}}}}private void UpdateList(){for (int i=0;i<rankList.Length;i++){int length= (snakes[i].name == "Snake" ? snakes[i].transform.GetChild(0).GetComponent<SnakeController>()._bodys.Count : snakes[i].transform.GetChild(0).GetComponent<AISnakeController>()._bodys.Count);var name=rankList[i].transform.GetChild(0);var score= rankList[i].transform.GetChild(1);name.GetComponent<Text>().text = snakes[i].name;score.GetComponent<Text>().text = length.ToString();}}}

到此,游戏的大部分困难的地方的思路都有了,其他简单的地方有一些unity基础就可以很快实现,希望大家能做出一个更好的贪吃蛇大作战。

有任何思路不顺的地方欢迎给我留言评论或者加我的QQ微信。

[Untiy]贪吃蛇大作战(五)——游戏主界面相关推荐

  1. 基于Java实现的贪吃蛇大作战小游戏

    贪吃蛇大作战小游戏 整体思路与架构 本项目主要分为三个部分,即UI界面.游戏逻辑与网络传输. UI界面部分,主要是为了实现不同界面之间的切换.包括了注册登陆窗口(loginFrame)与游戏主窗口(G ...

  2. JAVA 实现《贪吃蛇大作战》游戏|CSDN创作打卡

    前言 贪吃蛇(也叫做贪食蛇)游戏是一款休闲益智类游戏,有PC和手机等多平台版本.既简单又耐玩.该游戏通过控制蛇头方向吃东西,从而使得蛇变得越来越长. 本程序是通过java的swing来实现<贪吃 ...

  3. Java实现贪吃蛇大作战小游戏(完整教程+源码)额外实现积分和变速功能

    大家好,我是黄小黄同学!今天给大家带来的是小项目是 基于Java+Swing+IO流实现 的贪吃蛇大作战小游戏.实现了界面可视化.基本的吃食物功能.死亡功能.移动功能.积分功能,并额外实现了主动加速和 ...

  4. 贪吃蛇大作战类游戏的实现

    贪吃蛇大作战类游戏的实现 前段时间玩了一个叫做贪吃蛇大作战的手机游戏,一下子就喜欢上了,然后就有了尝试实现的想法. 制作的平台环境:vs2012/cocos2dx3.8.1/C++ 关于贪吃蛇游戏的了 ...

  5. 【经典游戏】贪吃蛇大作战java游戏代码讲解

    <贪吃蛇大作战>一个简单到不行的游戏,也不知道怎么就火了.反正一款游戏火了,各路媒体.专家总能说出种种套路来,所以我就不发表意见了.不过这实在是一个挺好实现的游戏,于是一时技痒,拿 jav ...

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

    游戏主界面: 由于这个场景比较复杂,需要分几个部分实现: 1.游戏背景 首先我们的游戏场景上包括了一个大的背景图片,之外再包围一个红色的区域.中间的区域才是可活动的区域,周围通过碰撞检测盒来检测是否有 ...

  7. [Untiy]贪吃蛇大作战(一)——开始界面

    前言: 刚学unity没多久吧(大概1个月多点),这是我自己做的除官网之外的第一个游戏demo,中间存在很多不足的地方,但是还是希望可以给需要的人提供一些思路和帮助,有问题的小伙伴可以找我一起探讨一起 ...

  8. 【项目实战】轻松实现C/C++大作业:贪吃蛇大作战游戏!

    这是一个贪吃蛇大作战类游戏,修改特性为 AI 不互杀: 该程序有四个类:蛇基类 SnakeBase,玩家类 Player,AI 类,Game 类:SnakeBase 和 AI 均继承自 SnakeBa ...

  9. laya游戏开发之贪吃蛇大作战(一)

    laya游戏开发之贪吃蛇大作战 一.背景 二.引擎选择 三.整体架构 3.1 玩法分析 3.2 游戏架构 3.3 技术选型 一.背景 需要快速实现一个贪吃蛇的 demo 以验证功能,非传统贪吃蛇玩法, ...

最新文章

  1. 《游戏大师Chris Crawford谈互动叙事》一第 9 章 互动小说
  2. OS X终端颜色[关闭]
  3. 依赖版本控制-pom文件介绍
  4. 彻底解决.net中编码问题的心得
  5. Alibaba Druid 源码阅读(一) 数据库连接池初步
  6. 创建student数据表_创建数据库、表和更改表
  7. 验证手机号码归属地_excel函数爬取网页手机号码归属地,1.1%的人还不会!
  8. Rust : 危险! 关于字符串切片以及取值......
  9. 谈一下MVVM 框架
  10. QT_kvaser动态链接库配置
  11. markDown 下载安装教程
  12. 秒杀系统设计思路与实现
  13. 常见的保障盘点结果准确性的方法和盘点差异的处理方法
  14. java 中英日期转换器_Java SimpleDateFormat中英文时间格式化转换详解
  15. Python下载MP4视频
  16. 用手机GPRS使电脑上网
  17. python爬虫获取豆瓣正在热播电影
  18. OpenWRT网页设置
  19. java se包括哪些_Java SE
  20. 海康X86平台智能相机的使用注意事项

热门文章

  1. 基于多目标算法的冷热电联供型综合能源系统运行优化 多目标粒子群 冷热电联供 综合能源系统 运行优化
  2. 面试官:[‘1‘, ‘2‘, ‘3‘].map(parseInt)的结果是什么?为甚?我:[1, 2, 3]。面试官:你不用来了。
  3. 20140722-百度质量部测试开发工程师-实习面试
  4. 1、阅读和了解什么是形式化方法 2、推荐阅读书籍《大象——thinking in UML》
  5. WIFI基础入门--802.11--直接序列物理层(DSSS)--12
  6. CSS-使用background实现四个角边框
  7. 电子器件系列34:tvs二极管(2)
  8. MATLAB语言的串口助手
  9. 共享软件开发者、独立软件开发者
  10. 关键字和关键字优化(转)