C# Unity多人游戏车:网络粒子和声音

C# Unity多人游戏车:网络粒子和声音,c#,unity3d,unity5,C#,Unity3d,Unity5,我正在制作一个统一游戏,玩家控制一辆车,我希望这个游戏是多人游戏。我使用的是标准资产的汽车套件 控件的默认汽车预制结构在处理用户输入的“用户控件”脚本和处理物理(运动、加速度、转向、转向等)的“汽车控制器”之间分离 您可以在下面找到这两个脚本的源代码,我刚刚修改了CarUserControl.cs用于联网 网络位置不是问题,它工作正常(我只是将NetworkTransform组件连接到汽车上,将NetworkTransformChild连接到车轮上) 问题是,汽车控制器脚本还处理汽车转向时的粒子

我正在制作一个统一游戏,玩家控制一辆车,我希望这个游戏是多人游戏。我使用的是标准资产的汽车套件

控件的默认汽车预制结构在处理用户输入的“用户控件”脚本和处理物理(运动、加速度、转向、转向等)的“汽车控制器”之间分离

您可以在下面找到这两个脚本的源代码,我刚刚修改了CarUserControl.cs用于联网

网络位置不是问题,它工作正常(我只是将NetworkTransform组件连接到汽车上,将NetworkTransformChild连接到车轮上)

问题是,汽车控制器脚本还处理汽车转向时的粒子效果(生成烟雾并显示转向轨迹)和声音(加速、转向、打滑),我完全不知道如何将其联网

所以现在我有多人游戏的汽车运动,但只有本地的汽车会产生转向/滑行轨迹、烟雾和声音

你知道怎么做吗

资料来源:

修改了CarUserInput.cs:添加了
网络行为
而不是
单一行为
,并添加了
isLocalPlayer
检查

using System;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
using UnityEngine.Networking;

namespace UnityStandardAssets.Vehicles.Car
{
    [RequireComponent(typeof (CarController))]
    public class CarUserControl : NetworkBehaviour
    {
        private CarController m_Car; // the car controller we want to use


        private void Awake()
        {
            // get the car controller
            m_Car = GetComponent<CarController>();
        }


        private void FixedUpdate()
        {
            if (!isLocalPlayer)
                return;

            // pass the input to the car!
            float h = CrossPlatformInputManager.GetAxis("Horizontal");
            float v = CrossPlatformInputManager.GetAxis("Vertical");
#if !MOBILE_INPUT
            float handbrake = CrossPlatformInputManager.GetAxis("Jump");
            m_Car.Move(h, v, v, handbrake);
#else
            m_Car.Move(h, v, v, 0f);
#endif
        }
    }
}
使用系统;
使用UnityEngine;
使用UnityStandardAssets.CrossPlatformInput;
使用UnityEngine。联网;
命名空间UnityStandardAssets.Vehicles.Car
{
[所需组件(类型(CarController))]
公共类CarUserControl:网络行为
{
私家车控制器m_Car;//我们要使用的车控制器
私人空间
{
//去拿汽车控制器
m_Car=GetComponent();
}
私有void FixedUpdate()
{
如果(!isLocalPlayer)
返回;
//把输入传给汽车!
float h=CrossPlatformInputManager.GetAxis(“水平”);
float v=CrossPlatformInputManager.GetAxis(“垂直”);
#如果!移动输入
浮动手制动器=CrossPlatformInputManager.GetAxis(“跳跃”);
移动汽车(h、v、v、手刹);
#否则
移动汽车(h,v,v,0f);
#恩迪夫
}
}
}
默认CarController.cs:

using System;
using UnityEngine;

namespace UnityStandardAssets.Vehicles.Car
{
    internal enum CarDriveType
    {
        FrontWheelDrive,
        RearWheelDrive,
        FourWheelDrive
    }

    internal enum SpeedType
    {
        MPH,
        KPH
    }

