枪口火焰特效

常用粒子特效

将特效包下载后导入项目

编写 WeaponGraphics.cs 类,用于管理每把武器的特效。

using UnityEngine;

public class WeaponGraphics
{
    [SerializeField]
    public ParticleSystem muzzleFlash; //枪口火焰

    [SerializeField]
    public GameObject stoneHitEffectPrefab; //击中石头特效

    [SerializeField]
    public GameObject metalHitEffectPrefab; //击中金属特效
}

将WeaponGraphics.cs脚本挂载到武器预制体上,之后在WeaponManager类中动态获取。

将选好的火焰特效放入Prefab文件夹中,并修改一下特效的大小、播放速度等。

具体的火焰特效播放是在开枪后执行,所以修改PlayerShoot类。

在Shoot()函数中加入一行 OnShootServerRpc() ,具体代码逻辑如下.

	// 处理射击时的特效、音效等
    private void OnShoot()
    {
        weaponManager.GetCurrentGraphics().muzzleFlash.Play();
    }

    [ServerRpc]
    private void OnShootServerRpc()
    {
        if (!IsHost)
        {
            OnShoot();
        }
        OnShootClientRpc();
    }

    [ClientRpc]
    private void OnShootClientRpc()
    {
        OnShoot();
    }

击中粒子特效

粒子特效和火焰特效类似,只不过需要区分 击中石头、击中金属是不同的。

enum HitEffectMaterial { Stone, Metal };

定义一个枚举类型,用于区分特效类型。

写一个OnHit函数,用于执行具体物体被击中时的粒子动画播放逻辑。简单说就是在击中点动态实例化一个预制体,然后播放其中的ParticleSystem。

private void OnHit(Vector3 position, Vector3 normal, HitEffectMaterial material)
{
    GameObject hitEffectPrefab;
    if (material == HitEffectMaterial.Metal)
    {
        hitEffectPrefab = weaponManager.GetCurrentGraphics().metalHitEffectPrefab;
    }
    else
    {
        hitEffectPrefab = weaponManager.GetCurrentGraphics().stoneHitEffectPrefab;
    }
    GameObject hitEffectObject = Instantiate(hitEffectPrefab, position, Quaternion.LookRotation(normal));
    ParticleSystem particleSystem = hitEffectObject.GetComponent<ParticleSystem>();
    particleSystem.Emit(1);
    particleSystem.Play();
    Destroy(hitEffectObject, 0.5f);
}

private void Shoot()
{
    OnShootServerRpc(recoilForce);

    RaycastHit hit;
    if (Physics.Raycast(eyesCamera.transform.position, eyesCamera.transform.forward, out hit, currentWeapon.range))
    {
        if (hit.collider.tag == PLAYER_TAG)
        {
            ShootServerRpc(hit.collider.name, currentWeapon.damage);
            OnHitServerRpc(hit.point, hit.normal, HitEffectMaterial.Metal);
        }
        else
        {
            OnHitServerRpc(hit.point, hit.normal, HitEffectMaterial.Stone);
        }
    }
}

击中特效同样要同步到其他客户端。

[ClientRpc]
private void OnHitClientRpc(Vector3 position, Vector3 normal, HitEffectMaterial material)
{
    OnHit(position, normal, material);
}

[ServerRpc]
private void OnHitServerRpc(Vector3 position, Vector3 normal, HitEffectMaterial material)
{
    if (!IsHost)
    {
        OnHit(position, normal, material);
    }
    OnHitClientRpc(position, normal, material);
}