坦克大战经典复刻【附资源&源码】

1个月前 (01-07 08:03)阅读1回复0
zaibaike
zaibaike
  • 管理员
  • 注册排名1
  • 经验值165935
  • 级别管理员
  • 主题33187
  • 回复0
楼主

第一次在知乎上颁发长篇文章,希望各人喜好!​

❥游戏申明:

❥除了音效,游戏地图上的元素有:

❀草丛(玩家能够躲进去,仇敌攻击不到)

❀河流(两边都过不去,但是枪弹能够穿过)

❀铁墙(坦克和枪弹都过不去)

❀砖墙(一发枪弹摧毁后坦克能够过去)

❀空气墙(围在地图四周,避免出界)

❀敌方大坦克(打两下才死)

❀敌方小坦克(打一下就死)

❀有玩家1和玩家2,能够选择单人/双人形式

❥地图是随机生成的,每次翻开都纷歧样,丰硕了游戏的多样性和可玩性。敌方坦克(包罗大小坦克)一次最多存在3个,被摧毁后间隔3s在地图的左上/右上/上面中间 随机生成响应数量的。

❥输赢的判断:

敌方坦克数目必然,每覆灭一个获得1分,覆灭满20个,也就就是得分20分获得成功,玩家本身有3生命值(即3条生命),被击中一次丧失1条生命而且在出生点新生,获得3s的无敌效果。生命耗尽或者老家被摧毁,就game over。

❥能够理解为有10个类: ☀️项目效果展现那里的gif是用了一款ScreenToGif的软件录造的,处置的比力短右侧图标别离暗示覆灭的仇敌数量(上) 和 当前的生命值(下),被击中一次生命值-1,变成0的时候玩家灭亡,游戏完毕 ☀️媒介 ⭐️相关布景博主在大二暑期接触了unity,借鉴实战视频上手花两天复刻了 “坦克大战” 那一典范小游戏,发现做游戏那种过程实的比玩儿游戏还要爽啊,hh,看着一些功用逐步被实现,游戏越来越完好,实的是挺令人温馨和爽快。因为那时候零根底间接上手,关于一些根底操做实的是不太纯熟,很不灵敏,幸亏有一些前辈的帮忙(好比CSDN小伙伴们熟悉的y哥),处理了一些本身难以处理的问题,帮忙小虾在苍茫的夜海上扒开奥秘的迷雾。第一次在知乎上颁发长篇文章,希望各人喜好!⭐️相关常识在进修的过程中,几个比力重要的常识点就是:预造体、克隆体、精灵衬着器、衬着层级、脚本、碰碰检测、触发检测、AI设想、UI设想、固定物理帧...⭐️版本申明小虾接纳的是Unity一个较新的版本-2021.1.16,那里建议小伙伴们下载和教程不异版本的,否则实的会有可能碰到卡点消耗表情哈。能够和我一样在Unity Hub里面安拆,Hub觉得挺好用的。 ⭐️答应证激活那个...有段时间不登仿佛就要从头激活答应证,碰到同样问题的小伙伴能够进入下图的网址:Unity - Activation 按提醒停止操做即可 ⭐️及时保留翻开的时候老是冲动又煎熬,U3D启动有点慢而且操做过程中很可能就会报废,所以项目过程中必然要及时保留,否则一不小心可能就要从头来过啦! ☀️项目概略 ⭐️项目整体规划整个项目工程的一个概略就鄙人面了,Hierarchy菜单下是放 预造体(Prefab) 的 克隆体(Clone) 的,那些克隆体能够拖到左上方的大界面中,通过点击播放按钮停止效果查验。左下方的就是整体的动画效果显示了。做一个小游戏项目,我们起首需要素材,那里保举初学的小伙伴去siki学院进修,里面会有响应的完好初级案例教程。 ⭐️料想验证进修的过程就是不竭验证料想并领受新常识的过程,我原来想坦克大战里面的地图就是把预先处置好的 “砖墙、水泥墙、草坪、河流、空气墙(避免Object越过鸿沟的)” 根据必然规律和本身的爱好摆铺开来做为整张地图的,但事实打脸了(觉得本身实傻)。在 地图实例化(MapCreation) 中,我们利用了 “产生随机位置” 的办法,在避开已有位置的根底上,主动生成其它的地图元素。

