[unity learning] RPG Leaning(八)
写这个文章的目的就是为了初学unity,然后更好的掌握unity中的内容【主要是代码】
学习unity的途径是Brackeys 的教程;
接上篇: unity learning RPG Leaning(七).
目的
一、创建一个enemy:具有一定的可视范围,自动跟随找到的目标。
二、创立伤害系统;
一、建立enemy
1、创建enemy,component 属性设置如下图所示
如果isKinematic启用,力、碰撞或关节将不会影响这个刚体。
2、创立EnemyControll类来控制Enemy运动。「包括自动跟随人物以及面向人物」
这里需要设置一个可视范围,即人物到了这个可视范围内,enemy自动跟随;
使用
target = PlayerManager.instance.player.transform「EnemyControll类中」;
public GameObject player;「PlayerManager类中」
来得到人物的目标
用下面的来计算两者的距离,然后判断是否自动跟随
float distance = Vector3.Distance(target.position, transform.position);
if (distance <= lookRadius)
{
agent.SetDestination(target.position);}
由于在stoppingDistance内(我们在Nav Mesh Agent中设置的是2)物体不会自动面向对象,所以要写函数来控制:
void FaceTarget()
{
Vector3 direction = (target.position - transform.position).normalized;
Quaternion lookRtation = Quaternion.LookRotation(new Vector3(direction.x, 0, direction.z));
transform.rotation = Quaternion.Slerp(transform.rotation, lookRtation, Time.deltaTime * 5f);
}
3、给Enemy设置Stat 以及Interactive 的类 --> EnemyStats 和Enemy类
Enemy类很简单只需复写Die()函数
public class EnemyStats : CharacterStats
{
public override void Die()
{
base.Die();
Destroy(gameObject);
}
}
在Enemy类中,复写Interactive()函数,其中,攻击player的函数之后再写
public override void Interative()
{
base.Interative();
//attack the emeny
}
二、建立伤害系统
1、建立一个CharacterCombat类,来处理物体之间的相互伤害;
[RequireComponent(typeof(CharacterStats))]
public class CharacterCombat : MonoBehaviour
{
CharacterStats myStats;
void Start()
{
myStats = GetComponent<CharacterStats>();
}
public void Attack(CharacterStats targetStats)
{
targetStats.TakeDamage(myStats.damage.GetValue());
StartCoroutine(DoDamage(targetStats, attackDelay));
}
}
2、enemy受到伤害:
在Enemy类中,Interactive()函数中添加为:
PlayerManager playerManager;
CharacterStats myStats;
void Start()
{
playerManager = PlayerManager.instance;
myStats = GetComponent<CharacterStats>();
}
public override void Interative()
{
base.Interative();
//attack the emeny
CharacterCombat playerCombat = playerManager.player.GetComponent<CharacterCombat>();
playerCombat.Attack(myStats);
}
3、同时人物受到伤害:
在EnemyControll类中,如果物体小于一定距,发动攻击
CharacterStats targetStats = target.GetComponent<CharacterStats>();
if (targetStats != null)
{
combat.Attack(targetStats);
}
4、添加伤害细节「CharacterCombat类」:
加入攻击冷却时间:
public float attackSpeed = 1f;
public float attackCoolDown = 0f;
void Update()
{
attackCoolDown -= Time.deltaTime;
}
...
if (attackCoolDown <= 0f)
{
targetStats.TakeDamage(myStats.damage.GetValue());
attackCoolDown = 1f / attackSpeed;
}
加入攻击延时时间:
public float attackDelay = 0.6f;
public void Attack(CharacterStats targetStats)
{
if (attackCoolDown <= 0f)
{
// targetStats.TakeDamage(myStats.damage.GetValue());
StartCoroutine(DoDamage(targetStats, attackDelay));
attackCoolDown = 1f / attackSpeed
}
}
IEnumerator DoDamage(CharacterStats stats, float delay)
{
yield return new WaitForSeconds(delay);
stats.TakeDamage(myStats.damage.GetValue());
}
这里用到了IEnumerator接口:
腾讯:算是一个接口的时序说明,以后还会仔细阅读这篇! 、
知乎:解释了什么叫做IEnumerator接口
这两篇文章对我帮助很大。
什么时候使用IEnumerator呢?需要严格向下执行的时候。
5、最后重写player的Die()函数
「PlayerStats类」
public override void Die()
{
base.Die();
PlayerManager.instance.KillPlayer();
}
「PlayerManager类」:重新刷新整个场景:
using UnityEngine.SceneManagement;
public void KillPlayer()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}