This document is about: QUANTUM 3
SWITCH TO

7 - Boundaries

概述

現時,飛船和小行星可以無邊界地移動,並離開相機視野。在小行星遊戲中,當一艘船或小行星離開畫面時,它會再次出現在畫面的另一側。複製此行為的一種簡單方法是使用一個系統來檢查實體是否在邊界內,並相應地傳送它們。

邊界

創建一個BoundarySystem指令碼,並向其中新增以下程式碼:

C#

using UnityEngine.Scripting;
using Photon.Deterministic;

namespace Quantum.Asteroids
{
    [Preserve]
    public unsafe class BoundarySystem : SystemMainThreadFilter<BoundarySystem.Filter>
    {
        public struct Filter
        {
            public EntityRef Entity;
            public Transform2D* Transform;
        }

        public override void Update(Frame f, ref Filter filter)
        {
            if (IsOutOfBounds(filter.Transform->Position, new FPVector2(10, 10), out FPVector2 newPosition))
            {
                filter.Transform->Position = newPosition;
                filter.Transform->Teleport(f, newPosition);
            }
        }

        /// <summary>
        /// Test if a position is out of bounds and provide a warped position.
        /// When the entity leaves the bounds it will emerge on the other side.
        /// </summary>
        public bool IsOutOfBounds(FPVector2 position, FPVector2 mapExtends, out FPVector2 newPosition)
        {
            newPosition = position;

            if (position.X >= -mapExtends.X && position.X <= mapExtends.X &&
                position.Y >= -mapExtends.Y && position.Y <= mapExtends.Y)
            {
                // position is inside map bounds
                return false;
            }

            // warp x position
            if (position.X < -mapExtends.X)
            {
                newPosition.X = mapExtends.X;
            }
            else if (position.X > mapExtends.X)
            {
                newPosition.X = -mapExtends.X;
            }

            // warp y position
            if (position.Y < -mapExtends.Y)
            {
                newPosition.Y = mapExtends.Y;
            }
            else if (position.Y > mapExtends.Y)
            {
                newPosition.Y = -mapExtends.Y;
            }

            return true;
        }
    }
}

該系統在所有具有一個變換的實體上迴圈,然後在越界時傳送它到地圖的另一側。對於更具選擇性的方法,可以在篩選器中使用標籤元件。

轉換上的Teleport函數用於向EntityViewInterpolator發出訊號,表示應跳過此移動的內插補點。如果沒有傳送命令,當從畫面的一個邊緣傳送到另一個邊緣時,實體將從畫面的一端內插補點到另一端。

BoundarySystem新增到AsteroidsSystemConfig ScriptableObject中,然後進入遊玩模式。太空梭和小行星在到達邊界時被正確地傳送。

可設置邊界

現時,邊界被硬編碼為20x20單位的地圖大小。為了使其更加靈活,可以將地圖大小新增到AsteroidsGameConfig中。

打開AsteroidsGameConfig指令碼並新增以下內容:

C#

[Header("Map configuration")]
[Tooltip("Total size of the map. This is used to calculate when an entity is outside de gameplay area and then wrap it to the other side")]
public FPVector2 GameMapSize = new FPVector2(25, 25);

public FPVector2 MapExtends => _mapExtends;

private FPVector2 _mapExtends;

一個名為GameMapSize的公共成員欄位用於調整設置中地圖的大小,因為設計人員使用總地圖寬度和高度而不是擴展的話更直觀。然而,對於遊戲程式碼來說,使用擴展更容易,效能更高。設置檔中的一種常見模式是在將設置載入到遊戲中時計算一次額外資料。這可以透過以下方式使用Loaded函數來完成:

C#

public override void Loaded(IResourceManager resourceManager, Native.Allocator allocator)
{
    base.Loaded(resourceManager, allocator);

    _mapExtends = GameMapSize / 2;
}

返回到BoundarySystem指令碼,調整程式碼以載入設置並使用其中的擴展:

C#

public override void Update(Frame f, ref Filter filter)
{
    AsteroidsGameConfig config = f.FindAsset(f.RuntimeConfig.GameConfig);

    if (IsOutOfBounds(filter.Transform->Position, config.MapExtends, out FPVector2 newPosition))
    {
        filter.Transform->Position = newPosition;
        filter.Transform->Teleport(f, newPosition);
    }
}

返回Unity並調整設置中的GameMapSize。當使用16:9寬高比時,(70, 40)的值與視覺效果相匹配。

進入遊玩模式。太空梭和小行星現在使用設置檔中設定的邊界。

GIF of boundaries during play mode
Back to top