Unity3D笔记——解决Unity官方《Tanks》同时启动会创建两个服务器问题

Unity3d实现双人网络坦克大战 2222 阅读详情

前言:Unity3D笔记是我平时做一些好玩的测试和研究,记录的笔记。会比较详细也可能随口一提就过了。 所以大家见谅了,内容一般都会是原创的(非原创我会注明转载)。由于很多内容其他的朋友也肯定研究发表过,大家请指出错误。

       公司一个同事在用Unet的时候,是参考unity 的官方教程《Tanks》的。然后发现一个小问题:在局域网中,当两台电脑同时按下(接近的时间按下)play的时候,会一起检测局域网是否有服务器去加入。然后 都检测不到;于是就各自创建了服务器。没有在一个游戏中;

于是呢,考虑了下;我觉得造成该问题的原因是:游戏打开的时间接近,没有办法判断谁创建服务器,谁是客户端;导致互相都创建的问题;直觉告诉我,可以用UDP的广播实现问题:1.开始游戏,全网监听固定端口(5555)发来的消息(是否有服务器了)2.如果有则加入;3.如果1秒后没有收到,则自己广播信号出去(我要创建服务器);4.创建服务器;

用到了之前的一些代码;我改了下

直接上代码:UDP的全网接受和发送

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Net;
using System.Net.Sockets;
using UnityEngine.UI;

namespace ImmerUDP
{

    public class GameUdpManager :MonoBehaviour
    {
        [Header("本地端口"),SerializeField]
        private int sendPort = 6666;

        [Header("目标端口"), SerializeField]
        private int receivePort = 8888;


        //服务器端Scoket对象;
        private Socket serverSocket;

        //udp客户端socket
        private UdpClient client;

        private EndPoint epSender;

        private IPEndPoint endpoint;

        //接受数据的字符数组
        private byte[] ReceiveData = new byte[1024];

        public static GameUdpManager Instance;

        private void Awake()
        {
            Instance = this;
        }


        public void StartUdpWork(int sendPort,int recevie)
        {
            this.sendPort = sendPort;
            this.receivePort = recevie;

            StartUdpReceive();

            OpenSendSocket();

        }


        /// <summary>
        /// 开启接受的Socket 并开始异步接受
        /// </summary>
        public void StartUdpReceive()
        {
            //服务器Socket对象实例化
            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

            //Socket对象跟服务器端的IP和端口绑定 
            serverSocket.Bind(new IPEndPoint(IPAddress.Any, receivePort));

            //监听的端口和地址
            epSender = (EndPoint)new IPEndPoint(IPAddress.Parse("255.255.255.255"), sendPort);

            //开始异步接受数据
            serverSocket.BeginReceiveFrom(ReceiveData, 0, ReceiveData.Length, SocketFlags.None, ref epSender, new AsyncCallback(ReceiveFromClients), epSender);

        }


        /// <summary>
        /// 开启发送的Socket
        /// </summary>
        public void OpenSendSocket()
        {
            client = new UdpClient(new IPEndPoint(IPAddress.Any, sendPort));

            //目标端口和地址
            endpoint = new IPEndPoint(IPAddress.Parse("255.255.255.255"), receivePort);
        }




        /// <summary>
        /// 异步接受,处理数据
        /// </summary>
        /// <param name="iar"></param>
        private void ReceiveFromClients(IAsyncResult iar)
        {
            int reve = serverSocket.EndReceiveFrom(iar, ref epSender);

            //数据处理
            string str = System.Text.Encoding.UTF8.GetString(ReceiveData, 0, reve);

            //Debug.Log(str);

            //把得到数据传给数据处理中心
            NetworkDataHandler.Instance.NetworkDataUpdate(str);

            serverSocket.BeginReceiveFrom(ReceiveData, 0, ReceiveData.Length, SocketFlags.None, ref epSender, new AsyncCallback(ReceiveFromClients), epSender);

        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="dataStr">str 数据</param>
        public void Send(string dataStr)
        {
          

            byte[] SendData = System.Text.Encoding.UTF8.GetBytes(dataStr);

            client.Send(SendData, SendData.Length, endpoint);
        }

    }
}

说明:这边的UDP有这两个socket:分别是发送和接受;发送是向6666端口全网广播的;接受是:全网接受5555端口的;

消息处理中心:


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class NetworkDataHandler : MonoBehaviour {

    public static NetworkDataHandler Instance;

    public delegate void VoidEvent();

    //注册对应的事件
    public event VoidEvent serverOpenEvent;


    bool isDataUpdate = false;

    public string data="";

    private void Awake()
    {
        Instance = this;
    }

    // Use this for initialization
    void Start () {

	}

    private void Update()
    {
        if (!isDataUpdate) return;

        isDataUpdate = false;

    }

    public void NetworkDataUpdate(string data) {     

        this.data = data;

       // Debug.Log(data);

        if (data.Contains("ServerIsOpen"))
        {

            if (serverOpenEvent != null)
                serverOpenEvent();
        }

    }
}

执行脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class demo5 : MonoBehaviour {

    public static bool isHasServer=false;

    bool isSendMessage = false;

    private void Awake()
    {
       
    }

    // Use this for initialization
    void Start () {
        Invoke("startServer", 1f);

        NetworkDataHandler.Instance.serverOpenEvent += openClient;

        ImmerUDP.GameUdpManager.Instance.StartUdpWork(5555,6666);

      
    }

    private void Update()
    {
       if(isSendMessage)
        ImmerUDP.GameUdpManager.Instance.Send("ServerIsOpen");
    }

    void startServer()
    {
        if (isHasServer) return;

        isSendMessage = true;
    }


    void openClient()
    {
        if (isHasServer) return;

        if (isSendMessage == true)
        {
            Debug.Log("本机是服务器,不用去开始客户端");
            return;
        }

        isHasServer = true;

    }
}

说明:执行脚本的作用就是通过广播判断下:局域网中是否有服务器了;没呢:广播信息告诉大家,这边会创建服务器;

然后是《Tanks》中局域网开始游戏代码更改:

