网络游戏同步:状态同步核心原理剖析

news2025/1/25 9:14:44

状态同步是做网络游戏必然要掌握的一种服务端/客户端同步技术。什么是状态同步,具体到游戏中是如何实现的,带着这些问题本文将会从以下3个方面給大家详细的剖析状态同步。

对啦!这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础小白,也有一些正在从事游戏开发的技术大佬,欢迎你来交流学习。

什么样的游戏选择用状态同步

只要是网络游戏,涉及到服务器与客户端同步的游戏,都可以使用状态同步,举几个状态同步的例子,如《魔兽世界》,腾讯《吃鸡》,《自走棋》等大部分的多人在线的网络游戏都是用状态同步来做的,换句话说网络游戏中除了少数人对战(5v5, 10v10)的Moba类,FPS类等会用帧同步以外,其它的都是状态同步。像大型多人同时在线的游戏,只能用状态同步来做。目前主流的网络同步方式是状态同步与帧同步,状态同步可以做任意类型的游戏,帧同步只能做少数几个人在一局同时对战的短时间的网络游戏。一个游戏是否考虑使用状态同步的理由就在于你的游戏

帧同步与状态同步相比,帧同步只同步用户操作,由客户端迭代计算所有的游戏逻辑,更像是做单机游戏,只是有些玩家的输入是来自服务器而已。帧同步在操作手感,玩家的响应时间上,会比状态同步做的更出色。但是也有它的问题,比如防作弊,断线重连需要从头运算一帧帧快速迭代。这就限制了帧同步能做的游戏类型非常有限,不能做大量人同时在线或长时间在线的游戏。比如MMORPG,单服5000人同时在线,这种你做帧同步,客户端要迭代5000个玩家物体的每帧的计算,同时长期在线,比如MMORPG游戏服务已经跑了一个月了,新进来的用户,如

服务器上如何跑游戏逻辑

状态同步的一个核心是把整个游戏的所有数据与逻辑都跑到服务器上。这种咋一听感觉很难,其实也就是像写客户端一样,跑一个update的帧频率来进行迭代(一般1秒15~20次迭代,或者动态调整)。和客户端一样,每个游戏的

public class PlayerEntity {
	
	@Protobuf(order = 1, required = true)
	public StatusComponent statusInfo; // 玩家的状态;
	
	@Protobuf(order = 2, required = true)
	public AccountComponent accountInfo;
	
	@Protobuf(order = 3, required = true)
	public GhostPlayerInfoComponent ghostInfo;
	
	@Protobuf(order = 4, required = true)
	public EquipmentComponent equipmentInfo;
	
	@Protobuf(order = 5, required = true)
	public TransformComponent transformInfo;
	
	// 玩家私密的数据是不必要的;
	@Protobuf(order = 6, required = false)   
	public PrivatePlayerInfoComponent playerInfo;
	
	public AOIComponent aoiComponent;
	public SkillBuffComponent skillBuffComponent;
	
	public AttackComponent attackComponent;
	public ShapeComponent shapeInfo;
	public AStarComponent astarComponent;
	public JoystickComponent joystickComponent;
	