代码如下:

// 产生随机位置的办法 private Vector3 CreateRandomPosition() // 列表中没有那个位置,才气产生 { while(true) { // 不生成x=-13,13(变成10)那两列,y=-8,8那两行的位置 Vector3 createPosition = new Vector3( Random.Range(-9,10), Random.Range(-7,8), 0); // x y z,Random.Range(a,b)中b的现实值是b-1 if(!HasThePosition(createPosition)) { return createPosition; // 列表中没有的位置就返回 } // false 则继续轮回 } } ⭐️分步介绍(连系代码) ❀Barrier.cs目标:挪用音效代码如下:using System.Collections; using System.Collections.Generic; using UnityEngine; public class Barrier : MonoBehaviour { public AudioClip hitAudio; public void PlayAudio() { AudioSource.PlayClipAtPoint(hitAudio, transform.position); } } ❀Born.cs目标:让特效播放一段时间后自我销毁,产生玩家思绪:起首引用玩家playerPrefab,新建一个仇敌的数组做为仇敌预造体的列表,并设置bool变量判断枪弹是谁产生的。游戏一起头时,挪用延时Born办法,颠末延时销毁出生特效。判断能否是玩家,是则产生玩家,不是就定义一个随机数,随机生成2种仇敌中的1种。代码如下:using System.Collections; using System.Collections.Generic; using UnityEngine; public class Born : MonoBehaviour { public GameObject playerPrefab; // 先拿一下玩家的引用 public GameObject[] enemyPrefabList; // 新建一个仇敌的数组:仇敌预造体的列表 public bool createPlayer; // 为了判断枪弹是谁产生的(初始默认为仇敌的) // Start is called before the first frame update void Start() { Invoke("BornTank", 1.0f); // 让游戏一起头挪用一下延时Born办法 Destroy(gameObject, 1.0f); // 颠末0.8f延时0.8f销毁出生特效 } private void BornTank() { if(createPlayer) // ture则产生玩家 { Instantiate(playerPrefab, transform.position, Quaternion.identity); } else // 仇敌有两种,定义一个随机数 { int num = Random.Range(0,2); // 0 1(整型情况包罗前两个) Instantiate(enemyPrefabList[num], transform.position, Quaternion.identity); } } } ❀Bullet.cs目标:模仿枪弹和相关物体的碰碰效果思绪:起首给枪弹一个速度,那个速度要适中设置,建议和玩家挪动速度不异。设置一个bool变量 isPlayerBullet(默认false,不是仇敌的枪弹),再分6类完美枪弹碰碰检测的办法。代码如下:using System.Collections; using System.Collections.Generic; using UnityEngine; public class bullet : MonoBehaviour { public float moveSpeed = 10; public bool isPlayerBullet; // 默认false,不是仇敌的枪弹 void Update() { transform.Translate(transform.up * moveSpeed * Time.deltaTime, Space.World); //让枪弹沿着本身所在Y轴挪动 } //枪弹碰碰检测的办法 private void OnTriggerEnter2D(Collider2D collision) { switch (collision.tag) { case "Tank": if (!isPlayerBullet) // 玩家碰着仇敌的枪弹 { collision.SendMessage("Die"); // 玩家灭亡一次 Destroy(gameObject); // 玩家灭亡,本身枪弹销毁 } break; case "Heart": collision.SendMessage("Die"); // 老家灭亡 Destroy(gameObject); // 枪弹碰老家,枪弹销毁 break; case "Enemy": if(isPlayerBullet) // 仇敌碰着玩家的枪弹 { collision.SendMessage("Die"); // 仇敌灭亡一次 Destroy(gameObject); // 仇敌灭亡,本身枪弹销毁 } break; case "Wall": Destroy(collision.gameObject); // 枪弹碰着,墙就销毁 Destroy(gameObject); // 枪弹碰墙,枪弹也销毁 break; case "Barrier": if(isPlayerBullet) // 玩家的枪弹才有音效 { collision.SendMessage("PlayAudio"); } Destroy(gameObject); // 枪弹碰着不成销毁的障碍(铁墙和空气墙),枪弹本身销毁 break; default: break; } } } ❀Enemy.cs目标:实现敌方坦克的攻击、挪动、灭亡操做并优化 仇敌(Enemy) 的AI思绪:那里要用到精灵衬着器,我们要考虑枪弹的扭转角度、敌方坦克上下摆布的挪动操做,攻击的CD、改动标的目的的时间计时器以及攻击、挪动和灭亡的详细办法的实现。最初,为了使玩家获得愈加流利温馨的体验,我们要优化 仇敌(Enemy) 的AI。Tips:我们要用到 void FixedUpdate() 那个生命周期函数,它也叫固定物理帧,包管在每一秒都匀称的情况下施行...代码如下:using System.Collections; using System.Collections.Generic; using UnityEngine; public class Enemy : MonoBehaviour { //属性值 public float moveSpeed = 3; private Vector3 bulletEulerAngles; // 枪弹应该扭转的角度 private float v = -1; private float h; //引用 private SpriteRenderer sr; public Sprite[] tankSprite; // 暗示(上 右 下 左)标的目的;因为要改动精灵的值,所以设一个精灵数组(也就是拿一个和精灵值同类型的属性) public GameObject bulletPrefab; public GameObject explosionPrefab; //计时器 private float timeVal; // 攻击CD(计时器) private float timeValChangeDirection; // 改动标的目的的时间计时器(一起头若设为4是为了使其已呈现就挪动) private void Awake() // 一般的引用在awake中赋值比力好,因为所有属性确实定和引用都应该在游戏物体一起头的时候就拿到 { sr = GetComponent<SpriteRenderer>(); // 拿到了精灵衬着的组件 // 接下往来来往控造它的图片属性就能够了 } void Update() { // 攻击的时间间隔 if (timeVal >= 3f) { } else { } } void FixedUpdate() // 生命周期函数,也叫固定物理帧,是在每一秒都匀称的情况下施行的 { Move(); } //坦克的攻击办法 public void Attack() { //枪弹产生的角度:当前坦克的角度+枪弹应该扭转的角度(rotation中的欧拉角要转为四元数的形式暗示角度) //枪弹预造体 坦克位置 扭转角 timeVal = 0; } // 坦克的挪动办法 private void Move() // 把挪动代码封拆成 Move()函数 { // 下面的仇敌AI只是为了控造h和v的值,下面和player一样按照值选择图片 if(timeValChangeDirection >= 4) // 攻击一次后改动标的目的 { int num = Random.Range(0, 8); // 多定义4个,为了让朝下的概率变大 if(num > 5) // 向下(确保概率较大) { } else if(num == 0) // 向上(确保概率较小) { } else if (num > 0 && num <=2) // 向左 { } else if (num > 2 && num <= 4) // 向右 { } timeValChangeDirection = 0; // 归零避免鬼畜运动 } else { // 因为move()的办法是放在void FixedUpdate()里面的 } //控造玩家的挪动,Vector3.right 暗示X轴标的目的的挪动,Y轴是up,Z轴是forward if (v < 0) { sr.sprite = tankSprite[2]; bulletEulerAngles = new Vector3(0, 0, -180); } else if (v > 0) { sr.sprite = tankSprite[0]; bulletEulerAngles = new Vector3(0, 0, 0); } if (v != 0) // 确保根据上下挪动的同时不克不及停止摆布挪动 { return; } transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World); //Time.deltaTime:按每秒挪动;逗号右边的第二个标的目的是以世界坐标轴的标的目的 if (h < 0) { } else if (h > 0) { } } // 坦克的灭亡办法 private void Die() { // 仇敌每次灭亡,就让得分+1 PlayerManager.Instance.playerScore++; // 产生爆炸特效 Instantiate(explosionPrefab, transform.position, transform.rotation); //灭亡 Destroy(gameObject); } //优化Enemy的AI:若仇敌相碰,顺时针扭转一个角度,如许能制止扎堆 private void OnCollisionEnter2D(Collision2D collision) // 坦克是碰碰检测 { if(collision.gameObject.tag=="Enemy") { // 时间霎时到达4,即刻扭转 } } } ❀Explosion.cs目标:实现爆炸效果思绪:那里的爆炸效果是刚出生的爆炸特效,持续短暂时间后消逝就好,也就是只感化一小段时间代码如下:using System.Collections; using System.Collections.Generic; using UnityEngine; public class Explosion : MonoBehaviour { void Start() { Destroy(gameObject, 0.167f); } } ❀Heart.cs目标:模仿 老家(Heart)思绪:起头的时候就获取一下精灵衬着器组件,一旦触发老家灭亡效果,就改换为老家被毁坏时的图片,并附加爆炸特效。被击中的时候要挪用一下 dieAudio音效。代码如下:using System.Collections; using System.Collections.Generic; using UnityEngine; public class Heart : MonoBehaviour { private SpriteRenderer sr; public Sprite BrokenSprite; // 为了获取老家(Heart)被毁坏时的图片 public GameObject explosionPrefab; // 拿一下爆炸效果的引用 public AudioClip dieAudio; void Start() { sr = GetComponent<SpriteRenderer>(); // 起头的时候就获取一下精灵衬着器组件 } public void Die() { // 改换图片:一旦触发老家灭亡效果,就改换为老家被毁坏时的图片 // 产生爆炸特效 PlayerManager.Instance.isDefeat = true; // 被击中 // 在某个点挪用一下dieAudio } } ❀MapCreation.cs目标:地图实例化思绪:我们在已知固定位置的处所手动生成,并将它们放在一个列表中,其他的位置用随机生成位置的办法生成地图,如许每次玩家进入游戏的时候,就是一张崭新的地图了,那就丰硕了游戏的多样性和可玩性。我们将仇敌位置的生成也放在那部门代码中。代码如下:using System.Collections; using System.Collections.Generic; using UnityEngine; public class MapCreation : MonoBehaviour // 地图实例化 { // 用来粉饰初始化地图所需物体的数组 // 0.老家 1.墙 2.障碍 3.出生效果 4.河流 5.草 6.空气墙 public GameObject[] item; // 已经有工具的位置列表 private List<Vector3> itemPositionList = new List<Vector3>(); private void Awake() { InitMap(); } private void InitMap() { // 实例化老家(CreateItem其实仍是用的Instantiate的办法) CreateItem(item[0], new Vector3(0, -8, 0), Quaternion.identity); // Quaternion.identity:无扭转 //用墙把老家围起来 CreateItem(item[1], new Vector3(-1, -8, 0), Quaternion.identity); CreateItem(item[1], new Vector3(1, -8, 0), Quaternion.identity); for (int i = -1; i < 2; i++) { CreateItem(item[1], new Vector3(i, -7, 0), Quaternion.identity); } // 实例化外围墙 x=-14,14(变成11),y=-9,9 for (int i = -11; i < 12; i++) //最上面一行 { CreateItem(item[6], new Vector3(i, 9, 0), Quaternion.identity); } for (int i = -11; i < 12; i++) //最下面一行 { CreateItem(item[6], new Vector3(i, -9, 0), Quaternion.identity); } for (int i = -8; i < 9; i++) //最左面一行 { CreateItem(item[6], new Vector3(-11, i, 0), Quaternion.identity); } for (int i = -8; i < 9; i++) //最右面一行 { CreateItem(item[6], new Vector3(11, i, 0), Quaternion.identity); } // 初始化玩家(通过实例化出生特效实例化玩家) GameObject go = Instantiate(item[3], new Vector3(-2, -8, 0), Quaternion.identity); // 产生出生特效 go.GetComponent<Born>().createPlayer = true;// 特效上的bool值设置为true:产生玩家 // 产生仇敌(在固定的三个位置先产生,之后每隔一段时间在三个位置随机产生) CreateItem(item[3], new Vector3(-10, 8, 0), Quaternion.identity); CreateItem(item[3], new Vector3(0, 8, 0), Quaternion.identity); CreateItem(item[3], new Vector3(10, 8, 0), Quaternion.identity); InvokeRepeating("CreateEnemy", 4, 5); // 实例化地图 for (int i = 0; i < 60; i++) { CreateItem(item[1], CreateRandomPosition(), Quaternion.identity); } for (int i = 0; i < 20; i++) { CreateItem(item[2], CreateRandomPosition(), Quaternion.identity); } for (int i = 0; i < 20; i++) { CreateItem(item[4], CreateRandomPosition(), Quaternion.identity); } for (int i = 0; i < 20; i++) { CreateItem(item[5], CreateRandomPosition(), Quaternion.identity); } } private void CreateItem(GameObject createGameObject,Vector3 createPosition,Quaternion createRotation) // 封拆一个办法:使播放时Hierarchy菜单下的工具不散落 { // 按照上面的参数实例化游戏物体 // Parent是当前的游戏物体 // 把所有呈现过的物体位置存进位置列表 } // 产生随机位置的办法 private Vector3 CreateRandomPosition() // 列表中没有那个位置,才气产生 { while(true) { // 不生成x=-13,13(变成10)那两列,y=-8,8那两行的位置 Vector3 createPosition = new Vector3( Random.Range(-9,10), Random.Range(-7,8), 0); // x y z,Random.Range(a,b)中b的现实值是b-1 if(!HasThePosition(createPosition)) { return createPosition; // 列表中没有的位置就返回 } // false 则继续轮回 } } // 用来判断位置列表中能否有那个位置 private bool HasThePosition(Vector3 createPos) { for (int i = 0; i < itemPositionList.Count; i++) // 遍历当前的位置列表 { if(createPos == itemPositionList[i]) // 若是随机产生位置的值等于当前列表某个位置的值 { return true; } } return false; } // 产生仇敌的办法 private void CreateEnemy() { int num = Random.Range(0, 3); // 0 1 2 Vector3 EnemyPos = new Vector3(); // 拆随机产生的位置:向量/坐标 if (num == 0) { } else if (num == 1) { } else { } CreateItem(item[3], EnemyPos, Quaternion.identity); } } ❀Option.cs目标:选项监听实现代码如下:using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class Option : MonoBehaviour { private int choice = 1; public Transform posOne; public Transform posTwo; // Update is called once per frame void Update() { // 监听起头界面上下挪动的选项 if (Input.GetKeyDown(KeyCode.W)) { choice = 1; transform.position = posOne.position; } else if (Input.GetKeyDown(KeyCode.S)) { choice = 2; transform.position = posTwo.position; } if (choice==1 && Input.GetKeyDown(KeyCode.Space)) { SceneManager.LoadScene(1); // 加载 Main 场景 } } } ❀Player.cs目标:模仿玩家坦克Player思绪:玩家坦克Player 的实现能够借鉴 敌方坦克Enemy代码如下:using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { //属性值 public float moveSpeed = 3; private Vector3 bulletEulerAngles; // 枪弹应该扭转的角度 private float timeVal; // 攻击CD(计时器) private float defendTimeVal = 3; // 无敌CD(计时器) private bool isDefended = true; // 无敌形态 //引用 // 拿到衬着器 // 拿到需要用到的图片,(上 右 下 左)标的目的;因为要改动精灵的值,所以设一个精灵数组(也就是拿一个和精灵值同类型的属性) public GameObject bulletPrefab; public GameObject explosionPrefab; public GameObject defendEffectPrefab; // 控造音效的播放 // 拿到音效播放的资本 private void Awake() // 一般的引用在awake中赋值比力好,因为所有属性确实定和引用都应该在游戏物体一起头的时候就拿到 { // 拿到了精灵衬着的组件 // 接下往来来往控造它的图片属性就能够了 } void Update() { // 无敌CD if(isDefended) { defendEffectPrefab.SetActive(true); // 控造无敌形态时护盾翻开 defendTimeVal -= Time.deltaTime; if(defendTimeVal <= 0) { isDefended = false; // 控造无敌形态时护盾封闭 } } } private void FixedUpdate() {// 生命周期函数,也叫固定物理帧,是在每一秒都匀称的情况下施行的 if(PlayerManager.Instance.isDefeat) { return; // true则return:游戏失败,制止玩家所有操做 } Move(); // 攻击CD if (timeVal >= 0.4f) { Attack(); } else { timeVal += Time.fixedDeltaTime; } } //坦克的攻击办法 public void Attack() { if() //若检测到玩家输入为空格键 { //枪弹产生的角度:当前坦克的角度+枪弹应该扭转的角度(rotation中的欧拉角要转为四元数的形式暗示角度) //枪弹预造体 坦克位置 扭转角 timeVal = 0; } } // 坦克的挪动办法 private void Move() // 把挪动代码封拆成 Move()函数 { // 监听玩家垂曲轴值的输入 transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World); if (v < 0) { } else if (v > 0) { } // v和h不为0,播放...音效 (在判断v能否为0之前判断是考虑了它的优先级) if(Mathf.Abs(v)>0.05f) { // 若音效播放时又挪用,声音会很杂,所以要判断... if(!moveAudio.isPlaying) { moveAudio.Play(); } } if (v != 0) { // 确保根据上下挪动的同时不克不及停止摆布挪动 return; } //监听玩家程度轴值的输入h来控造在X轴上的位移的标的目的,按右标的目的为1,左为-1 //控造玩家的挪动,Vector3.right 暗示X轴标的目的的挪动,Y轴是up,Z轴是forward transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World); //Time.deltaTime:按每秒挪动;逗号右边的第二个标的目的是以世界坐标轴的标的目的 if (h < 0) { } else if (h > 0) { } if (Mathf.Abs(h) > 0.05f) { moveAudio.clip = tankAudio[1]; if (!moveAudio.isPlaying) { moveAudio.Play(); } } else { moveAudio.clip = tankAudio[0]; if (!moveAudio.isPlaying) { moveAudio.Play(); } } } // 坦克的灭亡办法 private void Die() { // 能否处于无敌形态 if (isDefended) { return; } // 击中的话,就让玩家办理里面的属性变成true PlayerManager.Instance.isDead = true; // 产生爆炸特效 Instantiate(explosionPrefab, transform.position, transform.rotation); //灭亡 Destroy(gameObject); } } ❀PlayerManager.cs目标:弄法办理和UI设想代码如下:using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; using UnityEngine.UI; // 为了更新 UI,拿一下它的引用,利用 UI,就要拿一下Unity的运营空间 using UnityEngine.SceneManagement; public class PlayerManager : MonoBehaviour { //属性值 public int lifeValue = 3; public int playerScore = 0; public bool isDead; public bool isDefeat; //引用 public GameObject born; public Text playerScoreText; public Text playerLifeValueText; public GameObject isDefeatUI; // 拿一下流戏物体的引用 //单例 private static PlayerManager instance; public static PlayerManager Instance { get => instance; set => instance = value; } private void Awake() { Instance = this; } // Update is called once per frame void Update() // 在此中实时监听一些形态 { if(isDefeat) // 失败的话 { isDefeatUI.SetActive(true); // 让失败的图片显示 return; } if(isDead) // 若是灭亡 { Recover(); } // 实时更新覆灭仇敌的显示和生命值 playerScoreText.text = playerScore.ToString(); // .ToString():把int转化为字符串 playerLifeValueText.text = lifeValue.ToString(); } private void Recover() { if (lifeValue<=0) { // 游戏失败,返回主界面 isDefeat = true; Invoke("ReturnToTheMainMenu", 3); // 延时3s挪用那个办法 } else { lifeValue --; GameObject go = Instantiate(born, new Vector3(-2, -7.9f, 0), Quaternion.identity); // 领受born的脚本 go.GetComponent<Born>().createPlayer = true; isDead = false; } } private void ReturnToTheMainMenu() { SceneManager.LoadScene(0); // 返回起头界面 } } ☀️进修/造做过程txt记录天职享

