实现子弹类
学习目标
- 实现子弹伤害
- 实现射击器(枪)
操作流程
实现射击器
- 新建类 Shooter 并实现
csharp
using UnityEngine;
namespace Character
{
public class Shooter
{
public float ShootCD { get; set; } = 0.1f; // 射击冷却时间(秒)
public int BulletSpeed { get; set; } = 10; // 子弹速度
public int BulletDamage { get; set; } = 10; // 子弹伤害
public int ShootCount { get; set; } = 1; // 每次射击的子弹数量
public float OffsetAngle { get; set; } = 5f; // 射击偏移量
private float lastShootTime = 0f; // 上次射击时间
private CharacterBase character; // 角色引用
public Shooter(CharacterBase character)
{
this.character = character;
}
public void Shoot(Vector2 startPos, float direction)
{
if (Time.time - lastShootTime >= ShootCD)
{
lastShootTime = Time.time; // 更新上次射击时间
for (int i = 0; i < ShootCount; i++)
{
// 加上随机偏移(正负)
float offset = Random.Range(-OffsetAngle, OffsetAngle);
// 计算射击方向
float shootDirection = direction + offset;
FireBullet(startPos, shootDirection);
}
}
}
private void FireBullet(Vector2 startPos, float direction)
{
// 实现射击逻辑
var bullet = Object.Instantiate(Resources.Load<GameObject>("Model/Bullets/TrailBullet"));
bullet.transform.GetComponent<Bullet>().Init(startPos, 15f, direction);
// 添加碰撞检测和伤害逻辑
Bullet bulletComponent = bullet.GetComponent<Bullet>();
bulletComponent.Damage = BulletDamage;
bulletComponent.Speed = BulletSpeed;
}
}
}
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
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
实现子弹类
- 找到子弹预制体 Bullet
- 挂载新建类 Bullet 并实现
csharp
using System;
using UnityEngine;
using UnityEngine.VFX;
namespace Character
{
[RequireComponent(typeof(Rigidbody2D))]
public class Bullet : MonoBehaviour
{
public float Speed = 5f; // 子弹速度
public float Direction = 0f; // 子弹方向(角度)
public float LifeTime = 10f; // 子弹生命周期
public int Damage = 10; // 子弹伤害
public bool Penetrate; // 穿透
public string SoundName;
public GameObject HitEffect;
private Rigidbody2D rb;
private float timer = 0f; // 计时器
private bool alive = true; // 子弹是否存活
public void Init(Vector2 startPos, float speed, float direction)
{
// 初始化子弹
rb = GetComponent<Rigidbody2D>();
// 设置子弹的初始位置
transform.position = startPos;
Speed = speed;
Direction = direction;
// 设置子弹的初始速度和方向
Vector2 velocity = new Vector2(Mathf.Cos(Direction * Mathf.Deg2Rad), Mathf.Sin(Direction * Mathf.Deg2Rad)) * Speed;
GetComponent<Rigidbody2D>().linearVelocity = velocity;
rb.linearVelocity = velocity;
// 设置子弹的旋转角度
rb.rotation = Direction;
AudioManager.Instance.PlayEffect(SoundName);
GetComponent<VisualEffect>().SetVector4("Color", 7 * PlayerController.Instance.PlayerColor);
}
private void Update()
{
timer += Time.deltaTime;
if (timer >= LifeTime)
{
Destroy(gameObject); // 销毁子弹
}
}
// 碰撞
private void OnTriggerEnter2D(Collider2D collision)
{
if (alive == false)
{
return;
}
AudioManager.Instance.PlayEffect("SFX/Hit");
var hit = Instantiate(HitEffect, transform.position, Quaternion.identity);
hit.GetComponent<VisualEffect>().SetVector3("Direction", rb.linearVelocity.normalized);
hit.GetComponent<VisualEffect>().SetVector4("Color", 7 * PlayerController.Instance.PlayerColor);
Destroy(hit, 2f);
// 获取被碰撞的对象的层级
if (collision.gameObject.layer == LayerMask.NameToLayer("Enemy"))
{
// 处理子弹与敌人碰撞的逻辑
var enemy = collision.GetComponent<CharacterBase>();
if (enemy != null && enemy.status.Alive)
{
enemy.status.Hit(Damage);
}
}
if (!Penetrate)
{
transform.Find("Head").gameObject.SetActive(false);
transform.GetComponent<VisualEffect>().SetBool("Enabled", false);
rb.linearVelocity = Vector2.zero; // 停止子弹移动
alive = false;
}
}
}
}
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
修改 Player Controller
- 添加 Shooter 相关逻辑 (给出完整代码)
csharp
using Character;
using UnityEngine;
using DG.Tweening;
[RequireComponent(typeof(Rigidbody2D))]
public class PlayerController : CharacterBase
{
public static PlayerController Instance { get; private set; }
public Color PlayerColor = Color.white; // 玩家颜色
public Shooter shooter;
public int Exp
{
get => exp;
set
{
exp = value;
GameApp.Instance.CheckLevel();
}
}
private Rigidbody2D rb;
private bool isDashing = false;
private Vector2 mousePosition;
private int exp;
private void Awake()
{
if (Instance == null)
{
Instance = this;
}
else
{
Destroy(gameObject);
}
rb = GetComponent<Rigidbody2D>();
Init();
shooter = new Shooter(this);
}
private void Update()
{
if (GameApp.Instance.State == GameApp.GameState.Break) return;
mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
ProcessInput();
}
private void ProcessInput()
{
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
bool isDash = Input.GetKey(KeyCode.Space);
Vector2 movement = new Vector2(moveHorizontal, moveVertical);
if (movement.magnitude > 1)
{
movement.Normalize();
}
if (isDash && !isDashing && movement != Vector2.zero)
{
isDashing = true;
Debug.Log("Dashing");
DoDashAnimation();
rb.linearVelocity = movement * 10f; // 冲刺速度
Invoke("StopDashing", 0.4f); // 停止冲刺的延时
}
else if (!isDashing)
{
rb.linearVelocity = movement * 5f;
}
if (movement != Vector2.zero)
{
var mouse = mousePosition - (Vector2)transform.position;
// 计算旋转角度
float angle = Mathf.Atan2(mouse.y, mouse.x) * Mathf.Rad2Deg;
// 设置玩家的旋转
rb.rotation = angle;
}
else if (!isDashing)
{
rb.linearVelocity = Vector2.zero; // 停止移动
}
if (Input.GetMouseButton(0))
{
Shoot(); // 射击
}
}
private void StopDashing()
{
isDashing = false;
}
private void DoDashAnimation()
{
transform.DOScale(new Vector3(1.3f, 0.7f, 1f), 0.1f);
transform.DOScale(new Vector3(1f, 1f, 1f), 0.15f).SetDelay(0.1f);
}
private void Shoot()
{
// 计算子弹发射方向
float direction = Mathf.Atan2(mousePosition.y - transform.position.y, mousePosition.x - transform.position.x) * Mathf.Rad2Deg;
shooter.Shoot(transform.position, direction);
}
public override void SetDead()
{
gameObject.SetActive(false);
var deadEffect = Instantiate( Resources.Load<GameObject>("Effects/Prefab/PlayerDead"));
deadEffect.transform.position = transform.position;
AudioManager.Instance.PlayEffect("SFX/Dead");
GameApp.Instance.State = GameApp.GameState.Dead;
Destroy(deadEffect, 7f);
}
}
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118