	public PlayerEntity() {
		this.accountInfo = null;
		this.playerInfo = null;
		this.ghostInfo = null;
		this.equipmentInfo = null;
		this.shapeInfo = null;
		this.transformInfo = null;
		this.astarComponent = null;
		this.joystickComponent = null;
		this.attackComponent = null;
		this.skillBuffComponent = null;
		this.statusInfo = null;
	}
	
	
	public static PlayerEntity create(Player p) {
		PlayerEntity entity = new PlayerEntity();
		entity.statusInfo = new StatusComponent();
		entity.statusInfo.state = RoleState.Idle;
		
		entity.accountInfo = new AccountComponent();
		entity.playerInfo = new PrivatePlayerInfoComponent();
		entity.ghostInfo = new GhostPlayerInfoComponent();
		entity.equipmentInfo = new EquipmentComponent();
		entity.shapeInfo = new ShapeComponent();
		entity.transformInfo = new TransformComponent();
		entity.aoiComponent = new AOIComponent();
		
		SkillBuffSystem.InitSkilBuffComponent(entity);
		
		entity.astarComponent = new AStarComponent();
		entity.joystickComponent = new JoystickComponent();
		entity.attackComponent = new AttackComponent();
		
		entity.statusInfo.entityId = p.getId();
		LoginMgr.getInstance().loadAccountComponentFromAccountId(entity.accountInfo, p.getAccountId());
		PlayerMgr.getInstance().loadPlayerEntityFromPlayer(entity, p);
		PlayerMgr.getInstance().loadEquipMentComponentDataFromPlayer(entity.equipmentInfo, p);
		
		entity.shapeInfo.height = 2.0f;
		entity.shapeInfo.R = 0.5f;
		
		
		return entity;
	}
	
}
比如上面的TransformComponent, 描述的就是这个游戏对象在世界中的位置,旋转。
public class TransformComponent {
	@Protobuf(order = 1, required = true)
	public Vector3Component position;
	
	@Protobuf(order = 2, required = true)
	public float eulerAngleY = 0;
	
	
	public TransformComponent clone() {
		TransformComponent t = new TransformComponent();
		t.position = this.position.clone();
		t.eulerAngleY = this.eulerAngleY;
		return t;
	}
	
	public void LookAt(Vector3Component point) {
		Vector3Component src = this.position;
		Vector3Component dir = Vector3Component.sub(point, src);
		float degree = (float)(Math.atan2(dir.z, dir.x) * 180 / Math.PI);
		degree = 360 - degree;
		this.eulerAngleY = degree + 90;
	}
}

当创建一个玩家登录到逻辑服的时候,服务器中的3D世界就会创建一个这样的数据对象。接下来就要尝试让这个对象在游戏世界中跑动交互起来,服务端的地图如何做呢?其实地图数据可以导出为地形高度图(x, y, z)+道路连通数据(哪些是可以行走,哪些不可以行走)。这个对团队的技术积累是有一点要求的。根据游戏不同的类型来做地图编辑器,来采用最合适的技术。同时客户端+服务端都要使用这套,客户端有地图编辑器工具编辑地图的地形+烘焙地图连通数据,能将这些数据按照对应的格式导出給服务端用,服务端使用这些数据利用上面的Update来进行迭代计算(和客户端开发的Update迭代是一样的)。

服务端与客户端如何同步

服务器上架起了游戏地图,在服务端Update的迭代之下,让一个个的玩家数据+NPC数据等在服务端”跑起来”,接下来是如何与客户端同步。状态同步是不是服务器上位置变换了,客户端的位置就要同步一次呢?其实不是或者说不全是,我们会把游戏中的重要变化,描述成”状态变化”。状态同步你记住很重要的一条: 服务端跑服务端的,客户端跑客户端的,每次状态发生变化了,要处理之前先同步。

接下来我们通过具体的例子来解释一下这句话。我们拿客户端在地图上点击p点,然后寻路导航到p点。这个过程来讲解状态同步。

Step1:当客户端玩家A用鼠标或者触摸在地图上点了一下以后,就把目的的地图坐标,和操作事件(类型标识)发送給服务端。

Step4: 服务端走服务端的,迭代玩家A的数据对象在寻路+导航的作用下每次Update更新A的位置。注意,服务端走服务端的,这个过程不会同步給客户端了

Step5: 客户端收到玩家A要行走到P点的事件,对于A来说状态改变了,先同步,同步数据包中服务器上玩家A的最新状态信息,同步后再做本地寻路导航行走到p点, 客户端跑客户端的。

Step6: 服务端上玩家A走到了目的地,这个时候玩家A的状态变化了,服务端把这个状态事件,发送給对玩家A感兴趣的所有玩家包括A自己。

Step7: 客户端收到玩家A到达目的地的状态事件后,就同步一下数据包中服务端上玩家A的状态信息。