流水账,实的能够忽略了

坦克大战:做动画特效时,播放动画后新建了一个另一个特效,再次播放时,新特效不只不会播放,新建的内容也会主动消逝,可能是播放和保留起了抵触

****************若何处理昨晚的截图问题

(已处理:没有添加vs)

****************若何处理玩家的朝向问题

(办法1.切换图片的衬着和显示,能够在Inspector查看;办法2.间接让图片沿着Z轴扭转)

图片的衬着工做是由Sprite renderer那个精灵衬着器主页来控造的,通过改动此中Sprite的值就能够改动图片的衬着

*************难点:碰碰检测和触发检测

一、发作碰碰检测需要前提:1.两个发作碰碰的物体都需要有碰碰器 2.此中一方(更好是运动的一方)要有刚体【要在运动的一方是因为:经常性的不运动后,刚体味休眠,那是无法发作碰碰检测】

二、留意点:碰碰器分为两大类,2D要配2D的,不然没用

三、要想发作碰碰检测和触发检测,要调整衬着层级的挨次,挨次不异才会发作触发检测。

************************

在Hierarchy中,对克隆体的操做不会间接应用到预造体上,因为Hierarchy中的只是克隆体,点apply能够应用;在预造体上操做,会主动存到克隆体上

************************

play时player发作颤动是因为加上刚体之后有受力,希望每一帧受力平均,也就是每秒受力大小是平均的,就要在物理帧中施行【认为update中的Time.deltaTime例来解释为何要在FixedUpdate的生命周期中施行:update在施行时,会因为电脑性能之类的差别,每一帧的时间是差别的,所以要设固定物理帧,在此中施行每一帧占用的时间固定】。那也告诉我们,以后再用到刚体停止挪动且有力的交互时,把工具放在固定物理帧的生命周期中运行,如许就不会产生颤动的效果。