    public class CarController : MonoBehaviour
    {
        [SerializeField] private CarDriveType m_CarDriveType = CarDriveType.FourWheelDrive;
        [SerializeField] private WheelCollider[] m_WheelColliders = new WheelCollider[4];
        [SerializeField] private GameObject[] m_WheelMeshes = new GameObject[4];
        [SerializeField] private WheelEffects[] m_WheelEffects = new WheelEffects[4];
        [SerializeField] private Vector3 m_CentreOfMassOffset;
        [SerializeField] private float m_MaximumSteerAngle;
        [Range(0, 1)] [SerializeField] private float m_SteerHelper; // 0 is raw physics , 1 the car will grip in the direction it is facing
        [Range(0, 1)] [SerializeField] private float m_TractionControl; // 0 is no traction control, 1 is full interference
        [SerializeField] private float m_FullTorqueOverAllWheels;
        [SerializeField] private float m_ReverseTorque;
        [SerializeField] private float m_MaxHandbrakeTorque;
        [SerializeField] private float m_Downforce = 100f;
        [SerializeField] private SpeedType m_SpeedType;
        [SerializeField] private float m_Topspeed = 200;
        [SerializeField] private static int NoOfGears = 5;
        [SerializeField] private float m_RevRangeBoundary = 1f;
        [SerializeField] private float m_SlipLimit;
        [SerializeField] private float m_BrakeTorque;

        private Quaternion[] m_WheelMeshLocalRotations;
        private Vector3 m_Prevpos, m_Pos;
        private float m_SteerAngle;
        private int m_GearNum;
        private float m_GearFactor;
        private float m_OldRotation;
        private float m_CurrentTorque;
        private Rigidbody m_Rigidbody;
        private const float k_ReversingThreshold = 0.01f;

        public bool Skidding { get; private set; }
        public float BrakeInput { get; private set; }
        public float CurrentSteerAngle{ get { return m_SteerAngle; }}
        public float CurrentSpeed{ get { return m_Rigidbody.velocity.magnitude*2.23693629f; }}
        public float MaxSpeed{get { return m_Topspeed; }}
        public float Revs { get; private set; }
        public float AccelInput { get; private set; }

        // Use this for initialization
        private void Start()
        {
            m_WheelMeshLocalRotations = new Quaternion[4];
            for (int i = 0; i < 4; i++)
            {
                m_WheelMeshLocalRotations[i] = m_WheelMeshes[i].transform.localRotation;
            }
            m_WheelColliders[0].attachedRigidbody.centerOfMass = m_CentreOfMassOffset;

            m_MaxHandbrakeTorque = float.MaxValue;

            m_Rigidbody = GetComponent<Rigidbody>();
            m_CurrentTorque = m_FullTorqueOverAllWheels - (m_TractionControl*m_FullTorqueOverAllWheels);
        }


        private void GearChanging()
        {
            float f = Mathf.Abs(CurrentSpeed/MaxSpeed);
            float upgearlimit = (1/(float) NoOfGears)*(m_GearNum + 1);
            float downgearlimit = (1/(float) NoOfGears)*m_GearNum;

            if (m_GearNum > 0 && f < downgearlimit)
            {
                m_GearNum--;
            }

            if (f > upgearlimit && (m_GearNum < (NoOfGears - 1)))
            {
                m_GearNum++;
            }
        }


        // simple function to add a curved bias towards 1 for a value in the 0-1 range
        private static float CurveFactor(float factor)
        {
            return 1 - (1 - factor)*(1 - factor);
        }


        // unclamped version of Lerp, to allow value to exceed the from-to range
        private static float ULerp(float from, float to, float value)
        {
            return (1.0f - value)*from + value*to;
        }


        private void CalculateGearFactor()
        {
            float f = (1/(float) NoOfGears);
            // gear factor is a normalised representation of the current speed within the current gear's range of speeds.
            // We smooth towards the 'target' gear factor, so that revs don't instantly snap up or down when changing gear.
            var targetGearFactor = Mathf.InverseLerp(f*m_GearNum, f*(m_GearNum + 1), Mathf.Abs(CurrentSpeed/MaxSpeed));
            m_GearFactor = Mathf.Lerp(m_GearFactor, targetGearFactor, Time.deltaTime*5f);
        }


