このページは編集中です。更新が保留になっている可能性があります。

入門チュートリアル

このドキュメントでは、付属のコンポーネントといくつかのUnity標準アセットのみを使用して、コーディングなしでゼロからデモシーンを作成する手順を説明しています。 そのため、見た目に美しいデモではありません。 このデモの目的は、アシストを使用して有用なネットワークを素早く作成する方法を説明することです。

目次

アシストについて

アシストとは、ネットワーク上のオブジェクトを作成する作業を自動化するためのメニューアイテムのことで、このデモで使用されています。 アシストは基本的にワンクリックウィザードで、インターフェイスはありません。 Unityで選択されているゲームオブジェクトに対してタスクを実行しようとしたり、必要に応じて新しいシーンオブジェクトを作成したりします。

トップに戻る

新規プロジェクトの作成と最新のPUN2/Simpleのインポート

  1. 2017.4以上の任意のバージョンのUnityで新規プロジェクトを作成する。
  2. Asset Storeから最新のPUN2をインポートする。
  3. Simpleをダウンロード してインポートする。

トップに戻る

新規シーンの作成

  1. 新しいシーンの作成(まだ作成していない場合)する。
  2. アシストを使って基本的な床・壁を設定する。 GameObject > Simple > Tutorial > Create Starting Scene


このアシストは、ネットワーク上で何にも行いません。 壁や床を追加してシーンを準備し、カメラをより良い位置に移動させます。

これで、床面のある空のシーンができました。

For Unity 2019 if the scene appears dark:
You may need to go to enable AutoGenerate in:
Window > Rendering > Lighting

トップに戻る

プレイヤーの作成

まず、BasicKyleプレハブのインスタンスをシーンに追加して、ネットワーク用のバリエーションを作成します。

  1. プロジェクトで検索して、アセットでプレハブを見つけます。 Standard AssetsのKyle/EthanのLite版が含まれています。
  2. プレハブをシーンにドラッグする。

トップに戻る

BasicKyleからSimple Net Objectへ変換

プレイヤーや車両のような制御可能なオブジェクトは、同期させるために「ネット化」する必要があります。 Convert To > Playerアシストは、そのための作業のほとんどを自動化します。 この例では、Unity Standard AssetsThirdPersonController を使用していますが、このプロセスはほとんどのプレイヤーオブジェクトタイプで同様です。 このアシストは、動く/アニメーションするシングルプレイヤーオブジェクトを ネットワークオブジェクトにするための、最適な出発点を作ります。

  1. シーン内の「BasicKyle」のゲームオブジェクトを選択する。

  2. アシストを使って「BasicKyle」をネットオブジェクトに変換する。 GameObject > Simple > Convert To > Player



    これにより、プレイヤーオブジェクトにプレースホルダーのヘルスバーが追加され、 各種のネットワークコンポーネントも追加されます。

    • PhotonView
    • NetObject
    • SyncAnimator (オブジェクトにアニメーターが存在する場合)
    • SyncTransform
    • SyncVitals
    • AutoOwnerComponentEnable
    • ContactTrigger
    • MountManager
    • Mount (ルートマウント)
    • BasicInventory
    • SyncState
    • OnStateChangeKinematic
    • SyncSpawnTimer
    • AutoDestroyUnspawned
    • OnStateChangeToggle (子の上)

NetObjectPhotonView の拡張機能として動作するルートコンポーネントで、 NetMaster から子の SyncObject や PackObject へのコールバックの受け渡しや、 シリアル化とデシリアライズの管理を行います。 NetObject は、実行時に自動的に追加される NetMaster シングルトンからタイミングを取得します。
注:AutoDestroyUnspawned が自動的に追加されます。 オブジェクトによっては、これを削除した方が良い場合もあります。 スタートシーンでこのコンポーネントを持つゲームオブジェクトは、ランタイムに破壊されます。 これにより、プレイする前やテストを構築する前にプレハブインスタンスを削除することなく、エディタで作業することができます。 シーンの一部としてスポーンさせる予定のオブジェクトは、このコンポーネントを削除する必要があります。

  1. シーンの「BasicKyle」プレハブインスタンスを任意のResourceフォルダにドラッグする。
    既存のResourcesフォルダを探すのではなく、新しいResourcesフォルダを追加した方が良いかもしれません。新しいバージョンのUnityでは、これをVariantにするかどうか尋ねられます。それは問題ありません。

トップに戻る

