Quantum 104 - Player Spawning
개요
플레이어 캐릭터 엔티티가 생성된 다음 단계는 게임에 참여하는 각 플레이어에 대해 플레이어 캐릭터를 생성하고 플레이어의 입력을 엔티티에 연결하는 것입니다.
플레이어 캐릭터 프리팹
현재 캐릭터는 씬 객체입니다. Quantum은 단일 플레이어 유니티 게임에서 프리팹이 런타임에 생성될 수 있는 방법과 유사한 엔티티를 런타임에 생성할 수 있습니다. PlayerCharacter
게임 객체를 씬에서 Resources/DB
폴더로 끌어 PlayerCharacter
프리팹을 만듭니다. 그런 다음 PlayerCharacter
를 씬에서 삭제합니다.
Prefab 아래에 EntityPrototype
과 EntityView
파일이 어떻게 생성되었는지 확인합니다. 이것들은 Quantum에서 엔티티를 생성하고 유니티 뷰에 연결하는 데 사용됩니다.
중요: 모든 Quantum 프리팹은 Resources/DB
폴더 또는 그 하위 폴더 안에 있어야 합니다. 외부 프리탭에는 EntityPrototype
파일이 생성되지 않습니다.
플레이어 링크 컴포넌트
Quantum은 플레이어의 개념을 가지고 있습니다. 각 클라이언트는 한 명 이상의 플레이어를 가질 수 있습니다. 그러나 Quantum에는 플레이어 객체/아바타에 대한 기본 개념이 없습니다. 게임에 연결된 각 플레이어에게는 고유한 ID가 부여됩니다. 이 아이디를 PlayerRef
라고 합니다. 엔티티를 특정 플레이어에 연결하기 위해 소유자의 PlayerRef
가 포함된 PlayerLink 컴포넌트를 만듭니다.
quantum-code
프로젝트의 3dPlatformer
폴더에 PlayerLink.qtn
파일을 만들고 여기에 다음 코드를 추가합니다:
C#
component PlayerLink
{
player_ref Player;
}
플레이어 데이터
캐릭터를 동적으로 생성하기 위해서는 게임플레이 코드가 어떤 엔티티를 생성해야 하는지 알려줘야 합니다. 퀀텀에는 플레이어 데이터 개념이 있습니다. 플레이어 데이터를 통해 각 플레이어는 연결 시 시뮬레이션에 정보를 전달할 수 있습니다. 플레이어가 어떤 캐릭터를 연기하고 있는지, 어떤 스킨을 사용하고 있는지 등의 정보가 될 수 있습니다.
플레이어 데이터는 RuntimePlayer.User
에서 확인할 수 있습니다. quantum_code
프로젝트에서 RuntimePlayer.User
파일을 열고 내용을 다음과 같이 변경합니다:
C#
using Photon.Deterministic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Quantum
{
partial class RuntimePlayer
{
public AssetRefEntityPrototype CharacterPrototype;
partial void SerializeUserData(BitStream stream)
{
stream.Serialize(ref CharacterPrototype);
}
}
}
빌드 (ctrl + shift + b
)를 누릅니다.
이 코드는 프리팹에 해당하는 Quantum인 플레이어 데이터에 AssetRefEntityPrototype
을 추가합니다. 나중에 플레이어 캐릭터 엔티티를 생성하는 데 사용됩니다.
중요: RuntimePlayer
클래스에 추가된 모든 데이터는 SerializeUserData
에 직렬화되어야 합니다. BitStream
은 모든 기본 유형에 대해 직렬화를 제공합니다.
플레이 모드로 들어가면 Quantum 시뮬레이션이 자동으로 실행됩니다. 이는 유니티의 게임 씬에 등장하는 QuantumRunnerDebug
게임 오브젝트의 QuantumLocalRunnerDebug
컴포넌트에 의해 구동됩니다. 이 컴포넌트는 개발 목적으로 단일 플레이어 버전의 Game
을 로컬로 디버그하는 데 사용됩니다.
QuantumLocalRunnerDebug
를 사용하면 임의의 수의 로컬 플레이어를 시뮬레이션할 수 있습니다. Players
아래의 QuantumLocalRunnerDebug
에서 목록에 새 항목을 추가합니다. 이 항목에는 이전에 플레이어 데이터에 추가된 필드인 PlayerCharacterEntityPrototype
필드가 포함되어 있습니다. 플레이어 캐릭터 프리팹 아래에 있는 PlayerCharacter
엔티티 프로토타입 파일을 필드로 끌어다 놓습니다.
이제 프리팹이 플레이어 데이터에 연결되면 플레이어가 참여할 때 엔티티를 생성하는 코드를 작성하는 것만 남았습니다.
플레이어 객체 스폰
새로운 PlayerSpawnsystem.cs
클래스를 생성합니다. 다음 코드를 추가합니다:
C#
namespace Quantum.Platformer
{
unsafe class PlayerSpawnSystem : SystemSignalsOnly, ISignalOnPlayerDataSet
{
public void OnPlayerDataSet(Frame frame, PlayerRef player)
{
var data = frame.GetPlayerData(player);
// resolve the reference to the prototpye.
var prototype = frame.FindAsset<EntityPrototype>(data.CharacterPrototype.Id);
// Create a new entity for the player based on the prototype.
var entity = frame.Create(prototype);
// Create a PlayerLink component. Initialize it with the player. Add the component to the player entity.
var playerLink = new PlayerLink()
{
Player = player,
};
frame.Add(entity, playerLink);
// Offset the instantiated object in the world, based in its ID.
if (frame.Unsafe.TryGetPointer<Transform3D>(entity, out var transform))
{
transform->Position.X = 0 + player;
}
}
}
}
이 코드는 플레이어가 참여할 때 캐릭터 엔티티를 생성하고 플레이어 링크 컴포넌트를 추가하여 플레이어에 연결합니다.
시그널은 C#의 이벤트와 유사합니다. Quantum 시스템에서 서로 통신하는 데 사용됩니다. Quantum은 플레이어가 세션에 참여해 플레이어 데이터를 공유한 후 호출되는 ISignalOnPlayerDataSet
등 기존 시그널이 많이 포함돼 있습니다.
SystemSignalsOnly는 자체적으로 아무것도 수행하지 않는 특수한 유형의 시스템입니다. 신호만 듣는 시스템을 구현할 수 있습니다.
SystemSetup.cs
의 시스템 목록의 MovementSystem
다음에 PlayerSpawnSystem을 추가합니다.
MovementSystem 업데이트
지금까지 MovementSystem은 항상 다음 코드를 사용하여 0 플레이어의 입력을 사용하여 이동했습니다:
C#
var input = *f.GetPlayerInput(0);
링크된 플레이어에서 입력을 가져오려면 다음으로 대체합니다:
C#
Input input = default;
if(f.Unsafe.TryGetPointer(filter.Entity, out PlayerLink* playerLink))
{
input = *f.GetPlayerInput(playerLink->Player);
}
필터가 조정되지 않았기 때문에 시스템은 여전히 CharacterController가 있지만 PlayerLink 컴포넌트가 없는 엔티티를 필터링합니다. 이 경우 입력에 default
값을 사용합니다. 이로 인해 중력이 작용하는 것 외에는 움직임이 없습니다.
Quantum에서 TryGet
을 사용하여 컴포넌트를 얻는 것은 Quantum이 희소 집합 ECS를 사용하기 때문에 O(n) 매우 빠릅니다.
빌드(ctrl + shift + b
)를 누르고 유니티로 전환하여 플레이 모드로 들어갑니다. 플레이어 캐릭터는 이미 씬에 있는 캐릭터와 함께 생성되며 키보드 입력에 반응합니다.