        private void CalculateRevs()
        {
            // calculate engine revs (for display / sound)
            // (this is done in retrospect - revs are not used in force/power calculations)
            CalculateGearFactor();
            var gearNumFactor = m_GearNum/(float) NoOfGears;
            var revsRangeMin = ULerp(0f, m_RevRangeBoundary, CurveFactor(gearNumFactor));
            var revsRangeMax = ULerp(m_RevRangeBoundary, 1f, gearNumFactor);
            Revs = ULerp(revsRangeMin, revsRangeMax, m_GearFactor);
        }


        public void Move(float steering, float accel, float footbrake, float handbrake)
        {
            for (int i = 0; i < 4; i++)
            {
                Quaternion quat;
                Vector3 position;
                m_WheelColliders[i].GetWorldPose(out position, out quat);
                m_WheelMeshes[i].transform.position = position;
                m_WheelMeshes[i].transform.rotation = quat;
            }

            //clamp input values
            steering = Mathf.Clamp(steering, -1, 1);
            AccelInput = accel = Mathf.Clamp(accel, 0, 1);
            BrakeInput = footbrake = -1*Mathf.Clamp(footbrake, -1, 0);
            handbrake = Mathf.Clamp(handbrake, 0, 1);

            //Set the steer on the front wheels.
            //Assuming that wheels 0 and 1 are the front wheels.
            m_SteerAngle = steering*m_MaximumSteerAngle;
            m_WheelColliders[0].steerAngle = m_SteerAngle;
            m_WheelColliders[1].steerAngle = m_SteerAngle;

            SteerHelper();
            ApplyDrive(accel, footbrake);
            CapSpeed();

            //Set the handbrake.
            //Assuming that wheels 2 and 3 are the rear wheels.
            if (handbrake > 0f)
            {
                var hbTorque = handbrake*m_MaxHandbrakeTorque;
                m_WheelColliders[2].brakeTorque = hbTorque;
                m_WheelColliders[3].brakeTorque = hbTorque;
            }


            CalculateRevs();
            GearChanging();

            AddDownForce();
            CheckForWheelSpin();
            TractionControl();
        }


        private void CapSpeed()
        {
            float speed = m_Rigidbody.velocity.magnitude;
            switch (m_SpeedType)
            {
                case SpeedType.MPH:

                    speed *= 2.23693629f;
                    if (speed > m_Topspeed)
                        m_Rigidbody.velocity = (m_Topspeed/2.23693629f) * m_Rigidbody.velocity.normalized;
                    break;

                case SpeedType.KPH:
                    speed *= 3.6f;
                    if (speed > m_Topspeed)
                        m_Rigidbody.velocity = (m_Topspeed/3.6f) * m_Rigidbody.velocity.normalized;
                    break;
            }
        }


        private void ApplyDrive(float accel, float footbrake)
        {

            float thrustTorque;
            switch (m_CarDriveType)
            {
                case CarDriveType.FourWheelDrive:
                    thrustTorque = accel * (m_CurrentTorque / 4f);
                    for (int i = 0; i < 4; i++)
                    {
                        m_WheelColliders[i].motorTorque = thrustTorque;
                    }
                    break;

                case CarDriveType.FrontWheelDrive:
                    thrustTorque = accel * (m_CurrentTorque / 2f);
                    m_WheelColliders[0].motorTorque = m_WheelColliders[1].motorTorque = thrustTorque;
                    break;

                case CarDriveType.RearWheelDrive:
                    thrustTorque = accel * (m_CurrentTorque / 2f);
                    m_WheelColliders[2].motorTorque = m_WheelColliders[3].motorTorque = thrustTorque;
                    break;

            }

            for (int i = 0; i < 4; i++)
            {
                if (CurrentSpeed > 5 && Vector3.Angle(transform.forward, m_Rigidbody.velocity) < 50f)
                {
                    m_WheelColliders[i].brakeTorque = m_BrakeTorque*footbrake;
                }
                else if (footbrake > 0)
                {
                    m_WheelColliders[i].brakeTorque = 0f;
                    m_WheelColliders[i].motorTorque = -m_ReverseTorque*footbrake;
                }
            }
        }