   public IEnumerator DiscoverNetwork()
        {

            yield return new WaitForSeconds(1);

            NetworkDiscoveryCustom discovery = GetComponent<NetworkDiscoveryCustom>();
            discovery.Initialize();

            print(demo5.isHasServer);

            if (demo5.isHasServer)
            {
                discovery.StartAsClient();
            }
            else
            {
                yield return new WaitForSeconds(0.5f);
                //NetworkDiscoveryCustom discovery2 = GetComponent<NetworkDiscoveryCustom>();
                discovery.StartAsServer();
                StartHost();
            }

            //////start listening to other hosts
            //NetworkDiscoveryCustom discovery = GetComponent<NetworkDiscoveryCustom>();
            //discovery.Initialize();
            //discovery.StartAsClient();

            ////wait few seconds for broadcasts to arrive
            //yield return new WaitForSeconds(8);

            ////we haven't found a match, open our own
            //if (discovery.running)
            //{
            //    discovery.StopBroadcast();
            //    yield return new WaitForSeconds(0.5f);

            //    discovery.StartAsServer();
            //    StartHost();
            //}
        }

说明:这是《Tanks》中NetworkManagerCustom.cs中一段;主要功能是实现局域网的寻找服务器和搭建服务器; 我改了下:

如果之前广播结果是:有服务器了,那么就直接去连接;如果是没有服务器,那么本地创建服务器;


东西不多,也算是一种应用啦。希望对大家有帮助;


Unity3D游戏开发案例学习——Tanks!(基本完结) 【2020.1.12】 概述 本案例来自unity官方中级游戏教程Tanks(单机双人坦克大战) 第一部分:场景设置 阅读详情

相关推荐

【Unity3D-Mirror多人坦克大战】基础配置、场景生成和房间机制(一)

基础配置、场景生成和房间机制

Lomiss的博客 5107

Tank!networking DEMO Unity3D项目

1.新建工程,导入资源,新建Scenes文件夹,保存该场景进该文件夹 2.删除场景中的默认灯光 2.1 再把Prefab里的LevelArt预设场景拖到Hierarchy中 2.2选择window-&gt;lighting 打开光照窗口,取消勾选下面的Auto(自动渲染),取消勾选BakeGI,把RealtimeResoulution改为0.5,在把上面的AmbientSource改为color,...

Batman1208的博客 1096

【实战】Unity3d实战之Unity3d网络游戏实战篇(1):坦克构建

Unity3d实战之Unity3d网络游戏实战篇(1):坦克构建 阅读文章前请细读以下几点: 学习书籍《Unity3d网络游戏实战》 罗培羽著 机械工业出版。 本文是作者在学习过程中遇到的认为值得记录的点,因此引用的代码等资源基本出资罗培羽老师的书籍 以下为个人的学习简记,与诸君共论。 由于U3D的官方案例Tank Tutorial中对坦克的基本操作已经有了详尽的描述(其...

Rioer的博客 3279

【游戏开发实战】Unity使用Socket通信实现简单的多人聊天室(万字详解 | 网络 | TCP | 通信 | Mirror | Networking)

教你Unity使用Socket通信实现简单的多人聊天室(网络 | TCP | 通信 | Mirror | Networking)

linxinfa的专栏 1万+

NetworkDiscovery:测试网络发现

网络发现 适用于 Android 设备的机器发现/映射(通过 Wifi)和端口扫描(通过 3G/Wifi)实用程序。 特征 发现 LAN 上的机器(连接/ping 发现、dns 发现) TCP 端口扫描器(connect() 扫描) 网卡供应商数据库 以 XML 格式将结果导出到您的 SD 卡 快速访问 Wifi 设置 自适应扫描速率(慢启动,然后自适应网络延迟) 开源,可在 建造 git clone https://github.com/rorist/android-network-discovery.git cd android-network-discovery; cp local.properties-example local.properties vim local.properties #add path to the Android SDK ant debug in

转载神启unity3d项目完整版本(服务器,客户端,工具,文档)

神启 unity3d项目完整版本(服务器,客户端,工具,文档)

Unity3d Network 局域网多人对战之游戏大厅

本文是通过在局域网内进行玩家匹配,需要游戏大厅展示局域网内的服务器列表(房间信息),玩家通过点击列表进入服务器创建的房间,准备好后开始游戏。

yxl219的专栏 3777

HybridCLR热更新打包报错全解析:从原理到实战解决方案

热更新技术是现代游戏和应用开发中实现动态内容交付与Bug修复的核心机制,它允许开发者在无需重新发布完整应用的情况下更新代码逻辑。其原理通常涉及在运行时加载并执行新的代码模块,这要求框架在底层实现安全的代码隔离、内存管理与元数据桥接。在Unity生态中,HybridCLR作为基于IL2CPP的高性能热更新解决方案,通过补充元数据和AOT泛型引用技术,实现了对C#代码的原生级热更支持,显著提升了开发迭代效率与线上问题修复能力。然而,在实际的工程实践中,尤其是在面向Android、iOS等多平台打包构建时,开发者

weixin_29017445的博客 308

一些值得学习的Unity教程

***********************项目源码******************************** 1. 降临 2. 沉睡缤纷乐 3. 千炮捕鱼 4. Photon官方FSP示例 5. 末日战歌 6. 热血军团 天天萌泡泡 源码都分享在群里:375151422*****************************Git开

学无止境的专栏 2万+

Unity游戏开发:从零开始适配Nintendo Switch的完整指南

本文详细介绍了如何使用Unity进行Nintendo Switch游戏开发的完整流程,包括开发环境搭建、Unity工程适配、手柄与硬件特性开发、存储与性能优化等关键步骤。特别强调了Switch SDK的配置、输入系统改造和内存优化技巧,帮助开发者高效完成跨平台适配。

vodka的博客 1066

【5G全网建设】Option3X和Option2模式建安市、兴城市和四水市核心网、承载网网络设计与部署

拓扑规划: Option 3X网络拓扑图规划 Option 2网络拓扑图规划 设备部署: 建安市核心网 建安市承载中心机房 建安市骨干汇聚机房 建安市3区汇聚机房 建安市C站点无线机房 兴城市核心网 兴城市承载中心机房 兴城市骨干汇聚机房 兴城市2区汇聚机房 兴城市B站点无线机房 数据配置: 建安市核心网 建安市承载中心机房 建安市骨干汇聚机房 建安市3区汇聚机房 建安市C站点无线机房 兴城市核心网 兴城市承载中心机房 兴城市骨干汇聚机房 兴城市2区汇聚机房 兴城市B站点无线机房 业务调试

weixin_67183034的博客 8850

一些值得学习的Unity教程 (很实用的包括源码)

*****************************Git开源项目*******************************1.https://git.oschina.net/dingxiaowei/TANKS.git2.SCUT  https://github.com/ScutGame/Scut/wiki3.TTUIFramework https://github.com/chiuan...

chenxupest的专栏 9078

2.实体机安装TrueNAS 方法

访问不了可以使用以下连接:提取码:0927。

Unofficial_user的博客 7429

不错的Unity教程

***********************项目源码********************************  1. 降临    2. 沉睡缤纷乐    3. 千炮捕鱼    4. Photon官方FSP示例    5. 末日战歌    6. 热血军团  天天萌泡泡  源码都分享在群里:375151422 *****************

feizhu003的博客 1404

C++/WinRT入门指南:现代Windows原生开发的核心技术

Windows运行时(WinRT)是微软为现代Windows应用开发设计的一套跨语言API框架,它基于COM技术原理构建,提供了统一的二进制接口标准。这项技术的核心价值在于让开发者能够以原生性能调用系统级功能,同时保持跨语言兼容性。在工程实践中,C++/WinRT作为官方推荐的C++语言投影,通过标准C++语法封装WinRT API,显著降低了开发复杂度。特别是在异步编程场景中,结合C++20协程特性,能够大幅提升代码可读性和维护性。对于需要高性能图形处理、系统集成或跨平台兼容的桌面应用开发,掌握C++/W

weixin_33910191的博客 1196

电力现货市场出清机制解析:从理论到实践(附节点电价计算实例)

本文深入解析电力现货市场的核心出清机制,重点阐述了节点边际电价的计算原理与实践方法。通过对比系统边际电价、节点边际电价和分区边际电价三种模式,揭示了市场出清价格如何反映电力供需与网络阻塞。文章结合IEEE 30节点系统,提供了基于MATLAB和最优潮流模型的计算实例,详细展示了从构建模型到求解对偶变量以获取节点电价的全过程,为理解电力市场定价机制提供了从理论到实践的完整路径。

whisky的博客 755

Unity学习资料收集

***********************项目源码******************************** 1. 降临 2. 沉睡缤纷乐 3. 千炮捕鱼 4. Photon官方FSP示例 5. 末日战歌 6. 热血军团 天天萌泡泡 源码都分享在群里:375151422 *****************************Git开源项目*********************...

hfush的博客 2156

存储硬盘格式怎么把512还原为520格式??

硬盘厂商工具(如SeaChestsg_format)可以调整扇区大小。备份数据,因为调整扇区会清除硬盘内容。根据硬盘型号和接口类型,选择合适的工具进行调整。如果你需要更详细的帮助,请提供你的硬盘型号和存储设备类型。希望如上措施及解决方案能够帮到有需要的你。PS:如若遇到采纳如下方案还是未解决的同学,希望不要抱怨&&急躁,毕竟影响因素众多,我写出来也是希望能够尽最大努力帮助到同类似问题的小伙伴,即把你未解决或者产生新Bug黏贴在评论区,我们大家一起来努力,一起帮你看看,可以不咯。

**My Coding Family** 1142

Unity官方案例篇:Tanks Tutorial全解读(Tank移动)

PS:除了需要注意和重点学习的地方,其他过于基础的我不再赘述。(因为注释实在太详细了啊,魂淡!)史诗级注释了解一下? 我们先来看Tank的移动控制脚本。 遍历得到粒子系统子物体并播放 利用玩家的标识来决定操纵者的按键。 我们可以按下图顺序来查看Input Setting,并且可以根据自己的需求来更改。 然后是坦克位置的改变。通过刚体来插值更新位置。 ...

设计师养成记 1725

MTK-Android12开机应用自启需求-自定义原生Launcher3 主界面布局图标

MTK平台 Android12 版本 上实现 开机应用自启需求-自定义原生Launcher3 主界面布局图标。添加一个属性定义即可,如下:这里自定义一个属性目的是为了在加载Launcher3启动时候从属性获取需要自启动应用的包名,可以扩展动态替换 自启动包名。这里有两种方案,要么在Launcher3里面实现,要么在系统服务里面在开机时候启动第三方一次。这里强烈建议在Launcher3中去实现,体验效果更好。// 第一步:定义属性,// 第二步:在onCreate 方法中获取属性并启动应用。

十年饮冰,难凉热血 1374

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Unity入门案例-Tanks坦克大战

这是我的第一个Unity项目精简版的坦克大战看着siki视频学着做的历时一天半。 游戏描述: 游戏由2个玩家控制,每个玩家可以控制坦克前进后退左转右转和攻击,每个玩家有100hp基础血量每次攻击随机造成10-20点伤害。当某个玩家血量低于0时他操控的坦克被摧毁并且游戏结束。 我的工作: 一、坦克的移动脚本 using System.Collections; using System.Co

MY Blog 1万+

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

《Unity入门案例-Tanks坦克大战》1-准备工作

0.案例介绍 0.1开始界面 点击Play Now 进入游戏界面 左边的坦克使用ws控制前后移动,ad键左右旋转,空格键开火 右边的坦克使用方向键上下控制前后移动,方向键左右键实现左右旋转,enter键开火 1.准备工作 本案例需要unity5.2以上版本. 素材为Tanks Tutorial.unitypackage 1.1新建3d项目 点击unity右上角...

杜增强的博客 2794

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

[Unity Mirror] Network Discovery

英文原文: https://mirror-networking.gitbook.io/docs/components/network-discovery   假设你在一个朋友旁边。他以主持人模式开始游戏,而您想加入他。你的手机将如何定位他的?找出他的 IP 地址并不是很直观,也不是孩子们可以做的事情。   要解决此问题,您可以使用Network Discovery。当您的游戏开始时,它会在您当前的网络中发送一条消息,询问“是否有可用的服务器?”。同一网络内的任何服务器都会回复并提供有关如何连接到它的信息

unity尧明的博客 1935
上一篇: Unity3D笔记——TCP简单服务器和客户端的连接和异步接受
下一篇: Unity3D笔记——Socket粘包分包的理解和最简单的处理方式
YYL_Debug
博客等级 码龄10年 14粉丝 8原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值