Unity Tutorial - Tanks! 总结(下)

本文是Unity Tanks!教程的下篇总结,涵盖了炮弹(SHELLS)、射击(SHOOTING)、游戏管理(GAME MANAGERS)和音频(AUDIO)等内容。作者通过实践,解析了炮弹碰撞逻辑、爆炸效果、射击机制、游戏流程控制和音频管理等关键点,反思了照搬脚本与深入理解知识的差异,旨在增进对Unity游戏开发的深入理解。
摘要由CSDN通过智能技术生成

Unity Tutorial - Tanks! 总结(下)

紧接着上一篇Unity Tutorial - Tanks! 总结(上),我们来到第五章

05 - SHELLS

现在有坦克有血条,自然而然就是要造炮弹了,对于炮弹首先要思考个问题,我们希望炮弹做什么,我们希望炮弹在碰撞其他的东西时,显示一个爆炸特效,除此之外,我们并不想要它会像一个实体一样爆炸后依然留在地上,为此我们需要为炮弹的 colliderIs Trigger 打上勾。这里解释一下 Is Trigger,勾选它之后,炮弹将不会再被当作一个实体,它是一个只有表面,没有内容的模型,但是再加上 rigidbody 之后它的运动会符合物理规律,只是不会和任何其他的 collider 真实地发生碰撞,而是触发 OnTriggerEnter()OnTriggerExit()OnTriggerStay() 等方法。于是乎,这里的炮弹发生碰撞的行为我们可以理解为,在炮弹触发到 OnTriggerEnter() 方法时,显示爆炸效果,同时销毁炮弹实例。

知道炮弹是如何爆炸之后,接着来想象炮弹爆炸会引发哪些事情,可以想象得到,爆炸是一种范围性的影响,我们希望炮弹在爆炸的时候会对一定范围里面的敌人造成伤害,以及给它一个爆炸所产生的作用力,而对于其他的物体,我们不想对它们产生影响。这里使用的方法,是将坦克的 LayerMask 标记为 player 从而在爆炸范围监测时忽略掉其他的 collider ,结合源码感受一下具体实现

public class ShellExplosion : MonoBehaviour
{
    public LayerMask m_TankMask;                        // Used to filter what the explosion affects, this should be set to "Players".
    public ParticleSystem m_ExplosionParticles;         // Reference to the particles that will play on explosion.
    public AudioSource m_ExplosionAudio;                // Reference to the audio that will play on explosion.
    public float m_MaxDamage = 100f;                    // The amount of damage done if the explosion is centred on a tank.
    public float m_ExplosionForce = 1000f;              // The amount of force added to a tank at the centre of the explosion.
    public float m_MaxLifeTime = 2f;                    // The time in seconds before the shell is removed.
    public float m_ExplosionRadius = 5f;                // The maximum distance away from the explosion tanks can be and are still affected.


    private void Start ()
    {
        // If it isn't destroyed by then, destroy the shell after it's lifetime.
        Destroy (gameObject, m_MaxLifeTime);
    }


    private void OnTriggerEnter (Collider other)
    {
  // Collect all the colliders in a sphere from the shell's current position to a radius of the explosion radius.
        Collider[] colliders = Physics.OverlapSphere (transform.position, m_ExplosionRadius, m_TankMask);

        // Go through all the colliders...
        for (int i = 0; i < colliders.Length; i++)
        {
            // ... and find their rigidbody.
            Rigidbody targetRigidbody = colliders[i].GetComponent<Rigidbody> ();

            // If they don't have a rigidbody, go on to the next collider.
            if (!targetRigidbody)
                continue;

            // Add an explosion force.
            targetRigidbody.AddExplosionForce (m_ExplosionForce, transform.position, m_ExplosionRadius);

            // Find the TankHealth script associated with the rigidbody.
            TankHealth targetHealth = targetRigidbody.GetComponent<TankHealth> ();

            // If there is no TankHealth script attached to the gameobject, go on to the next collider.
            if (!targetHealth)
                continue;

            // Calculate the amount of damage the target should take based on it's distance from the shell.
            float damage = CalculateDamage (targetRigidbody.position);

            // Deal this damage to the tank.
            targetHealth.TakeDamage (damage);
        }

        // Unparent the particles from the shell.
        m_ExplosionParticles.transform.parent = null;

        // Play the particle system.
        m_ExplosionParticles.Play();

        // Play the explosion sound effect.
        m_ExplosionAudio.Play();

        // Once the particles have finished, destroy the gameobject they are on.
        ParticleSystem.MainModule mainModule = m_ExplosionParticles.main;
        Destroy (m_ExplosionParticles.gameObject, mainModule.duration);

        // Destroy the shell.
        Destroy (gameObject);
    }


