前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >mirror--tankWar

mirror--tankWar

作者头像
酱紫安
发布2022-05-10 16:42:29
1.3K0
发布2022-05-10 16:42:29
举报
文章被收录于专栏:python学习路python学习路

一、创建离线场景

  • 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旋转、拖动滑杆更新坦克颜色、保存输入框输入的姓名、坦克颜色,切换场景
代码语言:javascript
复制
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上,编写脚本,先完成的功能是能够同步名字、材质
    • 将该拖拽的拖拽上去,保存场景,打包,发现名字和材质并没有同步,只是在自己的客户端上更改了
    • 为了同步,我们使用SynVar:用于同步服务器和所有客户端的变量,变量只能在服务器上更改
    • 变量只能在服务其被修改,所以在客户端调用的方法,上面要加上【command],修改代码
    代码语言:javascript
    复制
    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材质
    •  坦克的部分是分开的,所以需要用创建的材质,替换所有部分的材质,修改代码-------成功
    代码语言:javascript
    复制
    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;
        }
    }
代码语言:javascript
复制
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");
    }

}
  • 4、移动+相机跟随 
    • 看一看下面有没有勾选上
    • 时间有限不详细叙述代码,创建相关变量,
    • 此时代码TankControl.cs的代码
代码语言:javascript
复制
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的代码
    • 现在能够同步出现子弹了,但是子弹没有速度,创建脚本ShellControl.cs脚本,拖拽给shell子弹,将爆炸效果拖拽上去
    代码语言:javascript
    复制
    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
    代码语言:javascript
    复制
    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);
        }
    
    }
    • 发射子弹功能完毕(爆炸效果还是有点问题)
代码语言:javascript
复制
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;
    }
}
  • 6、坦克伤害
    • 创建变量hp表示坦克血量,判断坦克的碰撞体,碰到的是不是子弹,谁碰到,谁减血,用到TargetRpc。
    • 打包,运行,会发现只有客户端的 删掉了自己的坦克,因为我们只让受伤的目标客户端删掉了(看天蓝色的坦克)。修改代码
    • 现在就可以了
  • 7、坦克重生
    • 坦克消失,身上的脚本就不起作用了,所以需要在场景中创建一个空物体,重命名GameManager,在上面创建脚本GameManager.cs,编写代码
    • 在TankControl脚本中,添加代码
    • 坦克重生完成,运行会发现,重生的坦克有些问题(会和最后一个进入客户端的坦克同名同材质,)稍后测试是不是同一台电脑的原因
    • 目前为止,此时代码TankControl.cs的代码
    代码语言:javascript
    复制
    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);
        }
    }
代码语言:javascript
复制
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();
        }      
    }
}
  • 8、答题重生
    • 创建一个脚本QuestionData.cs,里面写一个题类
    • 创建一个文件夹Resources,在创建一个文本,里面题和答案用逗号分割开
    • 修改GameManager.cs中的代码
    • 创建UI,自己做选择,创建一个Text用来显示题目,一个输入框输入答案,一个按钮用来确定,我还创建了一个Text用来提示(按p键重生)
    •  编写代码
    代码语言:javascript
    复制
    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();
    
            }
        }
    }
    • 拖拽需要的变量
    • 结束
代码语言:javascript
复制
// 题类
public class QuestionData 
{
    // 问题
    public  string question;
    // 答案
    public string answer;
}
  • 之后是微调,比如添加点错误提示,加点音效,扩展题库。 
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-01-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、创建离线场景
  •  二、创建主场景
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档