前言

项目已经传到 github 上了 https://github.com/zong4/Ooo,不过目前的功能还需要测试,可能会有 bug。

v1

PlayerController

简单实现一下移动,放炸弹,引爆炸弹的功能,并且留下了一些可变参数。

这里没有设置成空中不能移动,一方面是会引出新的 bug,一方面是我忘记了游戏里是什么样的了。

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
public class PlayerController : MonoBehaviour
{
// Move
public float moveSpeed = 3f;

// Bomb
private Foot _foot;
public GameObject bombPrefab;
public int maxBombs = 2;
private readonly List<Bomb> _bombs = new List<Bomb>();

private void Start()
{
_foot = transform.GetComponentInChildren<Foot>();

if (!bombPrefab)
{
Debug.LogError("Bomb Prefab is not assigned in the inspector.");
}
}

private void Update()
{
Move();

if ((Input.GetKeyDown(KeyCode.J) || Input.GetMouseButtonDown(0)) && _foot.touchTag is "Ground" or "Bomb" &&
_bombs.Count < maxBombs)
{
if (bombPrefab)
{
var oldPosition = transform.position;
transform.position = new Vector3(transform.position.x,
transform.position.y + bombPrefab.transform.localScale.y, transform.position.z);
_bombs.Add(Instantiate(bombPrefab, oldPosition, Quaternion.identity).GetComponent<Bomb>());
}
}

if ((Input.GetKeyDown(KeyCode.K) || Input.GetMouseButtonDown(1)) && _bombs.Count > 0)
{
_bombs[0].Explode();
_bombs.RemoveAt(0);
}
}

private void Move()
{
// // In the air
// if (_foot.touchTag == null || (_foot.touchTag != "Ground" && _foot.touchTag != "Bomb"))
// return;

var moveInput = new Vector3(Input.GetAxis("Horizontal"), 0, 0);
transform.Translate(moveInput * (Time.deltaTime * moveSpeed));
}
}

Foot

一般平台游戏都需要单独的脚部检测,通过稍微缩小一点判定框可以减少很多 bug。

用 Gizmos 显示了一下爆炸范围,方便 debug。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Foot : MonoBehaviour
{
public string touchTag;

private void OnCollisionEnter2D(Collision2D collision)
{
touchTag = collision.gameObject.tag;
}

private void OnCollisionExit2D()
{
touchTag = null;
}
}

Bomb

游戏中是十字形爆炸,所以这边就用两个矩形检测,配合 hashset 去重。

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
public class Bomb : MonoBehaviour
{
public float explosionWidth = 3f;
public float explosionHeight = 1f;
public float explosionForce = 5f;

public void Explode()
{
CheckExplosionRange();
Destroy(gameObject);
}

private void CheckExplosionRange()
{
var hashSet = new HashSet<Rigidbody2D>();

{
var results = new Collider2D[10]; // todo Adjust size as needed
var size = Physics2D.OverlapBoxNonAlloc(transform.position,
new Vector2(explosionWidth * transform.localScale.x - 0.1f,
explosionHeight * transform.localScale.y - 0.1f),
0f,
results,
LayerMask.GetMask("Player", "Bomb")); // hack

for (var i = 0; i < size; i++)
{
hashSet.Add(results[i].GetComponent<Rigidbody2D>());
}
}

{
var results = new Collider2D[10];
var size = Physics2D.OverlapBoxNonAlloc(transform.position,
new Vector2(explosionHeight * transform.localScale.x, explosionWidth * transform.localScale.y), 0f,
results,
LayerMask.GetMask("Player", "Bomb"));

for (var i = 0; i < size; i++)
{
hashSet.Add(results[i].GetComponent<Rigidbody2D>());
}
}

foreach (var rigidbody2D1 in hashSet)
{
if (rigidbody2D1.CompareTag("Bomb"))
{
rigidbody2D1.bodyType = RigidbodyType2D.Dynamic;
}

var direction = Vector3.zero;
if (rigidbody2D1.position.y > transform.position.y + 0.1f) // hack
{
direction = new Vector3(0f, 1f, 0f);
}
else if (rigidbody2D1.position.y < transform.position.y - 0.1f)
{
direction = new Vector3(0f, -1f, 0f);
}
else if (rigidbody2D1.position.x > transform.position.x + 0.1f)
{
direction = new Vector3(1f, 0f, 0f);
}
else if (rigidbody2D1.position.x < transform.position.x - 0.1f)
{
direction = new Vector3(-1f, 0f, 0f);
}

rigidbody2D1.AddForce(direction * explosionForce, ForceMode2D.Impulse);
}
}

private void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.CompareTag("Ground"))
{
transform.GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Kinematic;
}
}

private void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawWireCube(transform.position, new Vector2(explosionWidth, explosionHeight));
Gizmos.DrawWireCube(transform.position, new Vector2(explosionHeight, explosionWidth));
}
}