由上面得到的结论就是,行走过程中位置的变化,没有必要同步到客户端,服务端跑服务端的,客户端跑客户端的,只是重要状态变化后,服务端把最新的信息发送給客户端,客户端同步。在上面的例子中,玩家在行走中,玩家又有其它的攻击操作了,那么又是状态变化了,服务端又会在处理这个攻击事件的时候带上最新状态信息,客户端同步状态信息,然后再进行攻击(播放攻击动画,怪物掉血动画),服务器上也在做攻击,攻击完成后同步最新的状态与血量即可。状态同步的核心就是:处理每种状态和事件之前,先同步,然后再服务端计算服务端的,客户端做客户端的。直到有新的状态出来,先同步,再处理。

好今天的状态同步就分享到这里,关注我们学习更多的网络游戏实战系列教程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/894571.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【正点原子STM32连载】第十三章 按键输入实验 摘自【正点原子】APM32F407最小系统板使用指南

1)实验平台:正点原子stm32f103战舰开发板V4 2)平台购买地址:https://detail.tmall.com/item.htm?id609294757420 3)全套实验源码手册视频下载地址: http://www.openedv.com/thread-340252-1-1.html# 第十…

高忆管理:低位缩量上涨说明什么?

在股票商场中,股票价格在低位缩量上涨是一种常见的走势。那么,低位缩量上涨究竟阐明了什么?本篇文章将从多个角度剖析,并给出全文摘要和3个关键词。 一、什么是低位缩量上涨? 低位缩量上涨是指股票价格在前期低点的邻…

jenkins同一jar包部署到多台服务器

文章目录 安装插件配置ssh服务构建完成后执行 没有部署过可以跟这个下面的步骤先部署一遍,我这篇主要讲jenkins同一jar包部署到多台服务器 【Jenkins】部署Springboot项目https://blog.csdn.net/qq_39017153/article/details/131901613 安装插件 Publish Over SSH 这…

angular中如何定义一个全局组件?

需求,我们需要新建一个navBreadcrumb的全局组件。这是一个面包屑导航,在不同的页面引入时传入一个路由数组即可。 第一步:我们新建这个组件: ng g c navBreadcrumb ng g m navBreadcrumb----------nav-breadcrumb.module-------…

文件和目录的基础操作

cat命令 concatenate(连接)的缩写,即 combine pieces together 1)把碎片组合在一起(意味着可以使用cat创建一个小文件) 2)显示文件 ──(root㉿kali)-[~] └─# cat /etc/resolv.conf # Generated by NetworkManager…

数字孪生和SCADA有哪些区别?

虽然SCADA和数字孪生用于工业领域,但它们有不同的用途。SCADA专注于工业过程的实时监测和控制,而数字孪生用于模拟和分析系统的性能。接下来,让我们详细讨论SCADA和数字孪生(SCADA与数字孪生)之间的区别。 SCADA与数字…

Python Opencv实践 - 图像仿射变换

import cv2 as cv import numpy as np import matplotlib.pyplot as pltimg cv.imread("../SampleImages/pomeranian.png", cv.IMREAD_COLOR) rows,cols img.shape[:2] print(img.shape[:2])#使用getAffineTransform来获得仿射变换的矩阵M #cv.getAffineTransform(…

Java项目-苍穹外卖-Day04

