今回は宝箱からアイテムを受け取るデモを見ていきます。
初めに使用する無料アセットを3つインポートします。
まずはスタンダードアセットです。
公式ページ に進み「Add to My Assets」をクリックしてください。サインインが求められた場合はそれに従ってください。その後「Open in Unity」ボタンをクリックしてダウンロードしてください。
UnityでPackage Managerを開きStandardAssetをインポートします。
(※必要な物は一部ですが、念のため全てインポートします)
「Assets/StandardAssets/Utility/SimpleActivatorMenu」の(恐らく)11行目の
GUIText を
UnityEngine.UI.Text に変更して下さい。
次はUnity-Chanをインポートします。StandardAssetの時と同様、
公式ページ からインポートしてください。
最後に宝箱のモデルです。
公式ページ から
下の図のように一部を選んで インポートしてください。
次に用いる地形をダウンロードします。以下のボタンからプレハブをダウンロードしてください
terrain.unitypackageそしてこのファイルをUnityのプロジェクト上の好きな場所にD&D(インポート)します。
いまインポートした「FlMr_Terrain_Prefabs/」フォルダの「Terrain」プレハブをシーン上にD&Dしてください。
さらに「unity-chan!/Unity-chan! Model/Prefabs/」フォルダの「unitychan_dynamic」プレハブもシーンに追加します。
私の画面では、位置を (x, y, z) = (40, 6.4, 55)に指定しています。
次にUnity-Chanのコンポーネントの調節です。まず初めにTagを「Player」に変更します。そして「IdleChanger」「FaceUpdate」コンポーネントを非アクティブ(チェックを外す)にしてください。そして「ThirdPersonUserControl」を追加します。そして勝手についてきた「ThirdPersonUser
Character 」コンポーネントの「GroundCheckDistance」を0.3に変更します。次に「Animator」コンポーネントのControlerを「ThirdPersonAnimatorController」に変更してください。
最後に当たり判定のサイズを調節します。次の画像のようにUnity-Chanにピッタリのサイズに変更してください。
次にカメラです。シーン上のカメラオブジェクトに「SmoothFollow」コンポーネントを追加し、Targetをシーン上の「unitychan_dynamic/mesh_root/」の子オブジェクトの「hair_front」を指定します。さらにDistanceを5、Heightを2、HeightDampingを5に変更します。
ここで動作確認をしてください。WASD又は矢印キーで操作できるようになったと思います。カメラの向きを変更することはできませんが、脱線が過ぎることを考えてここでは解説しません。
次に宝箱です。「FS Loot Boxes/Assets/Prefabs/」フォルダ内のプレハブをシーンに追加してください。次に追加したオブジェクトのコンポーネントを次の図のように変更します。
さらに、RigidBodyコンポーネントのIs Kinematicにチェックを入れます。
次にスクリプトをいじります。「FS Loot Boxes/Assets/Scripts/」フォルダのLootBoxスクリプトを、次のコードで置き換えます。
LootBox.cs
// © 2019 Flying Saci Game Studio
// written by Sylker Teles
using System;
using UnityEngine;
using FlMr_Inventory;
/// <summary>
/// These are the ways you can open the box.
/// </summary>
public enum OpeningMethods { OpenOnCollision, OpenOnKeyPress, OpenOnTouch }
/// <summary>
/// Loot Box class.
/// </summary>
public class LootBox : MonoBehaviour , ISerializationCallbackReceiver
{
[ SerializeField ] private string lootId;
/// <summary>
/// The loot GameObject prefab.
/// </summary>
[ SerializeField ] private ItemBase boxContents;
public void OnBeforeSerialize ( )
{
if ( string .IsNullOrEmpty(lootId))
{
lootId = Guid.NewGuid().ToString();
}
}
public void OnAfterDeserialize ( )
{
if ( string .IsNullOrEmpty(lootId))
{
lootId = Guid.NewGuid().ToString();
}
}
/// <summary>
/// How should the player open the box?
/// </summary>
public OpeningMethods openingMethod;
/// <summary>
/// You can use a tag for the player that can open the box.
/// </summary>
public string playerTag = "Player" ;
/// <summary>
/// You can also use a key to open the box. Player must be close.
/// </summary>
public KeyCode keyCode = KeyCode.Space;
/// <summary>
/// Activates the leaping animation.
/// </summary>
public bool bouncingBox = true ;
/// <summary>
/// Close the box after player goes away
/// </summary>
public bool closeOnExit;
/// <summary>
/// Flags when player is close enough to open the box.
/// </summary>
private bool isPlayerAround;
/// <summary>
/// Flags when the box is open avoiding opening it twice.
/// </summary>
/// <value> <c> true </c> if is open; otherwise, <c> false </c> . </value>
public bool isOpen { get ; set ; }
/// <summary>
/// The box animator for leaping, open and close animations.
/// </summary>
Animator animator;
/// <summary>
/// You can call OnBoxOpen and OnBoxClose as events, for
/// instance, you can get what's inside the box.
/// </summary>
protected virtual void OnBoxOpen ( )
{
if (boxContents == null ) return ;
var bag = GameObject.FindGameObjectWithTag( "playerBag" ).GetComponent<ItemBag>();
bag.AddItem(boxContents.UniqueId, 1 );
}
// Start is called before the first frame update
void Start ( )
{
// gets the animator
animator = GetComponent<Animator>();
// set the animation to bounce or not
BounceBox(bouncingBox);
}
/// <summary>
/// Update this instance.
/// </summary>
private void Update ( )
{
// when player is close enough to open the box
if (isPlayerAround)
{
// in case of Key Press method for opening the box,
// waits for a key to be pressed
if (Input.GetKey(keyCode)) Open();
}
}
/// <summary>
/// Bounces the box.
/// </summary>
/// <param name="bounceIt"> If set to <c> true </c> bounce it. </param>
public void BounceBox ( bool bounceIt )
{
// flag the animator property "bounce" accordingly
if (animator) animator.SetBool( "bounce" , bounceIt);
}
/// <summary>
/// Open the box.
/// </summary>
public void Open ( )
{
// avoid opening when it's already open
if (isOpen) return ;
isOpen = true ;
// play the open animation
if (animator) animator.Play( "Open" );
// calls the OnBoxOpen event and deliver the
// earned GameObjects on temp list
OnBoxOpen();
}
/// <summary>
/// Close the box
/// </summary>
public void Close ( )
{
// avoid closing when it's already open
if (!isOpen) return ;
isOpen = false ;
// play the close animation
if (animator) animator.Play( "Close" );
}
/// <summary>
/// When player touches or click on the treasure box
/// </summary>
private void OnMouseDown ( )
{
// checks if the opening method is OpenOnTouch
if (openingMethod != OpeningMethods.OpenOnTouch) return ;
// Open the box.
Open();
}
/// <summary>
/// When something hits our treasure box.
/// </summary>
/// <param name="collision"> Collision. </param>
private void OnCollisionEnter ( Collision collision )
{
// OnCollisionMethod is not for OpenOnTouch method
if (openingMethod == OpeningMethods.OpenOnTouch) return ;
// check if the hitting object is our player
if (collision.gameObject.tag == playerTag)
{
// if the method is OpenOnKeyPress, let's just flag the player as close
if (openingMethod == OpeningMethods.OpenOnKeyPress) isPlayerAround = true ;
// otherwise, open the box.
else Open();
}
}
/// <summary>
/// When player goes away from box.
/// </summary>
/// <param name="collision"> Collision. </param>
private void OnCollisionExit ( Collision collision )
{
// flag the player as away.
isPlayerAround = false ;
// if the box is suppose to close on exit, close it
if (closeOnExit) Close();
}
}
今回はソースコードの説明は省きますが、基本的に変更した箇所は 88-93 行目です。このメソッドは宝箱が開かれた際に呼ばれます。
boxContents は宝箱で得られるアイテムです。これが
null の場合は何も起きません。
null では無い場合は「playerBag」タグが付いたアイテムバッグを探し、アイテムを追加します。
最後に、シーン上の「Canvas/ItemBag」オブジェクトのタグを変更します。まずは新しく「playerBag」タグを追加してください。
そして「Canvas/ItemBag」オブジェクトのタグを「playerBag」に変更します。
実行して宝箱に近づいてください。自動的に宝箱が開くことが確認できると思います。
そして宝箱にコンポーネントの「Box Contents」に今まで作成してきたアイテムを追加してください。
シーン上のInventoryTestを非アクティブにしたあと、再度宝箱に近づいてみて下さい。ゲーム開始時の持ち物は空ですが、宝箱を開けるとアイテムが一つ獲得できるはずです。