This document is about: QUANTUM 2
SWITCH TO

Quantum 104 - Player Spawning

개요

플레이어 캐릭터 엔티티가 생성된 다음 단계는 게임에 참여하는 각 플레이어에 대해 플레이어 캐릭터를 생성하고 플레이어의 입력을 엔티티에 연결하는 것입니다.

플레이어 캐릭터 프리팹

현재 캐릭터는 씬 객체입니다. Quantum은 단일 플레이어 유니티 게임에서 프리팹이 런타임에 생성될 수 있는 방법과 유사한 엔티티를 런타임에 생성할 수 있습니다. PlayerCharacter 게임 객체를 씬에서 Resources/DB 폴더로 끌어 PlayerCharacter 프리팹을 만듭니다. 그런 다음 PlayerCharacter를 씬에서 삭제합니다.

플레이어 프리팹

Prefab 아래에 EntityPrototypeEntityView 파일이 어떻게 생성되었는지 확인합니다. 이것들은 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 엔티티 프로토타입 파일을 필드로 끌어다 놓습니다.

Inspector view of the QuantumDebugRunner

이제 프리팹이 플레이어 데이터에 연결되면 플레이어가 참여할 때 엔티티를 생성하는 코드를 작성하는 것만 남았습니다.

플레이어 객체 스폰

새로운 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)를 누르고 유니티로 전환하여 플레이 모드로 들어갑니다. 플레이어 캐릭터는 이미 씬에 있는 캐릭터와 함께 생성되며 키보드 입력에 반응합니다.

Back to top