PUN2ネットワーキングコードの追加

PUNルームに参加するためのコードはまだありませんが、これを追加して進捗状況を確認してみましょう。

一般的には、マッチメイキング、ロビーやルームの作成、プレイヤーオブジェクトのインスタンス化などを行うための独自のカスタムコードを作成します。 PUN2にはこれらを自動化するコンポーネントがいくつかあり、Simpleにはそれらを自動的にシーンに追加するアシスト機能があります。

トップに戻る

接続とルームの作成のためのコンポーネントの追加

  1. アシストを実行する前に、シーンで「KyleBasic」を選択する。

  2. アシストを使ってルームランチャーを追加します。 GameObject > Simple > Add To Scene > Auto Room Launchers

    これにより、コンポーネントを持つシーンオブジェクトが作成されます(すでに存在する場合は修正されます)。

    • ConnectAndJoinRandom
    • OnJoinedInstantiate (選択したプレハブをインスタンス化するプレハブリストに追加します。)

You can rerun the assist with other prefabs select to add them to the OnJoinedInstantiate prefab list.

これでシーンを再生すると以下のようになります:

  1. マスターサーバーに接続
  2. ルームの作成または参加
  3. プレイヤーを起動

トップに戻る

バイタルとインベントリのピックアップアイテムを作成

ピックアップとは、IContactReactorコンポーネントを持つオブジェクトで、IContactSystems(InventoryやVitalsなど)と相互作用することができます。 これらのオブジェクトは、IContactSystemオブジェクトによって、トリガーされたり、ピックアップ、取り付け、マウントされたりします。 通常、これらのアイテムをトリガーするのはプレイヤー(またはAI)になります。

これらのオブジェクトのプロトタイプを作成するためのアシストがあり、すべてのネットワークコンポーネントが自動的に追加されます。 これらの生成されたオブジェクトには、異なる状態を表すプレースホルダーの子オブジェクトが含まれています。

  • Itemsは、IInventoryableなコンポーネントで、ピックアップしてIInventorySystemにマウントすることができます。
  • Vitalsは、IVitalsSystemとの連携に必要なIVitalsContactReactorコンポーネントを有しています。

アシストで生成されたアイテムには、OnStateChangeToggleコンポーネントを持つプレースホルダーのセットが付属しており、可能ないくつかの状態のために設定されています。 これを実際のグラフィック、サウンドトリガー、パーティクルシステムなどに置き換えます。 また、IOnStateChangeを実装した独自のスクリプトを作成して、オブジェクトの状態が変化したときのコールバックを取得することもできます。

トップに戻る

体力ピックアップを追加

  1. アシストを使ってPickup Vitalを追加します。 GameObject > Simple > Add To Scene > Pickup > Vital: Static

    Vital: Staticは、Vital.Dynamicと同じですが、RigidbodySyncTransformは追加されません。 これは、このオブジェクトがドロップ/スローされることを想定していないためです。

  2. プレイヤーのスポーンポイントに重ならないようにアイテムを移動させます。 ポジションXを3に設定



    この時点でゲームを実行すると、プレイヤーはアイテムを拾うことができます。 プレイヤーがこのピックアップをトリガーすると、ピックアップがバイタルタイプ「体力」に設定されており、プレイヤーのSyncVitalsが体力バイタルを持っているので、 プレイヤーの体力に追加され、プレイヤーに装着されます。

トップに戻る

ピックアップアイテムの追加 (IInventoryable)

同様の方法でインベントリアイテムを製作します。

  1. アシストを使ってPickup Itemを追加します。 GameObject > Simple > Add To Scene > Pickup > Item: Dynamic

    Item: Dynamicは、Item: Staticと同じですが、RigidbodyとSyncTransformが追加されているので、 落としたり投げたりすることができます。

  2. プレイヤーのスポーンポイントと重ならないように、アイテムを移動します。 ポジションXを-3に設定



    この状態でゲームを実行すると、プレイヤーはアイテムを拾うことができます。
    現在、Kyleのマウントは、「Convert To > Player」で自動的に追加されたデフォルトの「Root」マウントのみです。 Kyleにさらにマウントを追加し、「インベントリ」や「バイタル」システムに割り当てることができます。 次のセクションでは、追加のマウントを追加して使用する方法を説明します。

トップに戻る

プレイヤーにマウントを追加

あらゆるNetObjectの子ゲームオブジェクトにMountコンポーネントを追加することができます。 ピックアップしたアイテムは、これらのトランスフォームにマウントするように指定できます。

