在随机范围内生成敌人
学习目标
完成本教程后,你会学会
- 如何实现敌人死亡
- 实现敌人跟随玩家
操作流程
- 新建 CharacterBase 脚本,并实现
csharp
using DG.Tweening;
using UnityEngine;
namespace Character
{
public abstract class CharacterBase : MonoBehaviour
{
public Status status { get; private set; }
[SerializeField]
public int MaxHp;
protected Material material;
public virtual void Init()
{
material = GetComponent<SpriteRenderer>().material; // 获取角色的材质
status = new Status(this);
}
public virtual void SetDead()
{
if (!status.Alive) return; // 如果角色已经死亡,直接返回
Destroy(gameObject);
}
public void HitEffect()
{
material.DOFloat(1f, "_Blend", 0.1f);
material.DOFloat(0f, "_Blend", 0.1f).SetDelay(0.1f);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
- 实现 Enemy 脚本
csharp
using Character;
using UnityEngine;
using UnityEngine.VFX;
using System;
using System.Collections;
using System.Collections.Generic;
namespace Character
{
public class Enemy : CharacterBase
{
private void Update()
{
// 这里可以添加敌人的行为逻辑
if (status.Alive)
{
MoveToPlayer();
}
}
private void MoveToPlayer()
{
if (PlayerController.Instance != null)
{
Vector2 direction = (PlayerController.Instance.transform.position - transform.position).normalized;
float speed = 2f; // 敌人的移动速度
transform.position += (Vector3)direction * speed * Time.deltaTime;
// 计算旋转角度
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle));
}
}
public override void SetDead()
{
base.SetDead();
var deadEffect = Instantiate( Resources.Load<GameObject>("Effects/Prefab/EffectDead"));
deadEffect.transform.position = transform.position;
AudioManager.Instance.PlayEffect("SFX/Dead");
PlayerController.Instance.Exp += 1;
Destroy(deadEffect, 7f);
}
public void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.layer == LayerMask.NameToLayer("Player"))
{
// 处理敌人与玩家碰撞的逻辑
var player = other.gameObject?.GetComponent<PlayerController>();
if (player != null && player.status.Alive)
{
player.status.Hit(10); // 假设敌人造成10点伤害
Debug.Log($"{player.gameObject.name} hit by enemy!");
}
SetDead();
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
- 新建 Status 脚本,并实现
csharp
using UnityEngine;
namespace Character
{
public class Status
{
public bool Alive { get; private set; } = true; // 角色是否存活
private int maxHp; // 最大生命值
private int curHp; // 当前生命值
public int MaxHp {
get => maxHp;
set
{
maxHp = value;
if (CurHp > MaxHp) // 确保当前生命值不超过最大生命值
{
CurHp = MaxHp;
}
DeadCheck();
}
}
public int CurHp {
get => curHp;
set
{
curHp = value;
DeadCheck();
}
}
private readonly CharacterBase character;
public Status(CharacterBase character)
{
maxHp = character.MaxHp; // 设置最大生命值
curHp = maxHp; // 初始生命值为最大生命值
this.character = character;
}
private void DeadCheck()
{
if (Alive && CurHp <= 0)
{
character.SetDead(); // 如果生命值小于等于0,调用角色死亡方法
Alive = false; // 设置角色为死亡状态
}
}
public void Hit(int damage)
{
damage = Mathf.Max(damage, 0); // 确保伤害值不小于0
if (Alive)
{
CurHp -= damage; // 减少当前生命值
}
character.HitEffect();
}
public void Respawn()
{
Alive = true; // 重置为存活状态
curHp = MaxHp; // 恢复当前生命值为最大生命值
character.transform.position = Vector3.zero; // 重置角色位置
character.gameObject.SetActive(true);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
- 将敌人预制体的 Layer 改为 Enemy(新建 Enemy 图层),将玩家的 Layer 改为 Player(新建 Player 图层)
- 让玩家 Player Controller 继承 CharacterBase 类
概念解析
get&set
详情请见属性与字段