    private float CalculateDamage (Vector3 targetPosition)
    {
        // Create a vector from the shell to the target.
        Vector3 explosionToTarget = targetPosition - transform.position;

        // Calculate the distance from the shell to the target.
        float explosionDistance = explosionToTarget.magnitude;

        // Calculate the proportion of the maximum distance (the explosionRadius) the target is away.
        float relativeDistance = (m_ExplosionRadius - explosionDistance) / m_ExplosionRadius;

        // Calculate damage as this proportion of the maximum possible damage.
        float damage = relativeDistance * m_MaxDamage;

        // Make sure that the minimum damage is always 0.
        damage = Mathf.Max (0f, damage);

        return damage;
    }
}

整个脚本的主要逻辑是遍历 Physice.OverlapSphere() 返回的一组 collider ,通过 GetComponent<Rigidbody>() 获取 targetRigidbody 来施加爆炸作用力,通过 GetComponent<TankHealth> 获取 targetHealth 来造成伤害。随后在销毁炮弹实例前,将原本作为炮弹子对象的爆炸特效抽离出来,播放完成后再进行销毁。

  • 这里有一个问题我个人思考了很久,为什么将爆炸特效抽离出来不是用 m_ExplosionParticles.gameObject.parent = null 而使用 m_ExplosionParticles.transform.parent = null 经过一番搜索后依然得不到答案,索性就自己改一下,发现 m_ExplosionParticles.gameObject.parent = null 是不合法的,无法通过编译的,最后我强行猜想原因: 原本在 hierarchy 中,通过拖拽让一个对象变成另一个对象的子对象,他们之间的联系也就仅仅是通过在 transform 层面上建立起来的,所以通过将 transform.parentnull 相当于将他们建立联系的桥梁砍断,也意味着此时炮弹的销毁不再会影响到爆炸特效

  • 第二个需要注意的点是,脚本中的 CalculateDamage(Vector3 targetPosition) 方法之所以传入参数是一个 Vector3 是因为需要根

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity Mega-Fiers是一款强大的Unity插件,它为开发者提供了许多功能和工具,以帮助他们创建优秀的游戏体验。 首先,Unity Mega-Fiers具有强大的形变功能。开发者可以通过该插件实现各种形状的变换,包括弯曲、挤压、拉伸等。这为游戏中的人物、物体和环境提供了更多的自由度和个性化选项,使其更具动态和真实感。 其次,Unity Mega-Fiers还提供了高度的粒子系统控制能力。开发者可以使用该插件来创建更加逼真的粒子效果,并具有更准确的控制。这包括粒子的大小、颜色、速度等方面,使游戏中的特效更加出色。 另外,Unity Mega-Fiers还支持可编程网格。这意味着开发者可以通过脚本来控制网格的生成和变形,从而实现各种复杂的效果。无论是地形生成、水体模拟还是其他物体的变形,都可以通过该插件实现,并使游戏更加逼真和具有个性化。 除了以上功能,Unity Mega-Fiers还提供了其他诸多辅助工具,如动画控制、特效编辑等,为开发者提供了更丰富的开发选项和提升游戏质量的手段。 总结而言,Unity Mega-Fiers是一款功能强大的Unity插件,为开发者提供了丰富的形变、粒子系统控制和可编程网格等功能。它能够大幅提升游戏的真实感和品质,并为开发者提供更多的创作空间和个性化选项。无论是初学者还是有经验的开发者,都能够从中受益,并创造出出色的游戏作品。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值