zoukankan      html  css  js  c++  java
  • mirrortankWar

    一、创建离线场景

    • 1、创建新项目,导入mirror,创建场景重命名为OfflineScenes
    • 2、从Prefabs文件夹中,将预制体LevelArt拖拽到场景中,LevelArt有光源,删除场景中自带的光源
    • 4、从models文件夹中,将Tank拖拽到场景中,调试好合适的位置,也可以拖拽其他的模型布置场景
    • 5、创建canvas,修改UI Scale Mode选项为:scale with screen size,下面的尺寸根据自己的需求更改,我打包出来的是4:3的界面,创建输入框--输入姓名,3个滑杆--调整颜色,一个按钮,其余的自做调整,
    • 6、创建一个空对象,重命名为OfflineManager,创建的脚本OffLineConfig.cs,编写代码,实现功能:tank旋转、拖动滑杆更新坦克颜色、保存输入框输入的姓名、坦克颜色,切换场景
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.SceneManagement;
    
    public class OffLineConfig : MonoBehaviour
    {
        // 坦克的Transform组件
        public Transform tank;
        // 坦克旋转速度
        public float speedR;
        // 坦克材质
        public Material materialTank;
        // 滑杆数组
        public Slider[] color;
        // 名字
        public Text playerNameText;
        // 提示信息
        public Text markedText;
        // 坦克颜色
        private Color tankColor;
      
    
        // Update is called once per frame
        void Update()
        {
            // 加负号是为了绕y轴逆时针旋转
            tank.Rotate(-Vector3.up * Time.deltaTime * speedR);
            // 修改颜色
            tankColor.r = color[0].value /255f;
            tankColor.g = color[1].value /255f;
            tankColor.b = color[2].value /255f;
            materialTank.color = tankColor;
        }
    
        public void clickConfigBtn()
        {
            // 如果姓名为空
            if(playerNameText.text == "")
            {
                // 提示
                markedText.color = Color.red;
                markedText.text = "名字不能为空!!!";
            }
            else
            {
                // 记录姓名、颜色
                PlayerPrefs.SetString("playerName", playerNameText.text);
                PlayerPrefs.SetFloat("tankR", tankColor.r);
                PlayerPrefs.SetFloat("tankG", tankColor.g);
                PlayerPrefs.SetFloat("tankB", tankColor.b);
                // 切换场景
                SceneManager.LoadScene(1);
            }
        }
    }
    •  7、一个离线场景,一个主场景,都放到build中,这样才能切换场景,将脚本OffLineConfig.cs绑定到OfflineManager物体上,将需要拖拽的物体拖拽到

     二、创建主场景

    • 1、创建新场景,重命名为main,创建一个空对象,重命名为NetworkManager,添加脚本NetworkManagerHUD,会自动再添加两个组件,将可以修改Server Tick Rate,OfflineScenes场景拖拽到Offline Scenes中
    •  2、tank初始化

      • 将Tank拖拽到场景中,调整与摄像机的位置

      • 坦克添加刚体组件,坦克添加碰撞盒子,设置位置为(0,0.95,0),大小为(1.51,1.71,1.62),注意:碰撞盒子不能紧挨地面,容易检测坦克与地面发生碰撞导致坦克无法移动。
      • 在坦克里创建一个3D Text,重命名为playerName,调整位置,添加NetworkIdentity、NetworkTransform组件,将坦克做成预制体,将其拖拽到NetworkManager中的Player Prefab

    • 3、 创建脚本TankControl.cs,拖拽到Tank上,编写脚本,先完成的功能是能够同步名字、材质

      • using System.Collections;
        using System.Collections.Generic;
        using UnityEngine;
        // 引用mirror
        using Mirror;
        // 继承NetworkBehaviour
        public class TankControl : NetworkBehaviour
        {
            // 3DText,用于显示玩家姓名
            public TextMesh player3DText;
            
            // 坦克材质
            public Material materialTank;
            // 坦克颜色
            private Color tankColor;
        
            // OnStartLocalPlayer 类似star(),只在本地玩家上被调用
            public override void OnStartLocalPlayer()
            {
                player3DText.text = PlayerPrefs.GetString("playerName");
                tankColor.r = PlayerPrefs.GetFloat("tankR");
                tankColor.g = PlayerPrefs.GetFloat("tankG");
                tankColor.b = PlayerPrefs.GetFloat("tankB");
            }
        
        }
      • 将该拖拽的拖拽上去,保存场景,打包,发现名字和材质并没有同步,只是在自己的客户端上更改了
      • 为了同步,我们使用SynVar:用于同步服务器和所有客户端的变量,变量只能在服务器上更改
      • 变量只能在服务其被修改,所以在客户端调用的方法,上面要加上【command],修改代码
      • using System.Collections;
        using System.Collections.Generic;
        using UnityEngine;
        // 引用mirror
        using Mirror;
        // 继承NetworkBehaviour
        public class TankControl : NetworkBehaviour
        {
            // 3DText,用于显示玩家姓名
            public TextMesh player3DText;
            
            // 坦克盖材质
            public MeshRenderer RendererTank;
            // 坦克头材质
            public MeshRenderer RendererTankHead;
            // 坦克左轮
            public MeshRenderer RendererTankLeft;
            // 坦克右轮
            public MeshRenderer RendererTankRight;
        
            // 存放
            private Material playerMaterialClone;
        
            // SynVar用于同步服务器和所有客户端的变量,变量只能在服务器上更改
            // hook允许你创建一个在客户端的方法,当客户端上接受到更新的信息后,执行这个方法
            [SyncVar(hook = nameof(OnNameChanged))]
            public string playerName;
            // 名字发生改变
            void OnNameChanged(string _old, string _new)
            {
                player3DText.text = playerName;
            }
        
        
            [SyncVar(hook = nameof(OnColorChanged))]
            public Color playerColor;
        
            // 颜色发生变化TODO
            void OnColorChanged(Color _old, Color _new)
            {
                // 为playerMaterialClone赋值,任何都可以,只要是material类型
                playerMaterialClone = new Material(RendererTank.material);
                playerMaterialClone.color = playerColor;
                RendererTank.material = playerMaterialClone;
                RendererTankHead.material = playerMaterialClone;
                RendererTankLeft.material = playerMaterialClone;
                RendererTankRight.material = playerMaterialClone;
            }
        
            // OnStartLocalPlayer 类似star(),只在本地玩家上被调用
            public override void OnStartLocalPlayer()
            {
                // 获取玩家名字
                string name = PlayerPrefs.GetString("playerName");
                // 获取颜色一个颜色
                Color tankColor = new Color(PlayerPrefs.GetFloat("tankR"), PlayerPrefs.GetFloat("tankG"), PlayerPrefs.GetFloat("tankB"));
                // 调用方法,修改变量要在服务器端
                cmdSetupPlayer(name, tankColor);
            }
        
            //Command,从客户端调用,但是在服务器上运行
            [Command]
            void cmdSetupPlayer(string _name, Color _color)
            {
                //玩家信息发送到服务器,然后服务器更新所有客户端上SyncVar变量
                playerName = _name;
                playerColor = _color;
            }
        }
      • 保存场景,打包,发现名字同步了,但是所有客户端的材质颜色会改成最后一个客户端的颜色
      • 这是因为我一直改的都是TankColour材质的颜色,而所有的客户端坦克上都用的这个材质,只要一个发生变化,都发生变化,所以应该是每一个客户端创建新材质替换TankColour材质,而不是修改TankColour材质
      •  坦克的部分是分开的,所以需要用创建的材质,替换所有部分的材质,修改代码-------成功

      •  
      • using System.Collections;
        using System.Collections.Generic;
        using UnityEngine;
        // 引用mirror
        using Mirror;
        // 继承NetworkBehaviour
        public class TankControl : NetworkBehaviour
        {
            // 3DText,用于显示玩家姓名
            public TextMesh player3DText;
            
            // 坦克盖材质
            public MeshRenderer RendererTank;
            // 坦克头材质
            public MeshRenderer RendererTankHead;
            // 坦克左轮
            public MeshRenderer RendererTankLeft;
            // 坦克右轮
            public MeshRenderer RendererTankRight;
        
            // 存放
            private Material playerMaterialClone;
        
            // SynVar用于同步服务器和所有客户端的变量,变量只能在服务器上更改
            // hook允许你创建一个在客户端的方法,当客户端上接受到更新的信息后,执行这个方法
            [SyncVar(hook = nameof(OnNameChanged))]
            public string playerName;
            // 名字发生改变
            void OnNameChanged(string _old, string _new)
            {
                player3DText.text = playerName;
            }
        
        
            [SyncVar(hook = nameof(OnColorChanged))]
            public Color playerColor;
        
            // 颜色发生变化TODO
            void OnColorChanged(Color _old, Color _new)
            {
                // 为playerMaterialClone赋值,任何都可以,只要是material类型
                playerMaterialClone = new Material(RendererTank.material);
                playerMaterialClone.color = playerColor;
                RendererTank.material = playerMaterialClone;
                RendererTankHead.material = playerMaterialClone;
                RendererTankLeft.material = playerMaterialClone;
                RendererTankRight.material = playerMaterialClone;
            }
        
            // OnStartLocalPlayer 类似star(),只在本地玩家上被调用
            public override void OnStartLocalPlayer()
            {
                // 获取玩家名字
                string name = PlayerPrefs.GetString("playerName");
                // 获取颜色一个颜色
                Color tankColor = new Color(PlayerPrefs.GetFloat("tankR"), PlayerPrefs.GetFloat("tankG"), PlayerPrefs.GetFloat("tankB"));
                // 调用方法,修改变量要在服务器端
                cmdSetupPlayer(name, tankColor);
            }
        
            //Command,从客户端调用,但是在服务器上运行
            [Command]
            void cmdSetupPlayer(string _name, Color _color)
            {
                //玩家信息发送到服务器,然后服务器更新所有客户端上SyncVar变量
                playerName = _name;
                playerColor = _color;
            }
        }
    • 4、移动+相机跟随 
      • 看一看下面有没有勾选上
      • 时间有限不详细叙述代码,创建相关变量,

      • 此时代码TankControl.cs的代码
      • using System.Collections;
        using System.Collections.Generic;
        using UnityEngine;
        // 引用mirror
        using Mirror;
        // 继承NetworkBehaviour
        public class TankControl : NetworkBehaviour
        {
            // 同步姓名、材质
            // 3DText,用于显示玩家姓名
            public TextMesh player3DText;
            
            // 坦克盖材质
            public MeshRenderer RendererTank;
            // 坦克头材质
            public MeshRenderer RendererTankHead;
            // 坦克左轮
            public MeshRenderer RendererTankLeft;
            // 坦克右轮
            public MeshRenderer RendererTankRight;
            // 存放
            private Material playerMaterialClone;
        
        
        
            // 相机跟随+移动
            private float moveSpeed = 5;  // 坦克移动的速度
            private float turnSpped = 5; // 坦克转向的速度
            private Rigidbody rb;    // 刚体组件
        
            private Vector3 offset;//和相机的相对位置
            Quaternion camRotation;   //记录相机初始角度
         
        
        
            // SynVar用于同步服务器和所有客户端的变量,变量只能在服务器上更改
            // hook允许你创建一个在客户端的方法,当客户端上接受到更新的信息后,执行这个方法
            [SyncVar(hook = nameof(OnNameChanged))]
            public string playerName;
            // 名字发生改变
            void OnNameChanged(string _old, string _new)
            {
                player3DText.text = playerName;
            }
        
        
            [SyncVar(hook = nameof(OnColorChanged))]
            public Color playerColor;
        
            // 颜色发生变化TODO
            void OnColorChanged(Color _old, Color _new)
            {
                // 为playerMaterialClone赋值,任何都可以,只要是material类型
                playerMaterialClone = new Material(RendererTank.material);
                playerMaterialClone.color = playerColor;
                RendererTank.material = playerMaterialClone;
                RendererTankHead.material = playerMaterialClone;
                RendererTankLeft.material = playerMaterialClone;
                RendererTankRight.material = playerMaterialClone;
            }
        
            // OnStartLocalPlayer 类似star(),只在本地玩家上被调用
            public override void OnStartLocalPlayer()
            {
                // 获取玩家名字
                string name = PlayerPrefs.GetString("playerName");
                // 获取颜色一个颜色
                Color tankColor = new Color(PlayerPrefs.GetFloat("tankR"), PlayerPrefs.GetFloat("tankG"), PlayerPrefs.GetFloat("tankB"));
                // 调用方法,修改变量要在服务器端
                cmdSetupPlayer(name, tankColor);
        
        
                rb = GetComponent<Rigidbody>();
                offset = Camera.main.transform.position - transform.position;
                camRotation = Camera.main.transform.rotation;
            }
        
        
            // 物理动作尽量放到FixedUpdate中
            void FixedUpdate()
            {
                // 如果不是本地玩家,不执行下面的代码
                if (!isLocalPlayer) return;
                // 相机跟随
                Camera.main.transform.position = transform.position + offset;
                // 控制转向--转向是y轴方向转向,水平变量控制
                float h = Input.GetAxis("Horizontal");
                // 控制前进
                float v = Input.GetAxis("Vertical");
                // 前进
                rb.velocity = transform.forward * v * moveSpeed;
                // 转向
                rb.angularVelocity = transform.up * h * turnSpped;
        
            }
        
        
            //Command,从客户端调用,但是在服务器上运行
            [Command]
            void cmdSetupPlayer(string _name, Color _color)
            {
                //玩家信息发送到服务器,然后服务器更新所有客户端上SyncVar变量
                playerName = _name;
                playerColor = _color;
            }
        }
    • 5、发射子弹
      • 在tank预制体中创建一个空对象,重命名FirePos,用来做发射子弹的地点,设置位置和角度
      • 从models中添加子弹,为子弹添加碰撞器、刚体组件、将子弹设置成预制体
      • 添加变量,编写代码,拖拽该有的变量
      • 打包、运行,只能在自身的客户生成子弹,无法在所有客户端同步,应该在所有的客户端生成子弹,这里要用到Spawn
      • 修改代码
      •  用Spawn()生成的物体要加上Networkidentity组件,所以给子弹加上Networkidentity组件,并且添加到NetworkManage组件中

      •  打包、运行,只能在自身的客户生成子弹,无法在所有客户端同步,是因为Spawn()需要服务器调用,所以修改代码

      • 此时代码TankControl.cs的代码
      • using System.Collections;
        using System.Collections.Generic;
        using UnityEngine;
        // 引用mirror
        using Mirror;
        // 继承NetworkBehaviour
        public class TankControl : NetworkBehaviour
        {
            // 同步姓名、材质
            // 3DText,用于显示玩家姓名
            public TextMesh player3DText;
            
            // 坦克盖材质
            public MeshRenderer RendererTank;
            // 坦克头材质
            public MeshRenderer RendererTankHead;
            // 坦克左轮
            public MeshRenderer RendererTankLeft;
            // 坦克右轮
            public MeshRenderer RendererTankRight;
            // 存放
            private Material playerMaterialClone;
        
        
        
            // 相机跟随+移动
            private float moveSpeed = 5;  // 坦克移动的速度
            private float turnSpped = 5; // 坦克转向的速度
            private Rigidbody rb;    // 刚体组件
        
            private Vector3 offset;//和相机的相对位置
            Quaternion camRotation;   //记录相机初始角度
        
        
            // 发射子弹
            public GameObject shellPrefab;   // 子弹预制体
            public Transform firePoint;     // 发射点的Transform组件
        
        
        
            // SynVar用于同步服务器和所有客户端的变量,变量只能在服务器上更改
            // hook允许你创建一个在客户端的方法,当客户端上接受到更新的信息后,执行这个方法
            [SyncVar(hook = nameof(OnNameChanged))]
            public string playerName;
            // 名字发生改变
            void OnNameChanged(string _old, string _new)
            {
                player3DText.text = playerName;
            }
        
        
            [SyncVar(hook = nameof(OnColorChanged))]
            public Color playerColor;
        
            // 颜色发生变化TODO
            void OnColorChanged(Color _old, Color _new)
            {
                // 为playerMaterialClone赋值,任何都可以,只要是material类型
                playerMaterialClone = new Material(RendererTank.material);
                playerMaterialClone.color = playerColor;
                RendererTank.material = playerMaterialClone;
                RendererTankHead.material = playerMaterialClone;
                RendererTankLeft.material = playerMaterialClone;
                RendererTankRight.material = playerMaterialClone;
            }
        
            // OnStartLocalPlayer 类似star(),只在本地玩家上被调用
            public override void OnStartLocalPlayer()
            {
                // 获取玩家名字
                string name = PlayerPrefs.GetString("playerName");
                // 获取颜色一个颜色
                Color tankColor = new Color(PlayerPrefs.GetFloat("tankR"), PlayerPrefs.GetFloat("tankG"), PlayerPrefs.GetFloat("tankB"));
                // 调用方法,修改变量要在服务器端
                cmdSetupPlayer(name, tankColor);
        
                // 与相机的偏移量,相机 的初始角度
                rb = GetComponent<Rigidbody>();
                offset = Camera.main.transform.position - transform.position;
                camRotation = Camera.main.transform.rotation;
            }
        
        
            // 物理动作尽量放到FixedUpdate中
            void FixedUpdate()
            {
                // 如果不是本地玩家,不执行下面的代码
                if (!isLocalPlayer) return;
                // 相机跟随
                Camera.main.transform.position = transform.position + offset;
                // 控制转向--转向是y轴方向转向,水平变量控制
                float h = Input.GetAxis("Horizontal");
                // 控制前进
                float v = Input.GetAxis("Vertical");
                // 前进
                rb.velocity = transform.forward * v * moveSpeed;
                // 转向
                rb.angularVelocity = transform.up * h * turnSpped;
        
                // 如果按下空格键,射击
                if (Input.GetKeyDown(KeyCode.Space))
                {
                    // 射击
                    shoot();
                }
            }
        
            //加上[Command]的方法,为客户端向服务器端发消息,让服务器执行此方法
            [Command]
            void shoot()
            {
                // 实例化子弹
                GameObject go = Instantiate(shellPrefab, firePoint.position, firePoint.rotation);
                // Spawn:在所有的客户端生成括号里面的物体
                NetworkServer.Spawn(go);
            }
        
        
        
        
            //Command,从客户端调用,但是在服务器上运行
            [Command]
            void cmdSetupPlayer(string _name, Color _color)
            {
                //玩家信息发送到服务器,然后服务器更新所有客户端上SyncVar变量
                playerName = _name;
                playerColor = _color;
            }
        }
      • 现在能够同步出现子弹了,但是子弹没有速度,创建脚本ShellControl.cs脚本,拖拽给shell子弹,将爆炸效果拖拽上去
      • using System.Collections;
        using System.Collections.Generic;
        using UnityEngine;
        
        public class ShellControl : MonoBehaviour
        {
            public float shellSpeed = 10;    // 子弹速度
            private Rigidbody shellRb;       // 子弹刚体组件
        
            public GameObject shellExplosionPrefab; // 子弹爆炸效果
            // Start is called before the first frame update
            void Start()
            {
                shellRb = GetComponent<Rigidbody>();
                // 设置初速度,不能写到update中,速度只设置一次就好
                shellRb.velocity = transform.forward * shellSpeed;
            }
        
        
            // 子弹碰撞到东西是爆炸
            private void OnTriggerEnter(Collider other)
            {
                // 实例化爆炸效果
                GameObject.Instantiate(shellExplosionPrefab, transform.position, transform.rotation);
                // 删除子弹
                Destroy(gameObject);
            }
        }
      • 由于每个客户端都生成了子弹,所有爆炸效果也都可以生成,所以不需要考虑爆炸同步,子弹能够删除,但是爆炸效果没有删除,所以为爆炸效果创建组件DestoryExplore.cs

      • using System.Collections;
        using System.Collections.Generic;
        using UnityEngine;
        
        public class DestoryExplore : MonoBehaviour
        {
            // Start is called before the first frame update
            void Start()
            {
                // 删除爆炸效果
                GameObject.Destroy(gameObject, 1.5f);
            }
        
        }
      • 发射子弹功能完毕(爆炸效果还是有点问题
    • 6、坦克伤害
      • 创建变量hp表示坦克血量,判断坦克的碰撞体,碰到的是不是子弹,谁碰到,谁减血,用到TargetRpc。
      • 打包,运行,会发现只有客户端的 删掉了自己的坦克,因为我们只让受伤的目标客户端删掉了(看天蓝色的坦克)。修改代码

      • 现在就可以了

    • 7、坦克重生

      • 坦克消失,身上的脚本就不起作用了,所以需要在场景中创建一个空物体,重命名GameManager,在上面创建脚本GameManager.cs,编写代码

      • using System.Collections;
        using System.Collections.Generic;
        using UnityEngine;
        using UnityEngine.SceneManagement;
        using Mirror;
        
        public class GameManager : NetworkBehaviour
        {
            // 为了在其他脚本中,更好的调用,制作成单例
            public static GameManager instance;
            // 判断玩家是否死亡
            public bool isPlayerDead = false;
        
            private void Awake()
            {
                instance = this;
            }
        
            private void Update()
            {
                // 如果按下p键并且isPlayerDead为True,才能重生
                if (Input.GetKeyDown(KeyCode.P) && isPlayerDead )
                {
                    // 重新设置摄像机的位置
                    Camera.main.transform.position = new Vector3(0f, 3.5f, -9.5f);
                    // 重新生成玩家
                    NetworkClient.AddPlayer();
                }      
            }
        }
      • 在TankControl脚本中,添加代码
      • 坦克重生完成,运行会发现,重生的坦克有些问题(会和最后一个进入客户端的坦克同名同材质,)稍后测试是不是同一台电脑的原因
      • 目前为止,此时代码TankControl.cs的代码
      • using System.Collections;
        using System.Collections.Generic;
        using UnityEngine;
        // 引用mirror
        using Mirror;  
        // 继承NetworkBehaviour
        public class TankControl : NetworkBehaviour
        {
            // 同步姓名、材质
            // 3DText,用于显示玩家姓名
            public TextMesh player3DText;
            
            // 坦克盖材质
            public MeshRenderer RendererTank;
            // 坦克头材质
            public MeshRenderer RendererTankHead;
            // 坦克左轮
            public MeshRenderer RendererTankLeft;
            // 坦克右轮
            public MeshRenderer RendererTankRight;
            // 存放
            private Material playerMaterialClone;
        
        
        
            // 相机跟随+移动
            private float moveSpeed = 5;  // 坦克移动的速度
            private float turnSpped = 5; // 坦克转向的速度
            private Rigidbody rb;    // 刚体组件
        
            private Vector3 offset;//和相机的相对位置
            Quaternion camRotation;   //记录相机初始角度
        
        
            // 发射子弹
            public GameObject shellPrefab;   // 子弹预制体
            public Transform firePoint;     // 发射点的Transform组件
        
        
            // 坦克血量
            int hp = 20;
        
        
        
            // SynVar用于同步服务器和所有客户端的变量,变量只能在服务器上更改
            // hook允许你创建一个在客户端的方法,当客户端上接受到更新的信息后,执行这个方法
            [SyncVar(hook = nameof(OnNameChanged))]
            public string playerName;
            // 名字发生改变
            void OnNameChanged(string _old, string _new)
            {
                player3DText.text = playerName;
            }
        
        
            [SyncVar(hook = nameof(OnColorChanged))]
            public Color playerColor;
        
            // 颜色发生变化TODO
            void OnColorChanged(Color _old, Color _new)
            {
                // 为playerMaterialClone赋值,任何都可以,只要是material类型
                playerMaterialClone = new Material(RendererTank.material);
                playerMaterialClone.color = playerColor;
                RendererTank.material = playerMaterialClone;
                RendererTankHead.material = playerMaterialClone;
                RendererTankLeft.material = playerMaterialClone;
                RendererTankRight.material = playerMaterialClone;
            }
        
            // OnStartLocalPlayer 类似star(),只在本地玩家上被调用
            public override void OnStartLocalPlayer()
            {
                // 获取玩家名字
                string name = PlayerPrefs.GetString("playerName");
                // 获取颜色一个颜色
                Color tankColor = new Color(PlayerPrefs.GetFloat("tankR"), PlayerPrefs.GetFloat("tankG"), PlayerPrefs.GetFloat("tankB"));
                // 调用方法,修改变量要在服务器端
                cmdSetupPlayer(name, tankColor);
        
                // 与相机的偏移量,相机 的初始角度
                rb = GetComponent<Rigidbody>();
                offset = Camera.main.transform.position - transform.position;
                camRotation = Camera.main.transform.rotation;
            }
        
        
            // 物理动作尽量放到FixedUpdate中
            void FixedUpdate()
            {
                // 如果不是本地玩家,不执行下面的代码
                if (!isLocalPlayer) return;
                // 相机跟随
                Camera.main.transform.position = transform.position + offset;
                // 控制转向--转向是y轴方向转向,水平变量控制
                float h = Input.GetAxis("Horizontal");
                // 控制前进
                float v = Input.GetAxis("Vertical");
                // 前进
                rb.velocity = transform.forward * v * moveSpeed;
                // 转向
                rb.angularVelocity = transform.up * h * turnSpped;
        
                // 如果按下空格键,射击
                if (Input.GetKeyDown(KeyCode.Space))
                {
                    // 射击
                    shoot();
                }
            }
        
            //加上[Command]的方法,为客户端向服务器端发消息,让服务器执行此方法
            [Command]
            void shoot()
            {
                // 实例化子弹
                GameObject go = Instantiate(shellPrefab, firePoint.position, firePoint.rotation);
                // Spawn:在所有的客户端生成括号里面的物体
                NetworkServer.Spawn(go);
            }
        
        
        
            //Command,从客户端调用,但是在服务器上运行
            [Command]
            void cmdSetupPlayer(string _name, Color _color)
            {
                //玩家信息发送到服务器,然后服务器更新所有客户端上SyncVar变量
                playerName = _name;
                playerColor = _color;
            }
        
            // 进入的是子弹
            private void OnCollisionEnter(Collision collision)
            {
                // 这个判断需要在服务器端调用,不能是客户端,如果发现卡顿,就会出现问题
                if(collision.gameObject.tag == "Shell" && isServer)
                {
                    // 谁碰到谁减血
                    NetworkIdentity networkIdentity = GetComponent<NetworkIdentity>();
                    TakeDamage(networkIdentity.connectionToClient);
                }
            }
        
            [TargetRpc]
            void TakeDamage(NetworkConnection connection)
            {
                
                if (hp <= 0) return;  // 如果血量小于0,直接返回
        
                hp -= 10; // 伤害
                //第一次 血量变成0
                if (hp <= 0)
                {
                    // 将目标客户端上的isPlayerDead,设置为True
                    GameManager.instance.isPlayerDead = true;
                    // 删除这个坦克,在服务器上删除,其他的客户端都会删
                    DestroyTank();
                }
            }
            
            [Command]
            void DestroyTank()
            {
                NetworkServer.Destroy(this.gameObject);
            }
        }
    • 8、答题重生
      • 创建一个脚本QuestionData.cs,里面写一个题类
      • // 题类
        public class QuestionData 
        {
            // 问题
            public  string question;
            // 答案
            public string answer;
        }
      • 创建一个文件夹Resources,在创建一个文本,里面题和答案用逗号分割开
      • 修改GameManager.cs中的代码
      • 创建UI,自己做选择,创建一个Text用来显示题目,一个输入框输入答案,一个按钮用来确定,我还创建了一个Text用来提示(按p键重生)
      •  编写代码

      • using System.Collections;
        using System.Collections.Generic;
        using UnityEngine;
        using UnityEngine.SceneManagement;
        using Mirror;
        using UnityEngine.UI;
        
        public class GameManager : NetworkBehaviour
        {
            // 为了在其他脚本中,更好的调用,制作成单例
            public static GameManager instance;
            // 判断玩家是否死亡
            public bool isPlayerDead = false;
            // 创建列表,存储每一道题
            List<QuestionData> quests = new List<QuestionData>();
        
            // 显示题目的面板
            public GameObject panel;
            // 答案
            public Text answer;
            // 问题
            public Text question;
            // 题目序号
            int n = 0;
        
            private void Awake()
            {
                instance = this;
                // 加载问题文件
                TextAsset questiondata = Resources.Load<TextAsset>("question1");
                string a = questiondata.text;
                foreach (var item in a.Split('\n'))
                {
                    QuestionData q = new QuestionData();
                    string[] b = item.Split(',');
                    q.question = b[0];
        
                    // 大坑:1、编码格式不同 2、没有清除前后的空格
                    q.answer = b[1].Trim();
                    quests.Add(q);
                }
                // 设置初始问题
                question.text = quests[n].question;
            }
        
            private void Update()
            {
                // 如果按下p键并且isPlayerDead为True,才能重生
                if (Input.GetKeyDown(KeyCode.P) && isPlayerDead )
                {
                    // 显示问题面板
                    panel.SetActive(true);
                }      
            }
        
            public void Check()
            {
                // 如果回答对
                if (answer.text == quests[n].answer)
                {
                    // 随机一个序号
                    n = Random.Range(0, quests.Count - 1);
                    question.text = quests[n].question;
                    // 隐藏问题面板
                    panel.SetActive(false);
                    // 设置isPlayerDead为false
                    isPlayerDead = false;
                    // 重新设置摄像机的位置
                    Camera.main.transform.position = new Vector3(0f, 3.5f, -9.5f);
                    // 重新生成玩家
                    NetworkClient.AddPlayer();
        
                }
            }
        }
      • 拖拽需要的变量
      • 结束

    • 之后是微调,比如添加点错误提示,加点音效,扩展题库。 

  • 相关阅读:
    Java集合框架
    数字翻转
    Servlet的一些细节
    tomcat9配置https
    JavaWeb_打包web应用war
    JavaWeb_tomcat设置默认应用
    JavaWeb_增强for循环
    JavaWeb_静态导入、自动拆箱/装箱
    JavaWeb_泛型(Generic)
    54字符流中第一个不重复的字符
  • 原文地址:https://www.cnblogs.com/jiangzijiang/p/15755270.html
Copyright © 2011-2022 走看看