所以有一个Unity官方教程,2D流氓就好。 http://unity3d.com/learn/tutorials/projects/2d-roguelike
在这些系列中,我想修改,改进敌人的AI用于学习目的。
当敌人遇到墙壁时,我想要绕开或摧毁墙壁。
所以第一个敌人需要识别墙壁。
所以我这样修改它,但它没有用。有谁知道出了什么问题?
MovingObject.cs
using UnityEngine;
using System.Collections;
public abstract class MovingObject : MonoBehaviour {
public float moveTime = 0.1f;
public LayerMask blockingLayer;
private BoxCollider2D boxCollider;
private Rigidbody2D rb2D;
private float inverseMoveTime;
// Use this for initialization
protected virtual void Start () {
boxCollider = GetComponent<BoxCollider2D>();
rb2D = GetComponent<Rigidbody2D>();
inverseMoveTime = 1f / moveTime;
}
protected bool Move(int xDir, int yDir, out RaycastHit2D hit){
Vector2 start = transform.position;
Vector2 end = start+new Vector2(xDir, yDir);
boxCollider.enabled = false;
hit = Physics2D.Linecast(start, end, blockingLayer);
boxCollider.enabled = true;
if(hit.transform == null){
StartCoroutine(SmoothMovement(end));
return true;
}
return false;
}
protected IEnumerator SmoothMovement(Vector3 end){
float sqrRemainingDistance = (transform.position-end).sqrMagnitude;
while(sqrRemainingDistance > float.Epsilon){
Vector3 newPosition = Vector3.MoveTowards(rb2D.position, end, inverseMoveTime * Time.deltaTime);
rb2D.MovePosition(newPosition);
sqrRemainingDistance = (transform.position-end).sqrMagnitude;
yield return null;
}
}
protected virtual void AttemptMove<T> (int xDir, int yDir) where T : Component{
RaycastHit2D hit;
bool canMove = Move (xDir, yDir, out hit);
if(hit.transform == null)
return;
T hitComponent = hit.transform.GetComponent<T>();
if(!canMove && hitComponent != null){
OnCantMove(hitComponent);
if(hitComponent is Wall)
OnCantMoveEnemy(hitComponent);
}
}
protected abstract void OnCantMove<T> (T component) where T : Component;
protected abstract void OnCantMoveEnemy <T> (T component) where T : Component;
}
和Enemy.cs
using UnityEngine;
using System.Collections;
public class Enemy : MovingObject {
public int playerDamage;
private Animator animator;
private Transform target;
private bool skipMove;
public AudioClip enemyAttack1;
public AudioClip enemyAttack2;
protected override void Start () {
GameManager.instance.AddEnemyToList(this);
animator = GetComponent<Animator>();
target = GameObject.FindGameObjectWithTag("Player").transform;
base.Start();
}
protected override void AttemptMove<T> (int xDir, int yDir){
if(skipMove){
skipMove = false;
return;
}
base.AttemptMove<T>(xDir, yDir);
skipMove = true;
}
public void MoveEnemy(){
int xDir = 0; int yDir = 0;
if((Mathf.Abs(target.position.x - transform.position.x) > float.Epsilon)){
xDir = target.position.x > transform.position.x ? 1 : -1;
}
if(Mathf.Abs(target.position.y - transform.position.y) > float.Epsilon){
yDir = target.position.y > transform.position.y ? 1 : -1;
}
Debug.Log("ydir is "+yDir+" / xdir is "+xDir);
AttemptMove<Player>(xDir, yDir);
AttemptMove<Wall>(xDir, yDir);
}
protected override void OnCantMove<T>(T component){
Player hitPlayer = component as Player;
animator.SetTrigger("enemyAttack");
hitPlayer.LoseFood(playerDamage);
SoundManager.instance.RandomizeSfx(enemyAttack1, enemyAttack2);
}
protected override void OnCantMoveEnemy<T>(T component){
Wall hitWall = component as Wall;
Debug.Log("hit wall is "+hitWall.name);
}
}
您不需要添加任何额外的方法。
我通过在AttemptMove<T>
的MovingObject.cs
中添加几行来完成此操作:
Wall wallComponent = hit.transform.GetComponent<Wall>();
并通过扩展已存在的条件块:
else if (hit.transform.ToString().Substring(0,4) == "Wall")
{
OnCantMove(wallComponent);
}
请记住,从现在开始,每一块应该可以破坏的墙都必须从“Wall”预制件中创建。
然后你可以用条件块修改你的Enemy.cs
OnCantMove<T>
方法:
if (component is Player){...}
else if (component is Wall){...}
并填写脚本中已有的代码。