デフォルトのMountは自動的にルートに追加され、'Root'という名前になります。また、MountsManagerコンポーネント(自動マウントインデックス作成を処理します)も追加されます。 1. シーン内のPlayerインスタンスを選択します。

  1. 階層検索ボックスに「 wrist 」と入力します。

  2. Left_Wrist_Joint_01」を選択します。

  3. 「Left_Wrist_Joint_01」にMountコンポーネントを追加します。

  4. マウントタイプ 'LeftHand' を選択 します。 これは、このマウントをLeftHandという名前のタイプに関連付けます。 各ネットオブジェクトは、名前の付いたタイプに関連するマウントを1つだけ持つことができます。

  5. 任意: グローバルマウントタイプを変更。 LeftHandがマウント設定の現在のリストに存在しない場合は、Mount Settingsを展開して追加します。 これにより、マウント用のSettings ScriptableObjectが公開されます。 MountSettingsは、プロジェクト全体、およびすべてのマウントに適用されます。

  6. 「Left_Wrist_Joint_01」にMount Throwコンポーネントを追加。

  7. MountThrowのスローキーをAlpha 5 に設定。
    「5」キーを押すと、インベントリのアイテムを拾った後にドロップします。 左手にマウントができましたが、この新しいマウントを使うようにオブジェクトに指示するものは特にありません。 このマウントを使用するためには、次のステップが必要です。

トップに戻る

マウンティングアサインメント

インベントリとバイタルのアイテムは、それらのアイテムがMountable To(マウント可能)の名前のタイプを持ち、それがバイタルのマウント設定と一致する場合にのみマウントすることができます。 名前付きタイプがある場合のみマウントできます。

トップに戻る

特定のマウントにインベントリを割り当てる

SyncStateは、他のネットオブジェクトのマウントにネットオブジェクトをアタッチする処理を行います。 そのため、SyncStateMountable Toの値を設定することで、ネットオブジェクトがアタッチできるマウントを制限することができます。

  1. 前のステップで作成した「Pickup Item」を選択します。

  2. SyncState Mountable To セレクタで「LeftHand」を有効にします

このマスクは、互換性のあるタイプ間でのみアタッチが発生するよう制限するために使用されます。 このオブジェクトは、「LeftHand」マウントを使用するIContactSystemにのみマウントできます。


  1. マウントとしてLeftHandを使用するようにBasicInventoryを設定します。

    BasicKyleのルート上で、BasicInventoryを見つけ、Default MountingLeftHandに設定します。


    これは、このInventorySystemによってピックアップされたInventoryableが、 'LeftHand'に関連付けられたMountに取り付けられることを示しています。 _IInventoryableアイテムは、SyncState Mountable Toで'LeftHand'がチェックされている必要があります。(上記のステップを参照)
    プレハブに変更を加えることを忘れないでください!

    これで、プレイヤーが「ピックアップアイテム」に触れると、最初に見つかる有効なインベントリである、Kyleの手に取り付けられます。 取り付けられない場合は、インベントリが左手を使うように設定されているか、また、ピックアップのSyncStateで左手が有効なマウントとして選択されているかを再確認してください。

トップに戻る

ネットワーク化されたヒットスキャンの追加

  1. シーン内で「Robot2」または「BasicKyle」プレイヤーの子ゲームオブジェクトを選択します。

  2. アシストを使ってDamage Scanを追加します。 GameObject > Simple > Add To Object > Remote Contact > Damage Scan

  3. 作成した「ダメージスキャン」の子を再配置します。
    ポジションを(-0.5, 1.5, 0)に設定




    武器アシストは、子のプレースホルダーオブジェクトを追加します。 これらを独自のモデルで置き換えることができます。

    プレハブに変更を加えることを忘れないでください!

再生を押すと、「R」を押したときにデフォルトのヒットスキャンが発射されるのがわかります。

Note: Contact Scans generate ContactEvents similar to Enter, Stay and Exit.

そのため、ContactTriggerをリモートでトリガーするために使用することができます。 つまり、コンタクトトリガーを「レイキャスト」または「オーバーラップ」させることができるのです。 ヒットスキャンは武器だけのものではありません。

トップに戻る

