注册photonengine账号
创建App
Realtime: Photon Realtime 是 Photon 提供的最基本的多人游戏服务。它允许开发人员快速轻松地创建实时多人游戏,提供了可靠的基础设施来处理玩家之间的连接、房间管理、同步游戏状态等功能。
Chat: Photon Chat 是一个实时聊天解决方案,允许开发人员为他们的游戏添加聊天功能。它提供了一种可扩展的方式来处理聊天消息的传递、管理用户的频道、历史消息等。
Voice: Photon Voice 是用于实时语音聊天的解决方案。它允许玩家在游戏中进行语音通信,提供了可靠的语音传输、音频编解码和回声消除功能。
PUN (Photon Unity Networking): Photon PUN 是专为 Unity 开发者设计的高级网络解决方案。它是建立在 Photon Realtime 之上的,提供了易于使用的 Unity API,使开发人员能够在 Unity 中快速构建多人游戏。
Bolt 是 Photon 的另一个产品,它是一种高级的网络引擎,专为实时、多人游戏开发而设计。与Photon PUN不同,Bolt提供了更多的自定义性和灵活性,允许开发人员更深入地控制游戏的网络部分。
- Quantum 是一个高性能确定性 ECS(实体组件系统)框架,适用于使用 Unity 制作的在线多人游戏。它基于预测/回滚方法,非常适合延迟敏感的在线游戏,例如动作角色扮演游戏、体育游戏、格斗游戏、第一人称射击游戏等。
- Fusion 是 Unity 的全新高性能状态同步网络库。Fusion 在构建时考虑到了简单性,可以自然地集成到常见的 Unity 工作流程中,同时还提供开箱即用的数据压缩、客户端预测和滞后补偿等高级功能。
Quantum
ECS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Quantum是采用ECS框架,ECS独立于UnityEngine被放在quantum_code项目中,通过dsl生成component,这些组件通过unity中EntityPrototype挂在在角色身上,系统(继承SystemMainThread)通过SystemSetup注册到Core.cs, Quantum引擎回回调这些System函数。 #### 通过DSL生成数据类代码
1. 注册账号 生成appid
2. 下载测试按钮 (https://dashboard.photonengine.com/zh-cn/download/quantum/quantum-100-2.1.4.zip)
3. 解压文件quantum-100-2.1.4.zip,将quantum-100-2.1.4\tools\codeintegration_unity内容全部复制到quantum-100-2.1.4\quantum_code\quantum.code
4. 在quantum_unity/Packages/manifest.json中添加本地配置包配置 "com.exitgames.photonquantumcode": "file:../../quantum_code/quantum.code"
5. 删除 quantum_unity/Assets/Photon/Quantum/Assemblies/quantum.code.dll
6. quantum-100-2.1.4\quantum_code\quantum.code\quantum.code.csproj 添加下面代码
<ItemGroup>
<None Include="Foo\bar.qtn" />
<None Include="Oof\rab.qtn" />
</ItemGroup>
7. 创建qtn文件 ```c#
component Action
{
FP Cooldown;
FP Power;
} ```
7. cmd运行 D:\quantum-100-2.1.4/tools/codegen/quantum.codegen.host.exe D:\quantum-100-2.1.4\quantum_code\quantum.code
8. 打开quantum_code.sln 生成dll文件,开发阶段可以不用生成 
9. 使用Unity打开quantum_unity 生qtn代码 
组件 (Components)
- 自定义组件 通过dsl生成 component Action { FP Cooldown; FP Power; } 生成组件名:EntityComponentAction
- 系统组件 无状态物理引擎 PhysicsCollider、PhysicsBody、PhysicsCallbacks、PhysicsJoints (2D/3D)
- 系统组件 基于导航网格的路径查找和移动 PathFinderAgent、SteeringAgent、AvoidanceAgent、AvoidanceObstacle:。
游戏逻辑 Systems
- SystemMainThread
- SystemMainThreadFilter
,可以关注需要的内容 - System需要通过SystemSetup:CreateSystems需要将数据放入Core.cs
- Systems通过Update从Frame中获得需要的数据:f.Unsafe.TryGetPointer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public unsafe class MySystem : SystemMainThread
{
public override void Update(Frame f)
{
}
}
public unsafe class MovementSystem : SystemMainThreadFilter<MovementSystem.Filter>
{
public struct Filter
{
public EntityRef Entity;
public Transform2D* Transform;
public PlayerCharacter* PlayerCharacter;
public KCC* Kcc;
}
public override void Update(Frame frame, ref Filter filter)
{
}
}
Frame
1
2
3
4
frame是系统(继承SystemMainThread)通过Quantum内部回调Update得到。
继承关系:Frame:FrameBase:DeterministicFrame
使用Frame.User 扩展Frame数据
System从Frame中获得需要的数据:f.Unsafe.TryGetPointer
事件和回调 (Events & Callbacks)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//dsl生成myevnt类
event MyEvent {
int Foo;
}
//事件触发 必须是系统(MySystem)
public override void Update(Frame f) {
f.Events.MyEvent(2022);
}
//事件注册
QuantumEvent.Subscribe<EventMyEvent>(listener: this, handler: OnEventPlayerHit);
private void OnEventPlayerHit(EventMyEvent e){
Debug.Log($"MyEvent {e.Foo}");
}
定点数 Events & Callbacks
- 采用的是Q48.16(48位整数,16位小数)
- 使用FPAnimationCurve 创建动画曲线,或者AnimationCurve 烘培到FPAnimationCurve
QuantumLoadBalancingClient 使用(点击开始按钮创建QuantumLoadBalancingClient)
1
2
3
4
1. var Client = new QuantumLoadBalancingClient(PhotonServerSettings.Instance.AppSettings.Protocol);
2. Client.ConnectUsingSettings(appSettings, Username)
3. Client.OpJoinRandomOrCreateRoom(joinRandomParams, _enterRoomParams)
4. QuantumRunner.StartGame(clientId, param);
EntityViewUpdater (渲染部分)
1
2
1. 注册消息 QuantumCallback.Subscribe
2. 同步数据 SyncViews (是否创建player BindMapEntityIfNeeded->CreateView->CreateEntityViewInstance->GameObject.Instantiate)
EntityPrototype
1
2
3
4
5
这是一个实体原型,虽然继承了MonoBehaviour,但是没有使用任何API,直接用于挂在组件而用的,实际数据序列化到EntityPrototypeAsset。
需要加载EntityPrototypeAsset数据,实例化组件
IResourceLoader.LoadResource(AssetResource resource)
FinishLoading
EntityPrototypeAsset:PrepareAsset()->behaviourBuffer
EntityView 渲染部分
1
2
Non Verified:可在预测帧中创建视图游戏对象,如子弹
Verified :只能在已验证帧中创建,如玩家角色
QuantumCallbacks 相当于MonoBehaviour,回调数据来说photon网络调用
- Quantum.Core //Quantum 内部调用的一些接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
public enum CallbackId { PollInput, GameStarted,//游戏开始时调用 GameResynced,//游戏快照重新同步时调用的回调 GameDestroyed,//游戏销毁时调用 UpdateView,//回调保证在每个渲染帧被调用。 SimulateFinished,//逻辑帧完成回调 EventCanceled, //当由于回滚,错过预测而在已验证帧中取消预测帧中引发的事件时调用的回调 EventConfirmed,//当经过验证的帧确认事件时调用回调 ChecksumError,//校验预测错误时调用回调 ChecksumErrorFrameDump,//由于校验预测错误而转储帧时调用的回调 InputConfirmed,//本地输入确认后回调 ChecksumComputed, PluginDisconnect, UserCallbackIdStart, }
- QuantumCallbacks 函数 OnGameStart: OnGameResync: OnGameDestroyed: OnUpdateView: OnSimulateFinished: OnUnitySceneLoadBegin: OnUnitySceneLoadDone: OnUnitySceneUnloadBegin: OnUnitySceneUnloadDone: OnChecksumError:
- 注册数据Frame (quantum_code里面) _ISignalOnPlayerDataSet = BuildSignalsArray
(); _ISignalOnCollision2DSystems = BuildSignalsArray (); _ISignalOnCollisionExit2DSystems = BuildSignalsArray (); 发送数据 发生数据:game.SendPlayerData(lp, new Quantum.RuntimePlayer { PlayerName = PlayerName, SelectedCharacter = CharacterPrototype});
- 接受数据 Core:OnSimulate() Core:UpdatePlayerData()-> ISignalOnPlayerDataSet:OnPlayerDataSet() (quantum_code里面) 派发到 PlayerConnectedSystem 里面
- QuantumCallbackHandler_LegacyQuantumCallback QuantumCallback:QuantumCallback:() //内部调用 IsDefaultHandlerEnabled() QuantumCallbackHandler_LegacyQuantumCallback.Initialize() QuantumCallback.SubscribeManual //手动订阅消息(CallbackChecksumError,CallbackGameDestroyed,CallbackGameStarted,CallbackGameResynced …)
Fusion
Host Mode Basics
Shared Mode
Server Mod
实例 Animancer
PlayerLocomotionState.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//移动状态
public class PlayerLocomotionState : PlayerStateBehaviour
{
[SerializeField]
private LinearMixerTransition _moveMixer;
protected override void OnEnterStateRender()
{
Animancer.Play(_moveMixer);
// Update the animation time based on the state time
_moveMixer.State.Time = Machine.StateTime;
}
protected override void OnRender()
{
_moveMixer.State.Parameter = Controller.InterpolatedSpeed;
}
}
Player_AnimancerFSM.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class Player_AnimancerFSM : NetworkBehaviour, IStateMachineOwner
{
// PRIVATE MEMBERS
private CharacterController _controller;
private PlayerBehaviourMachine _fullBodyMachine;
// NetworkBehaviour接口调用
public override void FixedUpdateNetwork()
{
if (IsProxy == true)
return;
if (_controller.HasJumped == true)
{
//状态机切换状态
_fullBodyMachine.TryActivateState<PlayerJumpState>();
}
}
// IStateMachineOwner接口调用
void IStateMachineOwner.CollectStateMachines(List<IStateMachine> stateMachines)
{
//获得所有的的状态
var states = GetComponentsInChildren<PlayerStateBehaviour>(true);
var animancer = GetComponentInChildren<AnimancerComponent>(true);
//创建状态机
_fullBodyMachine = new PlayerBehaviourMachine("Full Body", _controller, animancer, states);
stateMachines.Add(_fullBodyMachine);
}
protected void Awake()
{
_controller = GetComponentInChildren<CharacterController>();
}
}