**************如何处置物体斜着运动

在h或v上加上优先级

**************2D衬着

***************

每次对克隆体做修改之后,都应该apply一下,让其应用到预造体上

***************

老家被仇敌攻打之后,会变样,就要给它一个衬着。

2D游戏停止衬着时,起首要拿一个精灵衬着器组件。

衬着有优先级【好比坦克大战中,玩家要穿过草坪,枪弹要横跨河流,那就需要衬着一些次序;特效的衬着的优先级要高于玩家,也就是说,特效要可以笼盖玩家】

精灵衬着中有一个Sorting Layer,暗示衬着的层级(大层级),能够通过那个层级的先后挨次控造衬着;Order in layer暗示层级的挨次,叫做小层级,也就是说在大层级下面有一些控造衬着的挨次。

层级(数值)越大,越后衬着,越不容易被笼盖【那个容不容易要按照游戏的需求,由情况决定】

*********************枪弹朝向问题

通过坦克的运动标的目的来确定枪弹的朝向

3D引擎中的2D图片要绕着Z轴扭转(那点切换Scene中的2/3D即可晓得,但那两个形态下的动弹标的目的就像照镜子一样是相反的,因为2D->3D的时候,已经是绕着X轴扭转180度了,因而在Unity 3D下,2D图片的扭转标的目的应为逆时针,和3D的相反)