ネットワーク化された投射砲の追加

  1. BasicKyle の子 Robot2 をシーン内で選択します。

  2. アシストを利用してネットワーク化された「Projectile Cannon」を追加します。 GameObject > Simple > Add To Object > Remote Contact > Damage Cannon

  3. 作られたProjectile Cannonの子を動かします。
    (今は足の指から発射しています)
    位置を(0.5, 1.5, 0)に設定してください。

    ダメージキャノンの追加
    武器アシストには、プレースホルダーオブジェクトが追加されています。 これらを独自のモデルで置き換えることができます。

    プレハブに変更を加えることを忘れないでください!

再生を押すと、「F」を押したときにデフォルトの発射が行われるのがわかります。

Note: Projectiles act as proxy ContactEvents. As such they can be used to trigger the ContactTrigger as if the shooting object collided with the object. This means it is possible to 'shoot' pickups. Projectiles are not just weapons._

トップに戻る

ヒットスキャンリモートアクションの追加

ヒットスキャンは武器だけではなく、ContactTriggerコンポーネントをプロキシでトリガーする手段としても使用でき、発射するオブジェクトのContactTriggerの延長となります。

  1. シーン内の「BasicKyle」インスタンスの子ノード「Robot2」を選択 します。

  2. アシストを使ってContactProxyのヒットスキャンを追加します。
    GameObject > Simple> Add To Object > Remote Contact > Contact Scan


Playを押すと、'5'キーを押すことで、IInventoryableアイテム(Vital/Item Pickup)をピックアップできるようになります。 また、すぐにヒットスキャンの視覚的表現が表示されます。 デフォルトのヒットキャンはOverlapSphereですが、他のタイプのオーバーラップやレイキャストに変更することもできます。 また、デフォルトでは、トリガー後しばらくの間、ヒットキャンの黄色い視覚化オブジェクトが表示されます。 スキャンによってヒットしたContactTriggersは、ContactType.Hitscanを持つOnContactEventをトリガーします。

The 'Contact Scan' assist adds the same set of components as 'Damage Scan', except it doesn't add a IContactReactor component. This means that all Hitscan Weapons are actually capable of triggering IInventory -> IInventoryable interactions.

トップに戻る

動く地形の追加

プラットフォームや移動する地形は、SyncMoverBaseから派生したITransformControllerコンポーネントを使って追加することができます。 この例では、SyncNodeMoverを使用して、2つのポイント間の時間ベースの移動を作成しています。 すべてのネットワークは自動的に処理されます(これは'Sync'で始まるコンポーネントすべてに言えることです)。 移動する地形が「マウント」を持つネットオブジェクトの場合、プレイヤーの「AutoMountHitscan」コンポーネントが自動的にその近さを検出して、そのプラットフォームに再ペアリングします。 これにより、移動するプラットフォームに対するプレイヤーの位置がネットワーク化され、他の人が所有している移動オブジェクトにプレイヤーが接続されている場合に発生する、遅延による「浮遊」を防ぐことができます。

  1. 「Floor Tile 1」という名前の床の一番左の部分を選択します。

  2. アシストを使ってPlatformに変換します。 GameObject > Simple > Convert To > Platform


    これにより、床の部分がネットオブジェクトに変換され、MountSyncNodeMoverのコンポーネントが追加されます。 シーンが作られたり再生されたりすると、この床の部分が上下に振動するようになります。

  3. アシストを使って「BasicKyle」にAutoMountHitscanを追加します。 GameObject > Simple > Add To Object > Auto Mount Hitscan

    これにより、「AutoMount」という名前の子ゲームオブジェクトが追加され、その中にはAutoMountHitscanコンポーネントが含まれます。

再生時には、「BasicKyle」のベースから下方に向けてレイキャストが継続的にテストされ、ネットオブジェクトが近くにあるかどうかを確認します。 BasicKyleは、互換性のあるマウントを持つ最も近いネットオブジェクトにマウント(再親権)します。 このヒットスキャンテストの設定は、AutoMountHitscanコンポーネントのHitscan Definition設定で定義されます。

トップに戻る

NPCの追加

まず、自律的に動くシーンオブジェクトを作る必要があります。

  1. アシストを使ってチュートリアルNPCを作成します。 GameObject > Simple > Tutorial > Add NPC
    これにより、リング状に動く基本的なネットワークキューブが出来上がります。

  2. 例のNPCオブジェクトが非選択状態になっている場合は選択します。

  3. アシストを使ってNPCをネットオブジェクトに変換します。 GameObject > Simple > Convert To > Player
    これにより、BasicKyleに追加したのと同じように、追加のコンポーネントが追加されます。 これで、このオブジェクトは、体力システム、インベントリシステム、体力バーなどを持つようになりました。

