今天从早上起来就开始画地图,做机关。直到后来发现,左右移动的机关不能带着主角一起移动。
然后经过百度搜索,知道了使用双碰撞体比地面检测盒子要好用一点。然后就开始了我的作死之旅。
通过一番改动,发现梯子上的空气墙设定很难实现,于是想Ctrl+Z回退,却发现回退不了。然后我就改改改,但是怎么改都改不回来,都会出现bug。
然后我想,昨天晚上我保存过,大不了就今天白干嘛!
然后我就点不保存退出,再次打开的时候发现,不仅今天的所有工作白干,而且代码还回不到原来的没有bug的状态。
家人们,我破防了呀!!!
所以大家千万要记得做大的改动之前,一定要备份一下!!!
算了,分享几个我觉得我处理的不错的代码。
关于怪物AI的设定,使用了面向对象的思想。
主要还是延时执行,使在每帧执行的函数Update里不每帧都执行位移,而是在特定条件下才执行。这点我想了很久。
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<Animator>();
_rigidbody2D = GetComponent<Rigidbody2D>();
player = GameObject.FindGameObjectWithTag("Player");
playerController = player.GetComponent<PlayerController>();
Grade = GameObject.FindGameObjectWithTag("Grade").GetComponent<Text>();
id_attack = Animator.StringToHash("attack");
distance = 100; //解决怪物出生时就攻击的bug
originPosition = 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<Animator>().GetBool("fall") && player.transform.position.y - transform.position.y >= 0.1f)
|| (player.transform.position.y - transform.position.y >= 0.5f && player.GetComponent<Animator>().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;
}
}
}
}
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<SpriteRenderer>().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);
}
}
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);
}
}
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;
}
}