一、创建敌人2D模型
裁切野猪素材,并放置在Scene
窗口中
打开文件夹,找到野猪待机素材
将素材进行必要的设置
点击窗口中的Sprite Editor
,打开裁切窗口。点击Slice,选择Type,进行按网格计数裁切(Grid By Cell Count)
接着,然后在Column & Row
中,写入4、1。即,4列1行。将中心点Pivot
选择Bottom
自动裁切成功。
将Sheet_0拖入到Hierarchy
窗口中,并命名为Boar
将Boar的图层顺序设置为Middle,并将Order设置为1。这样就不会被地面的草地遮挡
给野猪创建刚体和碰撞盒
选中Boar,点击Add Component,选择RigitBody 2D
将Collision Detection
设置为持续不断的(Continuous),并冻结Z轴
点击Add Component创建Box Collider 2D
点击Edit Collider将Box Collider设置为此大小
现在的Box Collider会导致人物穿过野猪时,会发生体积碰撞问题。这时就需要进行图层排除(Exclude Layer)。
点击右上角的Layer,选择Add Layer
新增两个图层,一个Player,一个Enemy
在Boar中,右上角Layer选择Enemy。在Player中,右上角Layer选择Player
然后在Boar的Layer Overrides内Exclude Layer中,选择Player和Enemy。这样就可以在此碰撞体中排除这两个图层。
为了实现人物的碰撞伤害,再给野猪创建另一个碰撞盒
选中Boar,创建Capsule Collider 2D
接着将Direction选择为Horizontal
,实现横向形状的碰撞
然后点击Edit Collider
,将碰撞盒修改为此大小
因为此碰撞盒是进行碰撞伤害,所以将Enemy图层排除
勾选Is Trigger
,此碰撞盒进行触发碰撞伤害功能
二、伤害计算
准备
在Scripts下创建General
文件夹
General文件夹内新建Character
(人物数值计算)、Attack
(攻击数值计算) C#文件
将Character添加进Boar和Player组件列表中
将Attack添加进Enemy组件列表中
基本数值创建
Character
内新建角色基本属性
[Header("基本属性")]
public float maxHealth;
public float currentHealth;
在Start()
方法内,初始化血量
每次开始时,当前生命值初始化为最大生命值
private void Start()
{
currentHealth = maxHealth;
}
Attack
内新建攻击的基本属性
public int damage;
// 攻击范围
public float attackRange;
// 攻击频率
public float attackRate;
可以选中Boar对象,将damage设置为5,即伤害为5
Player对象,最大血量为100
攻击计算过程
Character内创建空白的TakeDamage()
方法,以备进行伤害计算
public void TakeDamage(Attack attacker)
{
}
Attack内创建OnTriggerStay2D()
方法,将被攻击的对象Collider2D传入Character组件内的TakeDamage()
方法进行伤害计算
private void OnTriggerStay2D(Collider2D collision)
{
collision.GetComponent<Character>()?.TakeDamage(this);
}
OnTriggerStay2D()方法:https://docs.unity3d.com/cn/2022.3/ScriptReference/Collider2D.OnTriggerStay2D.html
?相当于!=null,对collision.GetComponent<Character>()
进行判null,如果为null,则不进行TakeDamage()
目前人物去对野猪进行碰撞,会发现短时间内被野猪造成持续不断的伤害。那么这时候就要增加“受伤无敌”的机制
在Character
内新建受伤无敌的基本属性
[Header("受伤无敌")]
// 无敌时间
public float invulnerableDuration;
// 计时器
private float invulnerableCounter;
// 无敌状态
public bool invulnerable;
创建TriggerInvulnerable()
方法,编写无敌的触发条件
private void TriggerInvulnerable()
{
if (!invulnerable)
{
invulnerable = true;
invulnerableCounter = invulnerableDuration;
}
}
如果当前不是在无敌的状态则赋予无敌状态,并且无敌的计数器等于无敌的时间周期
紧接着,在TakeDamage()
方法中,写入新的关于无敌条件的代码
public void TakeDamage(Attack attacker)
{
if (invulnerable)
{
return;
}
// Debug.Log(attacker.damage);
if (currentHealth - attacker.damage > 0)
{
currentHealth -= attacker.damage;
TriggerInvulnerable();
} else
{
currentHealth = 0;
// 触发死亡
}
}
如果当前已经是无敌状态,则不进行伤害计算,直接跳出当前方法。接着,如果当前血量受到了一定数值的伤害导致血量还在大于0,则扣除伤害值,触发无敌。否则血量赋值为0,触发死亡。
为了让无敌时间进行缩减,则在Update()
方法中,进行时间的扣除
private void Update()
{
if (invulnerable)
{
invulnerableCounter -= Time.deltaTime;
if (invulnerableCounter <= 0 )
{
invulnerable = false;
}
}
}
如果正在无敌,则将计数器扣除完成上一帧所使用的时间(以秒为单位)。如果计数器小于等于0,则更改当前的无敌状态为false。
可以将Player对象的无敌周期设置为1s,即受伤后的1s内无敌不会被短时间持续不断的受到伤害