シーンを実行すると、このオブジェクトが円を描くように動くはずです。 このオブジェクトは、マスタークライアントが所有します。 このNPCには体力システムがあるので、ダメージを受けることができ、通常のプレイヤーのようにIVitalsAffectorIInventoryableのピックアップを引き起こすことができます。 すべてのシーンオブジェクトと同様に、マスタークライアントがこのオブジェクトを所有します。

トップに戻る

SyncVarAttributesを用いたPackObjectの作成

実験

PackObjectsに関するドキュメント

トップに戻る

SyncVarAttributeの基本的な実装

  1. 新しいCubeをシーンに追加します。 GameObject > 3D Object > Cube

  2. SyncvarTest.csというスクリプトを作成し、以下のコードに貼り付けます。

        using UnityEngine;
    using Photon.Compression;
    using Photon.Pun;
    using Photon.Pun.Simple;
    
    
    /// The PackObject attribute tells the code gen engine and the NetObject that this class/struct
    /// contains [SyncVar] attributes that should be serialized and synced.
    [PackObject]
    [RequireComponent(typeof(NetObject))]
    public class SyncvarTest : MonoBehaviour
    {
        /// THIS IS OUR SYNCVAR.
        [SyncVar]
        public float syncedZ;
    
    
        public void FixedUpdate()
        {
            /// We only want to set the value on the MasterClient.
            if (PhotonNetwork.IsMasterClient)
            {
                /// Changes to syncvars only are networked if the master changes them.
                syncedZ = (float)(System.Math.Sin(Time.time) * 720);
            }
    
    
            transform.localEulerAngles = new Vector3(0, 0, syncedZ);
        }
    }
  3. SyncvarTestスクリプトをCubeに追加します。

  4. キューブの位置を(0, 3f, 0)に設定します。

  5. ビルドして実行します。

値はマスタークライアントで設定され、他のクライアントに同期されます。

トップに戻る

SyncVarAttributeの高度な実装

機能は上記と同じですが、いくつかの高度な機能が使用されています。 補間機能が有効になり、Updateごとにリモート値が自動的に補間されるようになりました。

using UnityEngine;
using Photon.Compression;
using Photon.Pun;
using Photon.Pun.Simple;

/// The PackObject attribute tells the code gen engine and the NetObject that this class/struct
/// contains [SyncVar] attributes that should be serialized and synced.
[PackObject]
[RequireComponent(typeof(NetObject))]
public class SyncvarTest : NetComponent
{
    /// THIS IS OUR SYNCVAR.
    [SyncVar(applyCallback = "MyOnApply", snapshotCallback = "MyOnSnapshot", interpolate = true, keyRate = KeyRate.Every10th)]
    public float syncedZ;

    // NOTE: With interpolate enabled, this callback isn't needed for this example.
    // This is just included to show how it would be enabled.
    /// applyCallback fires remotely when the synced value has changed.
    public void MyOnApply(float newValue, float oldValue)
    {
        // This is redundant with the interpolation being true, and values being applied in Update()
        // But is included to show how this callback would normally be used.
        transform.localEulerAngles = new Vector3(0, 0, newValue);
    }

    // NOTE: With interpolate enabled, this callback isn't needed for this example.
    // This is just included to show how it would be enabled.
    /// snapshotCallback fires remotely every simulation tick, whether or not the value changed.
    public void MyOnSnapshot(float snap, float targ)
    {
        /// snapshotCallback gets called every tick, whether the value has changed or not.
        Debug.Log("Applying Syncvar Snapshot " + snap);
    }

    /// We are using NetComponent so we have access to better timing callbacks for networking.
    /// However, this could work in FixedUpdate as well.
    public void FixedUpdate()
    {
        /// We only want to set the value on the MasterClient.
        if (PhotonNetwork.IsMasterClient)
        {
            /// Changes to syncvars only are networked if the master changes them.
            syncedZ = (float)(System.Math.Sin(Time.time) * 720);
        }
    }

    public void Update()
    {
        /// We set interpolate = true for this syncvar,
        /// so it will get modified remotely before every update
        /// to have interpolation automatically applied, using the Snap and Targ values.
        transform.localEulerAngles = new Vector3(0, 0, syncedZ);
    }
}


ドキュメントのトップへ戻る