        private void SteerHelper()
        {
            for (int i = 0; i < 4; i++)
            {
                WheelHit wheelhit;
                m_WheelColliders[i].GetGroundHit(out wheelhit);
                if (wheelhit.normal == Vector3.zero)
                    return; // wheels arent on the ground so dont realign the rigidbody velocity
            }

            // this if is needed to avoid gimbal lock problems that will make the car suddenly shift direction
            if (Mathf.Abs(m_OldRotation - transform.eulerAngles.y) < 10f)
            {
                var turnadjust = (transform.eulerAngles.y - m_OldRotation) * m_SteerHelper;
                Quaternion velRotation = Quaternion.AngleAxis(turnadjust, Vector3.up);
                m_Rigidbody.velocity = velRotation * m_Rigidbody.velocity;
            }
            m_OldRotation = transform.eulerAngles.y;
        }


        // this is used to add more grip in relation to speed
        private void AddDownForce()
        {
            m_WheelColliders[0].attachedRigidbody.AddForce(-transform.up*m_Downforce*
                                                         m_WheelColliders[0].attachedRigidbody.velocity.magnitude);
        }


        // checks if the wheels are spinning and is so does three things
        // 1) emits particles
        // 2) plays tiure skidding sounds
        // 3) leaves skidmarks on the ground
        // these effects are controlled through the WheelEffects class
        private void CheckForWheelSpin()
        {
            // loop through all wheels
            for (int i = 0; i < 4; i++)
            {
                WheelHit wheelHit;
                m_WheelColliders[i].GetGroundHit(out wheelHit);

                // is the tire slipping above the given threshhold
                if (Mathf.Abs(wheelHit.forwardSlip) >= m_SlipLimit || Mathf.Abs(wheelHit.sidewaysSlip) >= m_SlipLimit)
                {
                    m_WheelEffects[i].EmitTyreSmoke();

                    // avoiding all four tires screeching at the same time
                    // if they do it can lead to some strange audio artefacts
                    if (!AnySkidSoundPlaying())
                    {
                        m_WheelEffects[i].PlayAudio();
                    }
                    continue;
                }

                // if it wasnt slipping stop all the audio
                if (m_WheelEffects[i].PlayingAudio)
                {
                    m_WheelEffects[i].StopAudio();
                }
                // end the trail generation
                m_WheelEffects[i].EndSkidTrail();
            }
        }

        // crude traction control that reduces the power to wheel if the car is wheel spinning too much
        private void TractionControl()
        {
            WheelHit wheelHit;
            switch (m_CarDriveType)
            {
                case CarDriveType.FourWheelDrive:
                    // loop through all wheels
                    for (int i = 0; i < 4; i++)
                    {
                        m_WheelColliders[i].GetGroundHit(out wheelHit);

                        AdjustTorque(wheelHit.forwardSlip);
                    }
                    break;

                case CarDriveType.RearWheelDrive:
                    m_WheelColliders[2].GetGroundHit(out wheelHit);
                    AdjustTorque(wheelHit.forwardSlip);

                    m_WheelColliders[3].GetGroundHit(out wheelHit);
                    AdjustTorque(wheelHit.forwardSlip);
                    break;

                case CarDriveType.FrontWheelDrive:
                    m_WheelColliders[0].GetGroundHit(out wheelHit);
                    AdjustTorque(wheelHit.forwardSlip);

                    m_WheelColliders[1].GetGroundHit(out wheelHit);
                    AdjustTorque(wheelHit.forwardSlip);
                    break;
            }
        }


        private void AdjustTorque(float forwardSlip)
        {
            if (forwardSlip >= m_SlipLimit && m_CurrentTorque >= 0)
            {
                m_CurrentTorque -= 10 * m_TractionControl;
            }
            else
            {
                m_CurrentTorque += 10 * m_TractionControl;
                if (m_CurrentTorque > m_FullTorqueOverAllWheels)
                {
                    m_CurrentTorque = m_FullTorqueOverAllWheels;
                }
            }
        }


