unity学习|2021-9-7 破防了!!!崩溃瞬间,欲哭无泪

家人们,破防啦!! 今天从早上起来就开始画地图,做机关。直到后来发现,左右移动的机关不能带着主角一起移动。
然后经过百度搜索,知道了使用双碰撞体比地面检测盒子要好用一点。然后就开始了我的作死之旅。
通过一番改动,发现梯子上的空气墙设定很难实现,于是想Ctrl+Z回退,却发现回退不了。然后我就改改改,但是怎么改都改不回来,都会出现bug。
然后我想,昨天晚上我保存过,大不了就今天白干嘛!
【unity学习|2021-9-7 破防了!!!崩溃瞬间,欲哭无泪】然后我就点不保存退出,再次打开的时候发现,不仅今天的所有工作白干,而且代码还回不到原来的没有bug的状态。
家人们,我破防了呀!!!
所以大家千万要记得做大的改动之前,一定要备份一下!!!
算了,分享几个我觉得我处理的不错的代码。
关于怪物AI的设定,使用了面向对象的思想。
主要还是延时执行,使在每帧执行的函数Update里不每帧都执行位移,而是在特定条件下才执行。这点我想了很久。

  1. 总类:怪物类 :用于其他怪物继承
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; // 怪物总类别,唯一不能在面板中更改而需要写代码的只是怪物的攻击方式不同 public class MonsterAI : MonoBehaviour {[Header("与怪物距离多少进入攻击距离")] public float attackDistance = 4.0f; [Header("攻击持续时间")] public float attackTime = 2.5f; [Header("攻击后休息时间")] public float changeDirectionTime = 2.0f; [Header("怪物移动的速度")] public float MoveSpeed = 3.0f; [Header("消灭怪物的分数")] public float grade = 20; [Header("死亡预制体")] public GameObject death; // 必须要通过拖拽,在代码中利用tag寻找是找不到的protected float attackDirection = 1; // 怪物攻击方向,默认向左protected float distance; // 怪物与玩家的水平距离protected Animator _animator; protected Rigidbody2D _rigidbody2D; protected GameObject player; protected PlayerController playerController; protected Text Grade; protected int id_attack; protected bool isAttack; protected bool isPatrol = true; // 是否正在巡逻protected bool targeted = false; // 是否锁定目标,为了巡逻和攻击之间的转换protected Vector2 originPosition; protected Vector2 deathPosition; protected virtual void Awake() {_animator = GetComponent(); _rigidbody2D = GetComponent(); player = GameObject.FindGameObjectWithTag("Player"); playerController = player.GetComponent(); Grade = GameObject.FindGameObjectWithTag("Grade").GetComponent(); id_attack = Animator.StringToHash("attack"); distance = 100; //解决怪物出生时就攻击的bugoriginPosition = transform.position; }// Update is called once per frame protected virtual void Update() {if (player != null) {distance = transform.position.x - player.transform.position.x; } if (transform.position.y < -10 || transform.position.y > 10) {Destroy(gameObject); } if (Mathf.Abs(distance) <= attackDistance) {isPatrol = false; } else {isPatrol = true; } }protected virtual void Attack() {JudgeDirection(); isAttack = true; _animator.SetBool(id_attack, isAttack); Invoke("Rest", attackTime); // 延时执行休息,也是为了保证攻击时间 }// 休息,不再攻击 protected virtual void Rest() {_animator.SetBool(id_attack, false); Invoke("AttackAgain", changeDirectionTime); // 延时执行判断方向 }// 再次攻击,判断方向 protected virtual void AttackAgain() {isAttack = false; // 延时执行使isAttack=false的原因是为了执行完休息动画,也是为了让怪物不瞬间再次进入攻击状态 }// 休息时判断方向 protected virtual void JudgeDirection() {if (distance >= 0) {attackDirection = 1; } else {attackDirection = -1; } _rigidbody2D.transform.localScale = new Vector3(attackDirection, 1, 1); }protected virtual void OnCollisionEnter2D(Collision2D collision) {if (collision.collider.tag == "Player") {if ((player.GetComponent().GetBool("fall")&& player.transform.position.y - transform.position.y >= 0.1f) || (player.transform.position.y - transform.position.y >= 0.5f && player.GetComponent().GetBool("jump"))) {playerController.Jump(); Grade.text = (int.Parse(Grade.text) + grade).ToString(); deathPosition = transform.position; Instantiate(death, deathPosition, Quaternion.identity); Destroy(gameObject); } else {playerController.isHurt = true; } } } }

  1. 青蛙类: 开始时待机,玩家进入攻击范围后,向玩家方向跳跃,两秒后停止,判断玩家方向,再次进行攻击,直至玩家脱离青蛙攻击范围。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Frog : MonsterAI {[Header("跳跃力")] public float JumpForce = 2.0f; [Header("地面检测层")] public LayerMask groundMask; [Header("地面检测盒子的高度")] public float BoxHeight = 0.2f; private Vector2 frogsize; // 青蛙大小private Vector2 boxsize; // 检测盒子尺寸protected override void Awake() {base.Awake(); frogsize = GetComponent>().bounds.size; boxsize = new Vector2(frogsize.x * 0.2f, BoxHeight); // 设置检测盒的大小 }protected override void Update() {base.Update(); }void FixedUpdate() {if (!isPatrol && !isAttack) {Attack(); } }protected override void Attack() {base.Attack(); }protected override void Rest() {base.Rest(); }protected override void AttackAgain() {base.AttackAgain(); }protected override void JudgeDirection() {base.JudgeDirection(); }protected override void OnCollisionEnter2D(Collision2D collision) {base.OnCollisionEnter2D(collision); }void Jump() {if (IsOnGround()) {_rigidbody2D.velocity = new Vector2(MoveSpeed * -attackDirection, JumpForce); } }private bool IsOnGround() {Vector2 boxcenter = (Vector2)transform.position + (Vector2.down * frogsize.y * 0.3f); return Physics2D.OverlapBox(boxcenter, boxsize, 0, groundMask); }private void OnDrawGizmos() {Vector2 boxcenter = (Vector2)transform.position + (Vector2.down * frogsize.y * 0.3f); Gizmos.color = Color.blue; Gizmos.DrawWireCube(boxcenter, boxsize); } }

  1. 负鼠类:开始时左右巡逻,待玩家进入攻击范围后,迅速向玩家冲刺。冲刺1.5秒后,判断方向,再次攻击,直至玩家脱离攻击范围,负鼠再次确定左右边界,进行巡逻。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Opossum : MonsterAI {private float left, right; // 巡逻的左右边界private int patrolDir = 1; // 巡逻方向,默认向左private float Timer = 3.0f; // 3秒防止巡逻时卡住protected override void Awake() {base.Awake(); }protected override void Update() {base.Update(); }void FixedUpdate() {if (!isPatrol) {if (!isAttack) {Attack(); } else {transform.position += Vector3.left * attackDirection * MoveSpeed * Time.deltaTime; } } else if (isPatrol) {Patrol(); } }private void Patrol() {Timer -= Time.deltaTime; if (!targeted) {targeted = true; originPosition = transform.position; } _rigidbody2D.transform.localScale = new Vector3(patrolDir, 1, 1); left = originPosition.x - 4; right = originPosition.x + 4; transform.position += Vector3.left * patrolDir * MoveSpeed / 2 * Time.deltaTime; if (transform.position.x < left || transform.position.x > right || Timer <= 0) {patrolDir = -patrolDir; Timer = 3.0f; } }protected override void Attack() {base.Attack(); targeted = false; }protected override void Rest() {base.Rest(); }protected override void AttackAgain() {base.AttackAgain(); }protected override void JudgeDirection() {base.JudgeDirection(); }protected override void OnCollisionEnter2D(Collision2D collision) {base.OnCollisionEnter2D(collision); } }

  1. 老鹰类:开始时上下巡逻,待玩家进入攻击范围后,迅速飞向玩家进行攻击。冲刺1.5秒后,判断方向,再次攻击,直至玩家脱离攻击范围,老鹰再次确定上下边界,进行巡逻。 (我觉得难点是老鹰的重力处理以及与玩家碰撞后的弹力处理)
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Eagle : MonsterAI {private float up, down; // 巡逻的上下边界private int patrolDir = 1; // 巡逻方向,默认向上private Vector2 currentDir; protected override void Awake() {base.Awake(); }protected override void Update() {base.Update(); }void FixedUpdate() {if (!isPatrol) {if (!isAttack) {Attack(); } else {transform.position += (Vector3)currentDir * MoveSpeed * Time.deltaTime; } } else if (isPatrol) {Patrol(); } }private void Patrol() {if (!targeted) {targeted = true; _rigidbody2D.velocity = Vector2.zero; originPosition = transform.position; } _rigidbody2D.transform.localScale = new Vector3(attackDirection, 1, 1); up = originPosition.y + 3; down = originPosition.y - 3; transform.position += Vector3.up * patrolDir * MoveSpeed / 3* Time.deltaTime; if (transform.position.y < down || transform.position.y > up) {patrolDir = -patrolDir; } }protected override void Attack() {if (player != null)// 防止人物在鹰的范围内被击败导致的空引用问题 {currentDir = Vector3.Normalize(player.transform.position - transform.position); // 重新转换上下边界 } base.Attack(); targeted = false; }protected override void Rest() {base.Rest(); Patrol(); }protected override void AttackAgain() {base.AttackAgain(); }protected override void JudgeDirection() {base.JudgeDirection(); }protected override void OnCollisionEnter2D(Collision2D collision) {base.OnCollisionEnter2D(collision); _rigidbody2D.velocity = Vector2.zero; } }

    推荐阅读