当前位置: 首页 > news >正文

《Unity3D网络游戏实战》学习与实践--制作一款大乱斗游戏

角色类

基类Base Human是基础的角色类,它处理“操控角色”和“同步角色”的一些共有功能;CtrlHuman类代表“操控角色”​,它在BaseHuman类的基础上处理鼠标操控功能;SyncHuman类是“同步角色”类,它也继承自BaseHuman,并处理网络同步(如果有必要)​。

BaseHuman

        using System.Collections;using System.Collections.Generic;using UnityEngine;public class BaseHuman : MonoBehaviour {//是否正在移动protected bool isMoving = false;//移动目标点private Vector3 targetPosition;//移动速度public float speed = 1.2f;//动画组件private Animator animator;//描述public string desc = "";//移动到某处public void MoveTo(Vector3 pos){targetPosition = pos;isMoving = true;animator.SetBool("isMoving", true);}//移动Updatepublic void MoveUpdate(){if(isMoving == false) {return;}Vector3 pos = transform.position;transform.position = Vector3.MoveTowards(pos, targetPosition, speed*Time.deltaTime);transform.LookAt(targetPosition);if(Vector3.Distance(pos, targetPosition) < 0.05f){isMoving = false;animator.SetBool("isMoving", false);}}// Use this for initializationprotected void Start () {animator = GetComponent<Animator>();}// Update is called once per frameprotected void Update () {MoveUpdate();}}

CtrlHuman

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CtrlHuman : BaseHuman
{new void Start(){base.Start();}// Update is called once per framenew void Update(){base.Update();if(Input.GetMouseButtonDown(0)) {Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hit;Physics.Raycast(ray,out hit);if(hit.collider.tag == "Terrain") {MoveTo(hit.point);}}}
}

如何使用网络模块

在实际的网络游戏开发中,网络模块往往是作为一个底层模块用的,它应该和具体的游戏逻辑分开,而不应该把处理逻辑的代码写到 ReceiveCallback 里面去。因为ReceiveCallback应当只处理网络数据,不应该去处理游戏功能

一个可行的做法是,给网络管理类添加回调方法,当收到某种消息时就自动调用某个函数,这样便能够将游戏逻辑和底层模块分开。制作网络管理类前,需要先了解委托、协议和消息队列这三个概念。

通信协议

通信协议是通信双方对数据传送控制的一种约定,通信双方必须共同遵守,方能“知道对方在说什么”和“让对方听懂我的话”​。

使用一种最简单的字符串协议来实现。协议格式如下所示,消息名和消息体用“|”隔开,消息体中各个参数用“, ”隔开。

消息名|参数1, 参数2, 参数3, ...

Move|127.0.0.1:1234, 10, 0, 8,

处理数据:

        string str = "Move|127.0.0.1:1234, 10, 0,8, ";string[] args = str.Split('|');string msgName = args[0]; //协议名:Movestring msgBody = args[1]; //协议体:127.0.0.1:1234, 10, 0,8,string[] bodyArgs = msgBody.Split(', ');string desc = bodyArgs [0];               //玩家描述:127.0.0.1:1234float x = float.Parse(bodyArgs [1]);     //x坐标:10float y = float.Parse(bodyArgs [2]);     //y坐标:0float z = float.Parse(bodyArgs [3]);     //z坐标:8

消息队列

多线程消息处理虽然效率较高,但非主线程不能设置Unity3D组件,而且容易造成各种莫名其妙的混乱。由于单线程消息处理足以满足游戏客户端的需要,因此大部分游戏会使用消息队列让主线程去处理异步Socket接收到的消息。

C#的异步通信由线程池实现,不同的BeginReceive不一定在同一线程中执行。创建一个消息列表,每当收到消息便在列表末端添加数据,这个列表由主线程读取,它可以作为主线程和异步接收线程之间的桥梁。由于MonoBehaviour的Update方法在主线程中执行,可让Update方法每次从消息列表中读取几条信息并处理,处理后便在消息列表中删除它们

NetManager类

网络模块中最核心的地方是一个称为NetManager的静态类,这个类对外提供了三个最主要的接口。

  • Connect方法,调用后发起连接;
  • AddListener方法,消息监听。其他模块可以通过AddListener设置某个消息名对应的处理方法,当网络模块接收到这类消息时,就会回调处理方法;
  • Send方法,发送消息给服务端。

无论内部实现有多么复杂,网络模块对外的接口只有图片展示的这几个:

对内部而言,NetManager使用了异步Socket接收消息,每次接收到一条消息后,NetManager会把消息存入消息队列中​。NetManager有一个供外部调用的Update方法,每当调用它时就会处理消息队列里的第一条消息,然后根据协议名将消息分发给对应的回调函数

    using System.Collections;using System.Collections.Generic;using UnityEngine;using System.Net.Sockets;using UnityEngine.UI;using System;public static class NetManager {//定义套接字static Socket socket;//接收缓冲区static byte[] readBuff = new byte[1024];//委托类型public delegate void MsgListener(String str);//监听列表private static Dictionary<string, MsgListener> listeners =new Dictionary<string, MsgListener>();//消息列表static List<String> msgList = new List<string>();//添加监听public static void AddListener(string msgName, MsgListener listener){listeners[msgName] = listener;}//获取描述public static string GetDesc(){if(socket == null) return "";if(! socket.Connected) return "";return socket.LocalEndPoint.ToString();}//连接public static void Connect(string ip, int port){//Socketsocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);//Connect(用同步方式简化代码)socket.Connect(ip, port);//BeginReceivesocket.BeginReceive( readBuff, 0, 1024, 0,ReceiveCallback, socket);}//Receive回调private static void ReceiveCallback(IAsyncResult ar){try {Socket socket = (Socket) ar.AsyncState;int count = socket.EndReceive(ar);string recvStr =System.Text.Encoding.Default.GetString(readBuff, 0, count);msgList.Add(recvStr);socket.BeginReceive( readBuff, 0, 1024, 0,ReceiveCallback, socket);}catch (SocketException ex){Debug.Log("Socket Receive fail" + ex.ToString());}}//发送public static void Send(string sendStr){if(socket == null) return;if(! socket.Connected)return;byte[] sendBytes = System.Text.Encoding.Default.GetBytes(sendStr);socket.Send(sendBytes);}//Updatepublic static void Update(){if(msgList.Count <= 0)return;String msgStr = msgList[0];msgList.RemoveAt(0);string[] split = msgStr.Split('|');string msgName = split[0];string msgArgs = split[1];//监听回调;if(listeners.ContainsKey(msgName)){listeners[msgName](msgArgs);}}}

漏洞

上述代码没有处理粘包分包、线程冲突等问题

参考书籍:《Unity3D网络游戏实战(第2版)》 (豆瓣) (douban.com)

相关文章:

《Unity3D网络游戏实战》学习与实践--制作一款大乱斗游戏

角色类 基类Base Human是基础的角色类&#xff0c;它处理“操控角色”和“同步角色”的一些共有功能&#xff1b;CtrlHuman类代表“操控角色”​&#xff0c;它在BaseHuman类的基础上处理鼠标操控功能&#xff1b;SyncHuman类是“同步角色”类&#xff0c;它也继承自BaseHuman&…...

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《考虑源-荷不确定性的省间电力现货市场潮流风险概率评估》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…...

Pinterest 选择采用 TiDB

原文来源&#xff1a; https://tidb.net/blog/9f000c95 作者&#xff1a;Pinterest 公司高级软件工程师 Alberto Ordonez Pereira &#xff1b;高级工程经理 Lianghong Xu 声明&#xff1a;本文转载于 https://medium.com/pinterest-engineering/tidb-adoption-…...

【Python】 如何用 Docker 打包一个 Python 脚本

这是我父亲 日记里的文字 这是他的生命 留下留下来的散文诗 几十年后 我看着泪流不止 可我的父亲已经 老得像一个影子 &#x1f3b5; 许飞《父亲写的散文诗》 如何用 Docker 打包一个 Python 脚本 Docker 是一个开源的容器化平台&#xff0c;允许开发者将…...

从“幕后”到“台前”:一文读懂API经济如何促进企业的创新与增长

API&#xff08;Application Programming Interface&#xff0c;应用程序接口&#xff09;指一组定义软件程序如何与其他组件、服务或系统交互的规范。在传统的IT语境中&#xff0c;API往往更多承担前后端对接或应用系统间内部集成渠道的作用。但在当今大数据与智能化的时代&am…...

解锁PDF新姿势:2024年PDF转图片工具精选

随着数字化办公的普及和文档处理需求的日益增长&#xff0c;PDF转图片工具已成为日常工作中不可或缺的一部分。这些工具不仅帮助用户轻松地将PDF文件转换为图片格式&#xff0c;还提供了丰富的编辑、转换和批量处理功能&#xff0c;极大地提高了工作效率。 1.福昕PDF转换大师&…...

Node.js(8)——Express的基本使用

监听GET请求 通过app.get()方法&#xff0c;可以监听客户端GET请求&#xff0c;具体语法&#xff1a; app.get(请求URL,function(req,res){处理函数}) 监听POST请求 语法&#xff1a; app.post(请求URL,function(req,res){处理函数}) 把内容响应给客户端 通过res.send()方法…...

Linux--应用层协议HTTP

HTTP协议 HTTP协议&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;是互联网上应用最为广泛的一种网络协议&#xff0c;它基于TCP/IP通信协议来传送数据&#xff0c;规定了浏览器与服务器之间数据传输的规则&#xff0c;确保数据能够在网络源头…...

Flux:Midjourney的新图像模型挑战者

--->更多内容&#xff0c;请移步“鲁班秘笈”&#xff01;&#xff01;<--- Black Forest Labs是一家由前Stability.ai开发人员创立的AI初创公司&#xff0c;旨在为图像和视频创建尖端的生成式 AI 模型。这家初创公司声称&#xff0c;其第一个模型系列Flux.1为文本到图像…...

RabbitMQ高级特性 - 消费者消息确认机制

文章目录 RabbitMQ 消息确认机制背景消费者消息确认机制概述手动确认&#xff08;RabbitMQ 原生 SDK&#xff09;手动确认&#xff08;Spring-AMQP 封装 RabbitMQ SDK&#xff09;AcknowledgeMode.NONEAcknowledgeMode.AUTO&#xff08;默认&#xff09;AcknowledgeMode.MANUAL…...

PermX-htb

0x01 立足 信息收集 端口扫描 nmap -sSCV -Pn 10.10.11.23 正常开启22和80端口 访问web页面 并没有看到有攻击点 这个页面可先记录一会儿有需要的话可以尝试xss获取cookie 域名扫描 ffuf -w 1.txt -u http://permx.htb/ -H Host:FUZZ.permx.htb 这里用的ffuf扫描工具 扫出了…...

解密RCE漏洞:原理剖析、复现与代码审计实战

在网络安全领域&#xff0c;远程代码执行&#xff08;RCE&#xff09;漏洞因其严重性和破坏力而备受关注。RCE漏洞允许攻击者在目标系统上执行任意代码&#xff0c;从而掌控整个系统&#xff0c;带来极大的安全风险。理解RCE漏洞的工作原理&#xff0c;并掌握其复现与代码审计技…...

打造智能家居:用React、Node.js和WebSocket构建ESP32设备控制面板(代码说明)

一、项目概述 在物联网&#xff08;IoT&#xff09;时代&#xff0c;智能设备的远程控制变得越来越重要。本文介绍了一个构建智能设备控制面板的项目&#xff0c;允许用户通过 Web 应用来控制多个 ESP32 设备。用户可以通过该面板查看设备列表&#xff0c;实时了解设备状态&am…...

计网:从输入URL到网页显示期间发生了什么

1、URL包含的信息 我们输入的url中包含着一些信息&#xff1a; http&#xff1a;表示的此次我们使用的什么协议/www.baidu.com&#xff1a;表示的是我们想要访问的服务器名称&#xff0c;也就是域名dir3/home.html&#xff1a;表示我们所要访问的资源 2、通过DNS解析URL获得I…...

龚宇引以为傲的“爆款制造营”,爱奇艺怕是要爽约了

文&#xff1a;互联网江湖 作者&#xff1a;刘致呈 人们经常用人红戏不红&#xff0c;来形容毯星&#xff0c;综艺上咋咋呼呼&#xff0c;一提都知道&#xff0c;可问及代表作&#xff0c;不好意思&#xff0c;这个真没有。 今年的爱奇艺&#xff0c;貌似也迎来了这一宿命。 …...

org.springframework.web.client.HttpClientErrorException$NotFound异常

springCloud报错信息&#xff1a;org.springframework.web.client.HttpClientErrorException$NotFound: 404 null第一点&#xff1a; 第二点&#xff1a;没有httpclient工具类 注入RestTmeplate类时&#xff0c;改类需要RestController或ResponseBody...

在开关电源转换器中充分利用碳化硅器件的性能优势

在过去的几十年中&#xff0c;半导体行业已经采取了许多措施来改善基于硅 MOSFET &#xff08;parasitic parameters&#xff09;&#xff0c;以满足开关转换器(开关电源)设计人员的需求。行业效率標準以及市场对效率技术需求的双重作用&#xff0c;导致了对于可用于构建更高效…...

QObject::connect: Cannot queue arguments of type ‘QList<QString>‘

QObject::connect: Cannot queue arguments of type ‘QList’ QObject::connect: Cannot queue arguments of type QList<QString> (Make sure QList<QString> is registered using qRegisterMetaType().)使用信号和槽时&#xff0c;QList无法当做参数被传递&…...

基于K8S部署安装Jenkins

基于K8S部署安装Jenkins 1.Jenkins Kubernetes 清单文件2.Kubernetes Jenkins 部署1&#xff1a;为 Jenkins 创建 Namespace。 最好将所有DevOps工具分类为与其他应用程序分开的命名空间。2&#xff1a;创建“serviceAccount.yaml”文件并复制以下管理员服务帐户清单。1. kubec…...

24-8-4-读书笔记(十三)-《莎士比亚全集》(第一卷(续)) [英] 威廉·莎士比亚 [译]朱生豪

文章目录 《莎士比亚全集》(第一卷(续))目录阅读笔记记录总结《莎士比亚全集》(第一卷(续)) 《莎士比亚全集》朱生豪的经典译本,非常值得花时间去读一读,莎氏的巨作有其独特的韵味,与莫里哀、契诃夫、曹禺等其他国家的剧作家有其鲜明的特点,这既是源于其所处的时代…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比

目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec&#xff1f; IPsec VPN 5.1 IPsec传输模式&#xff08;Transport Mode&#xff09; 5.2 IPsec隧道模式&#xff08;Tunne…...

docker 部署发现spring.profiles.active 问题

报错&#xff1a; org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)

引言 在人工智能飞速发展的今天&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;已成为技术领域的焦点。从智能写作到代码生成&#xff0c;LLM 的应用场景不断扩展&#xff0c;深刻改变了我们的工作和生活方式。然而&#xff0c;理解这些模型的内部…...

渗透实战PortSwigger靶场:lab13存储型DOM XSS详解

进来是需要留言的&#xff0c;先用做简单的 html 标签测试 发现面的</h1>不见了 数据包中找到了一个loadCommentsWithVulnerableEscapeHtml.js 他是把用户输入的<>进行 html 编码&#xff0c;输入的<>当成字符串处理回显到页面中&#xff0c;看来只是把用户输…...

VisualXML全新升级 | 新增数据库编辑功能

VisualXML是一个功能强大的网络总线设计工具&#xff0c;专注于简化汽车电子系统中复杂的网络数据设计操作。它支持多种主流总线网络格式的数据编辑&#xff08;如DBC、LDF、ARXML、HEX等&#xff09;&#xff0c;并能够基于Excel表格的方式生成和转换多种数据库文件。由此&…...

C++_哈希表

本篇文章是对C学习的哈希表部分的学习分享 相信一定会对你有所帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、基础概念 1. 哈希核心思想&#xff1a; 哈希函数的作用&#xff1a;通过此函数建立一个Key与存储位置之间的映射关系。理想目标&#xff1a;实现…...