公共字段自动填充 这些字段在每张表基本都有,手动进行填充效率低,且后期维护更改繁琐 使用到注解AOP主要 先答应一个AutoFill注解 再定义一个切面类进行通知 对应代码 用到了枚举类和反射 package com.sky.aspect; /*** 自定义切面类&#xff0c…

信创办公–基于WPS的EXCEL最佳实践系列 (公式和函数)

信创办公–基于WPS的EXCEL最佳实践系列 (公式和函数) 目录 应用背景相关知识操作步骤1、认识基本的初级函数2、相对引用,绝对引用,混合引用3、统计函数4、文本函数 应用背景 熟练掌握Excel的函数工具能让我们在日常的使用中更加方…

8.深浅拷贝和异常处理

开发中我们经常需要复制一个对象。如果直接用赋值会有下面问题: 8.1 浅拷贝 首先浅拷贝和深拷贝只针对引用类型 浅拷贝:拷贝的是地址 常见方法: 1.拷贝对象:Object.assgin() / 展开运算符{…obj} 拷贝对象 2.拷贝数组:Array.prototype.con…

【小胡同志】我的创作纪念日——暨加入CSDN128天留念!

2023年4月12日,我首次加入CSDN这个创作大集体,大家庭!实属荣幸,倍感荣耀!在此之前,就曾听说,CSDN是中国开发者的摇篮,今日之悟,确有名之所属之感! 机缘 128天…

完美解决微信小程序使用复选框van-checkbox无法选中

由于小程序使用了vant-ui框架&#xff0c;导致checkbox点击无法选中问题 <van-checkbox value"{{ checked }}" shape"square"><view class"check-content"><view class"checktext">我已阅读并同意>《用户协议》…

中文医学知识语言模型:BenTsao

介绍 BenTsao&#xff1a;[原名&#xff1a;华驼(HuaTuo)]: 基于中文医学知识的大语言模型指令微调 本项目开源了经过中文医学指令精调/指令微调(Instruction-tuning) 的大语言模型集&#xff0c;包括LLaMA、Alpaca-Chinese、Bloom、活字模型等。 我们基于医学知识图谱以及医…

从其他地方复制的内容无法粘贴到idea中

问题描述 提示&#xff1a;这里描述项目中遇到的问题&#xff1a; 使用 idea 开发的时候&#xff0c;从其他地方复制的内容无法粘贴到 idea中&#xff0c;idea的版本是 2023.2 解决方案&#xff1a; 提示&#xff1a;这里填写该问题的具体解决方案&#xff1a; 网上查找资料…

文末有福利 | 小海小源表情包第一弹正式上线

手机铃声提醒你有新的消息 抓紧打个招呼“来了” 收到暖心的称赞 真是按捺不住激动的小心脏啊 只要你愿意拿起书 知识的大门将为你敞开 呲溜~ 这是不是像极了努力工作一天后下班的你&#xff1f; 。。。。。。 看了这么多“海源”表情包 是不是觉得小海、小源愈发可爱了呢…

“保姆级”考研下半年备考时间表

7月-8月 确定考研目标与备考计划 暑假期间是考研复习的关键时期&#xff0c;需要复习的主要内容有&#xff1a;重点关注重要的学科和专业课程&#xff0c;复习相关基础知识和核心概念。制定详细的复习计划并合理安排每天的学习时间&#xff0c;增加真题练习熟悉考试题型和答题技…

【ES6】箭头函数和普通函数的区别

它们之间的区别&#xff1a; &#xff08;1&#xff09;箭头函数没有自己的this。 &#xff08;2&#xff09;不可以当作构造函数&#xff0c;不可以对箭头函数使用new命令&#xff0c;否则抛出错误。 &#xff08;3&#xff09;不可以使用arguments对象&#xff0c;该对象在函…

今年全球智能手机出货量将创10年来新低 |百能云芯

据Counterpoint Research的最新报告称&#xff0c;本年度全球智能手机出货量可能面临十年来最低的局面。然而&#xff0c;值得注意的是&#xff0c;由于高端iPhone销售的坚挺表现&#xff0c;苹果有望在今年成为全球智能手机出货量的冠军。 需要强调的是&#xff0c;出货量并非…

【leetcode】225.用队列实现栈

分析&#xff1a; 队列遵循先入先出的原则&#xff0c;栈遵循后入先出的原则 也就是说&#xff0c;使用队列实现栈时&#xff0c;入队操作正常&#xff0c;但是出队要模拟出栈的操作&#xff0c;我们需要访问的是队尾的元素&#xff1b;题目允许使用两个队列&#xff0c;我们可…

ardupilot开发 --- 位置控制篇

几个疑问 如何根据GPS定位信息进行位置控制&#xff1f; 经纬度海拔高度如何转成导航坐标系&#xff1f; 飞控中的航迹点waypoint是基于那个坐标系的点&#xff1f;导航坐标系&#xff1f; Home点&#xff1f;导航坐标系的原点&#xff1f;电机解锁时的点&#xff1f;xyz&…