        private bool AnySkidSoundPlaying()
        {
            for (int i = 0; i < 4; i++)
            {
                if (m_WheelEffects[i].PlayingAudio)
                {
                    return true;
                }
            }
            return false;
        }
    }
}
使用系统;
使用UnityEngine;
命名空间UnityStandardAssets.Vehicles.Car
{
内部枚举类型
{
前轮驱动,
后轮驱动,
四轮驱动
}
内部枚举类型
{
每小时英里数,
KPH
}
公共类CarController:单行为
{
[SerializeField]private Card铆接类型m_Card铆接类型=Card铆接类型。四轮驱动;
[SerializeField]private WheelCollider[]m_WheelCollider=新的WheelCollider[4];
[SerializeField]私有游戏对象[]m_Wheelmesh=新游戏对象[4];
[SerializeField]private WheelEffects[]m_WheelEffects=新WheelEffects[4];
[SerializeField]专用向量3 m_CentreOfMassOffset;
[SerializeField]专用浮点m_MaximumSteerAngle;
[Range(0,1)][SerializeField]private float m_SteerHelper;//0是原始物理,1汽车将抓住它所面对的方向
[Range(0,1)][SerializeField]专用浮动m_牵引控制;//0表示无牵引控制,1表示完全干扰
[SerializeField]专用浮动m_FullTorque整体车轮;
[SerializeField]专用浮点m_ReverseTorque;
[SerializeField]专用浮点m_MaxHandbrakeTorque;
[Field]专用浮子m_下压力=100f;
[SerializeField]专用SpeedType Mu SpeedType;
[SerializeField]专用浮点m_Topspeed=200;
[SerializeField]私有静态int NoOfGears=5;
[SerializeField]专用浮点m_RevRangeBoundary=1f;
[SerializeField]私有浮点m_SlipLimit;
[field]私有浮动m_BrakeTorque;
私有四元数[]m_旋转;
专用矢量器3 m_Prevpos,m_Pos;
私人浮动m_SteerAngle;
私用国际货币基金组织;
私人浮动市盈率;
私有浮动m_OldRotation;
专用浮子m_电流转矩;
私人刚体m_刚体;
私有常数浮点k_反向阈值=0.01f;
公共场地打滑{get;private set;}
公共浮点BrakeInput{get;private set;}
公共浮点CurrentSteerAngle{get{return m_SteerAngle;}}
公共浮点CurrentSpeed{get{return m_Rigidbody.velocity.Magnite*2.23693629f;}
公共浮点最大速度{get{return m_Topspeed;}}
公共浮点数{get;private set;}
公共浮点输入{get;private set;}
//用于初始化
私有void Start()
{
m_WheelMeshLocalRotations=新的四元数[4];
对于(int i=0;i<4;i++)
{
m_WheelMeshLocalRotations[i]=m_WheelMesh[i]。transform.localRotation;
}
m_车轮碰撞器[0]。attachedRigidbody.centerOfMass=m_CentreOfMassOffset;
m_MaxHandbrakeTorque=float.MaxValue;
m_Rigidbody=GetComponent();
m_CurrentTorque=m_FullTorque Overall Wheels-(m_牵引控制*m_FullTorque Overall Wheels);
}
私有的
{
浮点f=数学绝对值(当前速度/最大速度);
浮点数上限=(1/(浮点数)*(m_GearNum+1);
浮动降档限位=(1/(浮动)无齿轮)*m_齿轮数;
如果(m_GearNum>0&&f上升速度限制&(m_GearNum<(NoOfGears-1)))
{
m_GearNum++;
}
}
//为0-1范围内的值添加向1的曲线偏移的简单函数
专用静态浮点曲线因子(浮点f
[SyncVar]
bool smokeOn;
if (!isServer)
{
  //Clients play their smoke locally depending on the synced variable
  if(smokeOn)
    particleSystem.Play();
  else
    particleSystem.Stop();
}
else 
{
  smokeOn = particleSystem.isPlaying;
}
 [Command]
 public void CmdSpell(int index, float time){

    var m_Spell = SpellGroup [index];
    GameObject spell = (GameObject)Instantiate (m_Spell, SpellCastPosition.position, SpellCastPosition.rotation);
    NetworkServer.Spawn (spell);
    Destroy (spell,time);
}