Unity学习之路10——多人游戏与网络

Unity学习之路10——多人游戏与网络

作业要求:

  • 选择一个以前的作业或自己选择一个小游戏,设计成网络游戏

效果图:

实现过程

上一次作业的基础上,将AI小坦克改成双人对战坦克游戏。

  • 主要参考资料——老师的博客
  • Step1:
    为了简化,去掉了上次作业的SceneController,IUserAction,IUserGUI,GameDirector,Enemy代码文件,只保留Player.cs,Bullet.cs,MyFactory.cs,Tank.cs文件。

  • Step2:Player中原逻辑不变,将UI中检测用户按键输入的代码迁移到Player.cs里的Update函数中:

public class Player : Tank{
    // player被摧毁时发布信息;
    /* public delegate void DestroyPlayer();
     public static event DestroyPlayer destroyEvent;*/

    public override void OnStartLocalPlayer()
    {
        GetComponent<MeshRenderer>().material.color = Color.blue;
    }
    void Start () {
        setHP(500);   
    }

    // Update is called once per frame
    void Update () {
        if (!isLocalPlayer)
            return;
        Camera.main.transform.position = new Vector3(gameObject.transform.position.x, 18, gameObject.transform.position.z);
        if (getHP() <= 0)    // Tank is destoryed
        {
            this.gameObject.SetActive(false);
            //destroyEvent();
        }

        if (Input.GetKey(KeyCode.W))
        {
            moveForward();
        }

        if (Input.GetKey(KeyCode.S))
        {
            moveBackWard();
        }

        if (Input.GetKeyDown(KeyCode.Space))
        {
            Debug.Log("space");
            CmdFire(TankType.PLAYER);
        }
        //获取水平轴上的增量,目的在于控制玩家坦克的转向
        float offsetX = Input.GetAxis("Horizontal");
        turn(offsetX);
    }

    //向前移动
    public void moveForward()
    {
        gameObject.GetComponent<Rigidbody>().velocity = gameObject.transform.forward * 25;
    }
    //向后移动
    public void moveBackWard()
    {
        gameObject.GetComponent<Rigidbody>().velocity = gameObject.transform.forward * -25;
    }

    //通过水平轴上的增量,改变玩家坦克的欧拉角,从而实现坦克转向
    public void turn(float offsetX)
    {
        float x = gameObject.transform.localEulerAngles.x;
        float y = gameObject.transform.localEulerAngles.y + offsetX*2;
        gameObject.transform.localEulerAngles = new Vector3(x, y, 0);
    }
}
  • Step3:其中Player继承的Tank需要改一下,记住Tank.cs继承的不再是MonoBehaviour,而是NetworkBehaviour:
public class Tank : NetworkBehaviour
{
    private float hp =500.0f;
    // 初始化
    public Tank()
    {
        hp = 500.0f;
    }

    public float getHP()
    {
        return hp;
    }

    public void setHP(float hp)
    {
        this.hp = hp;
    }

    public void beShooted()
    {
        hp -= 100;
    }

    [Command]
    public void CmdFire(TankType type)
    {
        GameObject bullet = Singleton<MyFactory>.Instance.getBullets(type);

        bullet.transform.position = new Vector3(gameObject.transform.position.x, 1.5f, gameObject.transform.position.z) + gameObject.transform.forward * 1.5f;
        bullet.transform.forward = gameObject.transform.forward; //方向
        bullet.GetComponent<Rigidbody>().AddForce(bullet.transform.forward * 20, ForceMode.Impulse);

        NetworkServer.Spawn(bullet);

        Destroy(bullet, 2.0f);
    }
}

其中[Command]是用来标记该函数是在服务端执行的,即使是在客户端触发也是在服务端执行,还有该函数名一定是要以Cmd开头命名的;然后在函数里调用NetworkServer.Spawn()使服务端和客户端同步。

  • Step4:Bullet.cs根据需要修改一下,代码模块就修改成这样,接下来是网络的构建,按照老师的一步一步来:
    Game Object -> Create Empty 添加一个新的空游戏对象;将对象重命名为“NetworkManager”,往该物体添加NetworkManager和NetworkManagerHUD组件(选中该物体,在菜单栏里选Component-> Network -> NetworkManager);成功后界面应该是这样:

另外还要将Player和Bullet预制(即坦克与子弹预制)拖进对应的slot槽才有以上界面,而预制要按Step5里的步骤添加组件才能拖到对应的slot槽里。

  • Step5:分别往Player和Bullet预制添加NetworkIdentity和NetworkTransform组件(Component->Network->NetworkIdentity或NetworkTransform)其中NetworkIdentity组件用于标识服务器和客户端之间的对象,而NetworkTransform组件使对象在网络中同步它的位置。
    Player预制添加组件后的效果,记得把Local Player Authority勾上:

  • Step6:Bullet预制添加组件后的效果:

  • Step7:运行代码(老师博客上也有对应的详细操作步骤)

    • 使用菜单 File -> Build Settings 打开 Build Settings 对话框。
    • 按下 “Add Open Scenes” 按钮,将当前场景添加到版本。
    • 按 “Build and Run” 按钮创建构建。这会提示输入可执行文件的名称,随便输入一个名称。
    • 译后的独立程序将启动,并显示分辨率选择对话框。
    • 选择 “windowed” 复选框和较低的分辨率,如640x480。
    • 从菜单中选择 “HOSTED” 作为主机启动。
    • 切换回编辑器并关闭 Build Settings 对话框,使用运行按钮进入运行模式。
    • 从 NetworkManagerHUD 用户界面中,选择 “LAN Client” 作为客户端连接到主机。
    • 应该出现两个坦克,一个在主机上的本地运行,另一个在该客户端的远程运行。
    • 效果图:

未解决的问题

  • 做的不好,还遗留一些问题:
    • 坦克只实现了移动同步,即客户端或服务端里其中一个坦克移动,另一个窗口里对应的坦克也会移动。
    • 坦克的射击功能还有bug,在客户端点击空格射击时服务端显示正常,客户端有时没显示子弹,有时显示的子弹运动路径诡异。由于时间关系,这部分暂时没处理,如果有解决方案的欢迎在评论区留言。

附言

  • 代码的传送门
  • 这次仅是自己的学习心得,想更好学习请移步到大神的博客。
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ke1950523491/article/details/80822213
个人分类: Unity3d学习
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