
在Unity中制作模块化的系统来处理游戏道具的方法,其实具有相似逻辑,虽然Spawn Manager会在不同时间负责生成power-ups,但这些power-ups还具有其他共同特征,他们都需要以相同的方式穿越游戏场景,它们在被玩家拦截时需要是可收集的,并且收集后需要触发特定效果,一旦收集、射击或离开游戏场景后,它们就需要被销毁。
由于它们都有许多共同的元素,因此重写相同的代码来定义每次加电的行为是没有意义的,即使它们对游戏玩法的影响会有所不同。
那么问题就来了,如何模块化启动脚本?不是硬编码OnTriggerEnter2D方法,而是当power-up与other.CompareTag(“Player”)发生碰撞时会发生什么,因此需要编写代码以检测哪个power-up发生碰撞,然后才设置特定值,以触发与该独特加电相关的行为。
private void onTriggerEnter2D(Collider20 other)
{
if (other.tag == "Player")
{
PlayerScript player = other.transform.GetComponent<PlayerScript>();
if (player != null)
{
player.TripleShotActivate();
}
Destroy(this.gameObject);
}
}
在这个Spawn Manager中,目前正在设置八个power-ups分成三个阵列。
- 第一个阵列负责基本阵列:Triple Shot、Speed Boost和Shields。
- 第二个阵列有武器:弹药、制导 导弹和横向激光炮。
- 第三个阵列有Health Boost和Negative Power-Up。
可以查看在下面使用的代码示例:
[Header("Power Up Related")]
[SerializeField] private GameObject[] _playerBasicPowerUps;
[SerializeField] private GameObject[] _playerWeaponsPowerUps;
[SerializeField] private GameObject[] _healthAndNegPowerUps;
}
public void StartSpawning()
{
StartCoroutine(SpawnEnemywave());
StartCoroutine(SpawnBasicPowerUps());
StartCoroutine( SpawnweaponsPowerUps());
StartCoroutine(SpawnHealthAndNegPowerUps());
}
IEnumerator SpawnBasicPowerUps()
{
yield return new waitForSeconds(2.0f);
while (_stopSpawning != true)
{
Vector3 pxToSpawn = new Vector3( Random.Range(-9f,9f),8f,0);
int randomPowerup = Random.Range(0,_playerBasicPowerUps.Length); // spaMwn Power Ups Elements 0 to Length of Array
GameObject newPowerUp = Instantiate(_playerBasicPowerUps[randomPowerUp],pxiToSpawn,Quaternion.identity);
newPowerUp.transform.parent = PowerUpContainer.transform;
yield return new MaitForSeconds(Random. Range(2f,5f)); // original figures were 15f & 25f
}
}
那么…
如何才能唯一地识别该脚本所附加的道具呢?来…我们一起看看是如何解决这个问题的!!
using System. collections;
using System.collections. Generic;
using UnityEngine;
public class Powerups : MonoBehaviour
{
[SerializeField] private Player _player;
[SerializeField] private SpawnManager _spawnManager;
[SerializeField] private GameManager _gameManager;
[SerializeField] private AudioManager _audioManager;
[SerializeField] private Gameobject _explosionPrefab;
[SerializeField] private float _powerUpSpeed ;
[SerializeField] private bool _isstartofGamePwrup = false;
[SerializeField] private int _powerUpID; // ID for PwrUp:
// 0= Triple Shot
// 1=Speed Boost
// 2= Shields
// 3= Ammo
// 4 = Homing Missiles
// 5= Lateral Laser Canon
// 6= Health (Ship Repairs)
// 7 = Negative PowerUp
//(...)
}
创建一个新脚本,将其命名为“PowerUps”,并设置对Player、SpawnManager、GameManager和AudioManager脚本的引用。
当能量提升被摧毁时添加一个私有游戏对象来保存爆炸预制件,基于游戏难度级别的一个私有浮点数来缓存来自游戏管理器的能量提升速度的引用,以及一个布尔值跟踪道具是否属于游戏的初始启动屏幕。
PS:在这个版本中,玩家需要在他们的武器自由开火之前收集两种类型的武器道具。
在这一点上使用整数系统来标识每个加电是有意义的。因此,为这些道具创建一个ID,在上面的脚本中,定义了一个private int,将其命名为_powerupID,并序列化了该字段,以便可以在Inspector中查看和修改它,将脚本附加到每个power-up预制件并将其“Power Up ID”设置为唯一的整数,将每个加电预制件的加电ID设置为自己唯一的ID。
- “0”代表TripleShot
- “1”代表速度
- “2”代表盾牌等等。
例如:

在Start()方法中,缓存Player、SpawnManager、GameManager和AudioManager脚本,并用NULL检查它们。
例如:
void start()
{
_player = GameObject.Find("Player").GetComponent<Player>();
_spawnManager = GameObject.Find("SpawnManager").GetComponent<SpawnManager>();
_gameManager = GameObject.Find("GameManager").GetComponent<GameManager>( );
_audioManager = GameObject.Find("AudioManager").GetComponent<AudioManager>();
if (_player == null)
{
Debug.LogError("The PowerUps : Player is NULL.");
}
if (_spawnManager -= null)
{
Debug.LogError("The PowerUps : SpawnManager is NULL.");
}
if (_gameManager == null)
{
Debug. LogError("The PowerUps : GameManager is NULL.");
}
if (_audioManager == null)
{
Debug.LogError("The Audio MAnager is null.");
}
}
通过Update()调用Movement()方法,如果Power-Up是介绍屏幕的一部分,那么我们将其速度设置为0以确保它在收集之前保持静止。
否则,会根据游戏的当前难度级别从游戏管理器获得所需的速度,继续将道具游戏对象向下平移到屏幕下方,并在它们超过y轴上的-9.0时销毁它们。
例如:

在碰撞检测中,对玩家进行NULL检查以确保它还活着。然后,
运行一个switch语句来比较道具的Power Up ID,并在销毁道具之前运行Player类中的适用方法。

在这个unity游戏版本中,道具很容易被玩家或敌人的激光破坏,除非道具的ID为7,这是“负能量提升”,无法破坏。
所需的逻辑如下所示:
// Continued from above. . .
if ( _powerUpID != 7)
{
if (other.CompareTag("LaserPlayer") || other.CompareTag("LaserEnemy"))
{
GameObject explosion = Instantiate(_explosionPrefab,transform.position,Quaternion.identity);
explosion.transform.parent = _spawnManager.ExplosionContainer.transform;
Destroy(other. gameObject);
Destroy(this.gameObject);
}
}
}
使用这种为每个powerup设置唯一ID值的方法可以让我们轻松区分这些游戏对象,从而确保调用正确的函数。最后这里只剩下一个脚本,只需将另一个case x:添加到Switch语句即可轻松修改该脚本以处理扩展。
…
以上是关于模块化的Power-Up系统的全部内容,如果你有任何反馈,请随时在本页面下方留言。