******************************

每新建一个脚本,都让VS识别一下,制止发作没必要要的错误

**********************用transform.Translate( , )函数时

若要沿着世界坐标轴挪动,前面填Space.World,后面能够填Space.Self或者不填;若沿着玩家所在轴标的目的,前面是玩家....,后面必需要有Space.World

***********************攻击CD

设一个计时器(时间间隔)

***********************触发器

1. 和碰碰器的区别:碰碰器产生碰碰效果;而触发器碰着的时候,会发作触发检测

2. 需要前提:参考碰碰检测

************************空气墙

Ctrl D一个,删去精灵衬着器,移到预造体(Prefab)里

************************

P18 6min

*****************************

UnassignedReferenceException: The variable button of CityScript has not been assigned.

因为我本身挂了两个CityScript脚本在差别的组件上面招致呈现了那个问题。所以有呈现那个问题的童鞋,找找看看有没有挂两个一样的脚本。

*****************************特效飞进来的问题???

做了一个explosion特效(放在了Prefab的Effect下)会飞进来,new了一个Newexplosion特效,只能拖进Prefab,不克不及拖进Effect和explosion并列(unity会有警告)

**************************数组越界的问题

存的数目和数组用到的元素数目不契合

**************************设置了多个仇敌,挂了不异的Enemybulllet脚本???

**************************地图实例化

长:18*2 宽:7.8*2

*************************Player和Enemy挪动的范畴有问题???

*************************Player的出生特效(为啥出生特效丢了,看视频去处理)???

*************************随机生成的地图元素会错乱(因为没有用整型,用了浮点型)

************************* API

InvokeRepeating(办法名,延时几秒后第一次挪用此办法,没隔多久挪用一次)

************************* API

Invoke 每隔一段时间挪用一次某办法,在update里面写一个计时器,让其每隔一段时间挪用一次办法

*********************** UI图片右对齐

缩放界面的时候UI图片具有必然自适性

结束,撒花❀~

0
回帖

坦克大战经典复刻【附资源&源码】 期待您的回复!

取消