网络游戏开发中状态同步核心原理剖析

本文详细阐述了状态同步在网络游戏中的应用,区分了帧同步与状态同步,介绍了服务器上如何处理游戏逻辑,以及客户端和服务端如何通过状态变化进行同步,重点讲解了行走过程中的位置更新策略。
摘要由CSDN通过智能技术生成

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

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

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

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

服务器上如何跑游戏逻辑

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;
	}
}

是有一点要求的。根据游戏不同的类型来做地图编辑器,来采用最合适的技术。同时客户端+服务端都要使用这套,客户端有地图编辑器工具编辑地图的地形+烘焙地图连通数据,能将这些数据按照对应的格式导出給服务端用,服务端使用这些数据利用上面的Update来进行迭代计算(和客户端开发的Update迭代是一样的)。

服务端与客户端如何同步

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

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

Step2: 服务端接收到这个事件,做合法性检查(比如操作的合法性检查, 目的地坐标范围合法性, 玩家在A点,导航去到千里之外的B点,距离太远,可能有外挂的嫌疑),检查通过后再处理。

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

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

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

由上面得到的结论就是,行走过程中位置的变化,没有必要同步到客户端,服务端跑服务端的,客户端跑客户端的,只是重要状态变化后,服务端把最新的信息发送給客户端,客户端同步。在上面的例子中,玩家在行走中,玩家又有其它的攻击操作了,那么又是状态变化了,服务端又会在处理

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值