1. 程式人生 > >Unity 3.Adventure Game tutorial(Event Systems、Animator State Machine、Inventory)

Unity 3.Adventure Game tutorial(Event Systems、Animator State Machine、Inventory)

目錄

The Player

Interact:

The Approach:

The Steps

Event Systems

Animator State Machine

Player Prefab

PlayerMovement script


雙語機翻視訊:

https://www.bilibili.com/video/av34383045/

在官網asset Store下載了完整工程,和pdf

asset Store:https://assetstore.unity.com/account/assets

在AssetStore上下載資源並匯入專案:(my Asset入口)

https://jingyan.baidu.com/article/4f34706e758caee387b56d3e.html

匯入後說Animation Clip __preview__Take 001有負time keys,無法壓縮,可能看起來異常

Lighting data asset ‘LightingData’ 與當前版本不相容。Please use Generate Lighting to rebuild the lighting data.(需要rebuild lighting data)Realtime Global Illumination cannot be used until the lighting data is rebuilt.(否則實時全域性光照Realtime Global Illumination不能使用)

 

目錄

Player Control(點選行走)

         Build a click to move animated character using:

• EventSystem

• NavMesh

• Animator

• Prefabs

Inventory(庫存)

Build a UI and Item Management System for Player Inventory

• UI System

• Editor Scripting

Interaction System(互動系統)

Build a system allowing the Player to interact with the game

• Conditions

    Create a system to check the current game state

• Scripting Patterns

• Scriptable Objects

• Generic Classes(泛型類)

• Inheritance(繼承)

• Extension Methods(擴充套件方法)

• Reactions

    Create a system to perform actions based on condition state

• Polymorphism(多型)

• Further editor scripting

• Serialization(序列化)

• Interactables

    Create a system to define what the player can interact with

• Interactable Geometry

• EventSystem

• Interaction System Summary

Game State(遊戲狀態、改變場景)

         Creating a system to load scenes while preserving game state

• Scene Manager

• ScriptableObjects as temporary runtime data storage(指令碼化物件作為臨時的執行時資料儲存)

• Delegates(委託)

• Lambda Expressions(表示式)

The Player

Event System:點選、對話

Navmesh(導航網格)

Animator(行走動畫)

Goal

INTERACTABLE互動,通過檢測條件觸發不同事件

Scene Management:Load Scene ,Maintain Inventory & Scene State(載入場景並儲存庫存和場景狀態)

 

Understanding the architecture(體系結構) of Scene Loading

Persistent(持久) Sceneà Load Level Additive-Scene 1à Unload Scene- Scene 1

                          à Load Level Additive-Scene 2à Set Active Scene-Scene 2

持久場景load 、unload其他場景

 

Interact:

When the user clicks on the ground, the character must move to that location(點選地面,角色移動到地點)

Interactable objects in the scene will be provided to our team for our character to interact with.

When an Interactable is clicked on, the character should approach the interactionLocation of the Interactable (點選互動物件,到達互動地點)

interactionLocation is a Transform value saved as part of the Interactable

On arrival, the character should match the position and rotation of the interactionLocation and call the Interact function of the Interactable(角色匹配座標與旋轉,呼叫互動函式)

When required, the character must play various animations in response to trigger parameters sent by the Interactables; specifically the supplied trigger parameters: HighTake, MedTake, LowTake and AttemptTake

The character cannot be allowed to move while these animations are playing(動畫播放時,角色不能移動)

P94

The Approach:

NavMesh :to define the walkable areas in the levels(導航網格:定義可行走區域)

Event Systems: to detect and handle user input and scripted interaction(事件系統:檢測處理使用者輸入,指令碼互動)

Animator state machine :to control and play all of the character animations; including idle(閒置), walking and interaction(動畫狀態機:控制、播放所有角色動畫)

Prefab system :to save the character so it can be easily added and used in any scene in the game(可以儲存角色,並放到任意場景)

The Steps

開啟專案

1. With the correct Asset Store package imported:

 1/6 - Adventure Tutorial - The Player

2. Navigate to the Project window(project視窗)

3. Expand the Scenes folder(Scenes資料夾)

4. Open the SecurityRoom scene(雙擊開啟場景)

 

將場景中room物件設為靜態:

1. Navigate to the Hierarchy window(層級視窗)

2. Expand(展開) the SecurityRoom GameObject and select

the SecurityRoomEnvironment GameObject

3. Check the Static checkbox(在Inspector視窗名字旁邊選擇Static複選框設為靜態場景:在上面建立導航網格nav mesh,不移動這些幾何體)

4. Select Yes, change children(將該物件與其子物件全部設為靜態)

 

將一些影響光照的子物件取消靜態(不能走到這些東西上):

1. Expand the SecurityRoomEnvironment

2. Multi-Select the children called:

• BlackUnlit

• FloorLightGlow

• HologramLight

• HologramLight02

• SecurityGateBeams

3. Uncheck the Static checkbox

 

設定nav mesh

1. Open the Navigation window(window-navigation開啟navigation視窗,可以在場景檢視中看到藍色網格)

2. Select the Bake panel

3. Set the Max Slope to 1

4. Set the Step Height to 0.2

5. Under ‘Advanced’ set Height Mesh to true(nav mesh、high mesh可以估測每個部分的高度,更精確地走過顛簸)

6. Press the Bake button(在右下角儲存)

 

1. Navigate to the Inspector window(切換檢視)

2. Save the scene(儲存場景)

 

Event Systems

We need to be able to interact with our environment

• An event system has 3 requirements.(事件系統需要:傳送、接收、管理) Something to -

1. Send events

Physics Raycaster component(觸發事件:物理射線投射元件。附加在camera上,每一幀重新投射進場景,尋找基礎物理物件)

2. Receive events

Colliders & Event Triggers(碰撞器和事件觸發器,碰撞器hip with Raycaster後,向事件觸發器發出訊號)

3. Manage events

The EventSystem

 

建立EventSystem管理事件(Manage events):

1. Navigate to the Hierarchy

2. Create > UI > Event System(新增Event System物件)

3. Add an AudioListener component(在該物件上新增元件,作為event system的監聽者。在實際專案中放在永續性場景,監聽所有場景,而不在每個場景中建立 )

4. Save the scene

 

建立Send events:

1. Expand the SecurityRoom and CameraRig GameObjects

2. Select the Camera GameObject

3. Add a Physics Raycaster component.(在相機上新增Physics Raycaster元件,查詢元件:Phy或在event目錄下)- Make sure this is not a Physics 2D Raycaster

 

建立Receive events:

1. Select the SecurityRoom GameObject

2. Add a MeshCollider component(在SecurityRoom增加網格碰撞器)

3. Set the Mesh property to SecurityRoomMeshCollider(設定元件下的網格屬性,為該資源)

1. Add an EventTrigger component(在SecurityRoom增加事件觸發器)

2. Click Add New Event Type and select (建立Pointer Click型別的Event)

3. Click the + button to add an event(新增新事件留著引用指令碼)

4. Leave the event empty!

5. Save the scene

Animator State Machine

處理玩家本身和它的動畫狀態

 

新增Animator Controller:

1. Navigate to the Project window

2. With the Animators > Player folder selected, create an Animator Controller

(在工程視窗的Animators >Player資料夾建立動畫控制器(Animator Controller))

3. Name it ClickToMove

 

建立引數

1. Open the Animator window(雙擊Animator Controller檔案)

2. Select the Parameters panel

3. To create a new Parameter, select the + dropdown menu

4. Create a float parameter and name it Speed

1. Create 4 trigger parameters and name them:

• AttemptTake

• HighTake

• MedTake

• LowTake

Animator Controller決定什麼時候,播放哪些動畫,移動速度

引數拼寫很重要,將匹配其他指令碼和material

 

1. Navigate to the Layout area(指網格區域)

2. Right-click on the background (在空白處右擊)and select:

 Create State > From New Blend Tree(融合樹)

3. Select the new Blend Tree

4. In the Inspector window, name the state Walking

5. Double click on the state to edit the blend tree

 

1. Click on BlendTree

2. Rename BlendTree to WalkingBlendTree

3. To make a new Motion Field, click the + button and

select Add Motion Field

4. Repeat this 2 more times to make a total of

3 Motion Fields in all

 

1. Using Circle Select find & assign:(圓形按鈕,新增引用)

• PlayerIdleBlender

• PlayerWalk

• PlayerRun

(當速度低於行走速度閾值時,將行走於閒置融合)

 

1. Uncheck Automate Thresholds(取消下方自動處理閾值複選框)2. Click on the Compute Thresholds dropdown menu

3. Select Speed(不是設定,而是一次計算,改變值後可再一次選擇它計算,選擇Automate Thresholds相當於重置)4. Return to Base Layer using Breadcrumb

Route motion 路線運動:每個animation也可以讓角色移動

速度speed可以控制動畫播放的速度

 

新增動畫:

1. Navigate to the Project window

2. Expand the Animations > Player folder

1. Select Idle, TakeObjectAttempt & TakeObjects(同時選擇這三個檔案)

2. Drag these into Animator window(拖進網格視窗)

3. Arrange Animations as shown:

 

新增狀態轉變Transition:

1. Right click on Walking

2. Select Make Transition(右擊新建狀態轉變)

3. Left click on PlayerIdle

This makes a Transition from Walking to PlayerIdle

4. Make a Transition from PlayerIdle back to Walking

1. Make Transitions from Any State to each of the

PlayerTakeObject... states:

• Attempt

• High

• Mid

• Low

2. Make Transitions from each of the PlayerTakeObject...states to Walking

 

設定Transition觸發條件:

1. Select the Transition from Walking to PlayerIdle

2. Uncheck has exit time(動畫完成退出時間)

3. Under the condition list click the + button to add a

condition and set the parameters as:(新增速度範圍作為條件)

• Speed (already set)

• Less

• 0.1

1. Select the Transition from PlayerIdle to Walking

2. Uncheck has exit time

3. Under the condition list click the + button to add a

condition

• Speed (already set)

• Greater (already set)

• 0.1

1. Select each of the Transitions from Any State to each of the PlayerTakeObject... states

2. Add a new condition and set the parameter the appropriate trigger using the parameter dropdown:(發生事件時觸發,預設播放完畢後自動轉為walking)

• AttemptTake

• HighTake

• MedTake

• LowTake

 

1. Select PlayerIdle

2. Set the tag to Locomotion(移動)

3. Select Walking

4. Set the tag to Locomotion

5. Navigate to the Scene window

6. Save the scene

Player Prefab

拿出player模型:

1. Navigate to the Project window

2. Expand the Models folder

3. Drag the Player model asset into the Hierarchy

4. Set the Layer on the Player GameObject to Character(Layer屬性在Tag右側)

5. Set Position -0.7, 0.0, 3.5

6. Set the Rotation 0.0, 180, 0.0

 

設定Animator元件屬性:

1. Using Circle select - set Controller to ClickToMove(在Animator元件的Controller屬性框)

2. Add a new component: NavMeshAgent

3. Change the Speed property to 2

4. Change the Acceleration(加速度) property to 20

5. Change the Stopping Distance to 0.15(到目的地前的減速距離)

 

新增指令碼,放入預製件:

1. Select and Drag the Player GameObject to the Project window > Prefabs folder

2. Navigate to Scripts/Monobehaviours/Player folder

3. Create a new C# Script called PlayerMovement

4. Drag the PlayerMovement script onto the Player Prefab

5. Open the PlayerMovement script for editing

 

PlayerMovement script

https://www.bilibili.com/video/av34383045/?p=2

pdf:P139

Scripts/Monobehaviours/Player folder

建立PlayerMovement指令碼,新增到Player(預製件,而非場景中的示例)

指令碼控制Player瞄準目的地移動, 由導航網格(nac mesh驅動)

同時控制動畫,在接近目的地時放慢

編寫指令碼:

需要包含一個新的namespace:using UnityEngine.EventSystems;

(在Unity5.5之後,需要加上: using UnityEngine.AI;

需要引用一個animator、nav mesh agent(導航網格代理)

需要知道要到多遠去

不允許agent旋轉角色:agent.updateRotation = false;

在互動時禁止移動:co-routine

確定角色要等待多久

確定玩家目的地:儲存玩家目的地位置的Vector3

靠近目的地時停止,在那時的第一幀將速度設為很小

 

新建控制角色如何移動的函式:OnAnimatorMove

結合animator與網格代理的移動:基於動畫播放速度,設定導航網格代理的速度-route motion:

agent.velocity = animator.deltaPosition / Time.deltaTime;

.deltaPosition:角色這一幀移動距離

.deltaTime:兩幀之間時間差

V=s/t

 

還需要slowing、stopping

確定是否要停止:呼叫private void Stopping

需要控制的引數:(out float speed)

 

類似地,函式Slowing需要傳入out float speed,

需要判斷目的地距離,傳入float distanceToDestination

旋轉角色:private void Moving ()

 

在Update函式中:

agent.pathPending代表網格代理正在計算path。這時直接返回

否則已經有path

需要知道沿path走多快

Agent有兩個速度:實際、將要

float speed = agent.desiredVelocity.magnitude;

magnitude(幅度)

依次檢查是否需要停止、減速、移動

確定停止距離比例常量:private const float stopDistanceProportion = 0.1f;

if (agent.remainingDistance <= agent.stoppingDistance * stopDistanceProportion)

            Stopping (out speed);

確保轉身之前速度夠快:speed > turnSpeedThreshold

(轉身速度閾值)

 

需要設定Animator速度(需要字串匹配,可以用整數代替)

宣告只讀整數(只讀整數為雜湊值):private readonly int hashSpeedPara = Animator.StringToHash("Speed");

Speed要匹配animator中的引數

設定變速時間(Damp time of speed)預設值:public float speedDampTime = 0.1f;

animator.SetFloat(hashSpeedPara, speed, speedDampTime, Time.deltaTime);

 

Stopping函式中:

停止網格代理:agent.Stop();

固定精確位置:transform.position = destinationPosition;

設定速度:speed = 0f;

 

Slowing函式中:

停止網格代理,

自己定義對位置的控制,漸漸移動:Vector3.MoveTowards(當前位,目標位,速度)

transform.position = Vector3.MoveTowards(transform.position, destinationPosition, slowingSpeed * Time.deltaTime);

定義slowingSpeed

 

計算速度:????????

比例(1-距/停止距):float proportionalDistance = 1f - distanceToDestination / agent.stoppingDistance;

線性插值:speed = Mathf.Lerp(slowingSpeed, 0f, proportionalDistance);

 

Moving函式:

完成旋轉

得到目標旋轉值:Quaternion targetRotation = Quaternion.LookRotation(agent.desiredVelocity);

在當前、目標旋轉值間以速度旋轉transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, turnSmoothing * Time.deltaTime);

 

OnGroundClick函式:

處理點選地面-public void OnGroundClick(BaseEventData data)

BaseEventData有此次點選時發生事件的資料

轉換型別:PointerEventData pData = (PointerEventData)data;

在導航網格上找到最接近點選處的點:

需要距離private const float navMeshSampleDistance = 4f:

NavMesh.SamplePosition (pData.pointerCurrentRaycast.worldPosition, out hit, navMeshSampleDistance, NavMesh.AllAreas)

引數:欲到達的世界座標系中一個點,返回所有資訊的接收變數,sample結束的距離,導航網格中可以用的區域

設定目標位置為hit位置:destinationPosition = hit.position;

若無hit位置則為最接近的位:destinationPosition = pData.pointerCurrentRaycast.worldPosition;

讓導航網格代理使用該位置:agent.SetDestination(destinationPosition);

恢復代理(之前用.Stop停止過):agent.Resume ();

 

Interact互動變數還未使用

 

1. Select the Player Prefab

2. On the PlayerMovement component:

• Setup the reference to the Player's Animator

• Setup the reference to the Player's NavMeshAgent

在預製件中的Player的PlayerMovement元件中填充animator、agent引用預製件中的Player

 

1. Navigate to the Hierarchy

2. Select SecurityRoom GameObject

3. Find the Event Trigger

4. Drag the Player GameObject from the Hierarchy onto

the object field of the Event Trigger

5. Select PlayerMovement.OnGroundClick()

Event trigger引用:

在層級目錄中,SecurityRoom的元件Event trigger,使用player的例項,呼叫PlayerMovement中的OnGroundClick

room的碰撞器將觸發Event Trigger,找到玩家和該方法

 

Test

 

在前往時,確定什麼是可互動的(interactable)

建立變數儲存他們:private Interactable currentInteractable;

當到達目的地時,使用他們互動

 

Stopping函式中:

判斷可互動

if (currentInteractable)

        {

面朝互動方向:transform.rotation = currentInteractable.interactionLocation.rotation;

            currentInteractable.Interact();

確保互動只被呼叫一次:currentInteractable = null;

            StartCoroutine (WaitForInteraction ());

        }

 

Bool handleInput只有在互動時才處理輸入

判斷是否可以移動,動畫機是否在運動狀態(locomotion)

-使用雜湊方法:

private readonly int hashLocomotionTag = Animator.StringToHash("Locomotion");

 

協程處理要交互發生需等待時間:

private IEnumerator WaitForInteraction ()

    {

等待時不獲取任何輸入:handleInput = false;

單位為秒:yield return inputHoldWait;

當不在運動狀態就等待,(0為基礎層),與快取的運動標籤不同,則等待一幀:while (animator.GetCurrentAnimatorStateInfo (0).tagHash != hashLocomotionTag)

        {

            yield return null;

        }

        handleInput = true;

    }

 

Stop中呼叫協程:StartCoroutine (WaitForInteraction ());

Slowing中平滑改變選擇角度(而不在Stop中突然改變):

如果是可互動的,旋轉,否則維持當前旋轉角度:Quaternion targetRotation =

 currentInteractable ? currentInteractable.interactionLocation.rotation : transform.rotation;

transform.rotation =

 Quaternion.Lerp(transform.rotation, targetRotation, proportionalDistance);

 

點選可互動物體時:

public void OnInteractableClick(Interactable interactable)

    {

保證可處理輸入:if(!handleInput)

            return;

儲存當前物品的可互動性:currentInteractable = interactable;

設定目的地:destinationPosition = currentInteractable.interactionLocation.position;

使用導航代理:agent.SetDestination(destinationPosition);

        agent.Resume ();

}

 

在OnGroundClick中:

無法處理輸入時,點選地面同樣無效果:if(!handleInput) return;

當點選可互動物後,又點選地面,改變主意:currentInteractable = null;

Working with Interactables

1. Interactables, along with Conditions and Reactions,(可互動物,有條件、反應)

have been supplied to our team

2. We simply need to set them up to work with our new Player click to move system

3. Note: We will be taking on the role of developing these systems later in the session

 

設定Event Trigger:

1. Select PictureInteractable(在層級目錄中)

2. Find the Event Trigger component

3. Drag the Player GameObject from the Hierarchy onto the

object field of the Event Trigger

4. Select PlayerMovement.OnInteractableClick()

觸發的事件與地面不同

5. Drag the Interactable GameObject or the Interactable

component below onto the EventTrigger's Parameter field

(OnInteractableClick需要傳入引數,將下方的指令碼拽入引數欄位)

PlayerMovement.cs:

using System.Collections;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.EventSystems;
public class PlayerMovement : MonoBehaviour
{
    public Animator animator;
    public NavMeshAgent agent;
    public float turnSmoothing = 15f;
    public float speedDampTime = 0.1f;
    public float slowingSpeed = 0.175f;
    public float turnSpeedThreshold = 0.5f;
    public float inputHoldDelay = 0.5f;
    
    private Interactable currentInteractable;
    private Vector3 destinationPosition;
    private bool handleInput = true;
    private WaitForSeconds inputHoldWait;
    private readonly int hashSpeedPara = Animator.StringToHash("Speed");
    private readonly int hashLocomotionTag = Animator.StringToHash("Locomotion");
    public const string startingPositionKey = "starting position";
    private const float stopDistanceProportion = 0.1f;
    private const float navMeshSampleDistance = 4f;
    private void Start()
    {
        agent.updateRotation = false;
        inputHoldWait = new WaitForSeconds (inputHoldDelay);
        destinationPosition = transform.position;
    }
    private void OnAnimatorMove()
    {
        agent.velocity = animator.deltaPosition / Time.deltaTime;
    }
    private void Update()
    {
        if (agent.pathPending)
            return;
        float speed = agent.desiredVelocity.magnitude;
        
        if (agent.remainingDistance <= agent.stoppingDistance * stopDistanceProportion)
            Stopping (out speed);
        else if (agent.remainingDistance <= agent.stoppingDistance)
            Slowing(out speed, agent.remainingDistance);
        else if (speed > turnSpeedThreshold)
            Moving ();
        
        animator.SetFloat(hashSpeedPara, speed, speedDampTime, Time.deltaTime);
    }
    private void Stopping (out float speed)
    {
        agent.Stop();
        transform.position = destinationPosition;
        speed = 0f;
        if (currentInteractable)
        {
            transform.rotation = currentInteractable.interactionLocation.rotation;
            currentInteractable.Interact();
            currentInteractable = null;
            StartCoroutine (WaitForInteraction ());
        }
    }
    private void Slowing (out float speed, float distanceToDestination)
    {
        agent.Stop();
        float proportionalDistance = 1f - distanceToDestination / agent.stoppingDistance;
        Quaternion targetRotation = currentInteractable ? currentInteractable.interactionLocation.rotation : transform.rotation;
        transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, proportionalDistance);
        transform.position = Vector3.MoveTowards(transform.position, destinationPosition, slowingSpeed * Time.deltaTime);
        speed = Mathf.Lerp(slowingSpeed, 0f, proportionalDistance);
    }
    private void Moving ()
    {
        Quaternion targetRotation = Quaternion.LookRotation(agent.desiredVelocity);
        transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, turnSmoothing * Time.deltaTime);
    }
    public void OnGroundClick(BaseEventData data)
    {
        if(!handleInput)
            return;
        
        currentInteractable = null;
        PointerEventData pData = (PointerEventData)data;
        NavMeshHit hit;
        if (NavMesh.SamplePosition (pData.pointerCurrentRaycast.worldPosition, out hit, navMeshSampleDistance, NavMesh.AllAreas))
            destinationPosition = hit.position;
        else
            destinationPosition = pData.pointerCurrentRaycast.worldPosition;
        agent.SetDestination(destinationPosition);
        agent.Resume ();
    }
    public void OnInteractableClick(Interactable interactable)
    {
        if(!handleInput)
            return;
        currentInteractable = interactable;
        destinationPosition = currentInteractable.interactionLocation.position;
        agent.SetDestination(destinationPosition);
        agent.Resume ();
    }
    private IEnumerator WaitForInteraction ()
    {
        handleInput = false;
        yield return inputHoldWait;
        while (animator.GetCurrentAnimatorStateInfo (0).tagHash != hashLocomotionTag)
        {
            yield return null;
        }
        handleInput = true;
    }
}

Inventory(庫存物品欄)

P156

https://www.bilibili.com/video/av34383045/?p=3

Brief

Create a simple inventory system with persistent content that is not lost during scene changes

Inventory Items should be extensible if the design changes可擴充套件的

two public functions: AddItem & RemoveItem兩個公共方法

Simplify and improve the workflow of the project in the Inspector with regards to the Inventory and its Items簡化、提升工作流

The Approach:

Use the UI system to display the inventory to the user用UI展示庫存

Use ScriptableObjects to make a simple Item class which defines every possible inventory item and can easily be extended and referenced by the Inventory構建Item類,定義可能的庫存項,使能被Inventory引用

Create a custom inspector for the Inventory to improve the workflow of the project

The Steps

1. Navigate to the Scenes folder

2. Open the Persistent scene

3. Set the Scene view to 2D mode(Scene檢視上側的2D按鈕)

4. Navigate to the Game view

5. Set the Aspect Ratio(長寬比) to 16:9

6. Select and frame the PersistentCanvas

Understanding the UI in the Hierarchy Window

1. The order of UI Elements in the Hierarchy window informs the UI system what order to render the UI Elements(渲染UI元素)

2. The rendering order is from the top to the bottom which will render on screen from the back to the front(渲染次序從上到下,從後到前)

 

1. Navigate back to the Scene view

2. With the PersistentCanvas selected:Create an empty child GameObject

3. Name this new GameObject Inventory(在PersistentCanvas建立空遊戲物件Inventory)

4. Make sure that it is the first child of PersistentCanvas and that it is above FadeImage(確認排列為第一個子物件)

 

1. Create a child of Inventory called ItemSlot(Inventory下建立子物件ItemSlot)

2. As a child of ItemSlot, Create a new UI > Image GameObject(在ItemSlot建立UI > Image物件)

3. Duplicate the Image GameObject(複製)

4. Name the first child Image BackgroundImage

5. Name the second ItemImage

 

1. Select the BackgroundImage GameObject

2. Set the Image component’s Source Image to InventorySlotBG(BackgroundImage在Image元件設定影象源)

3. Select the ItemImage GameObject

4. Disable the Image component(ItemImage禁用Image元件)

 

1. Drag the ItemSlot GameObject into the Prefabs folder to make it a prefab(ItemSlot拖入預製件)

2. Return to the Hierarchy window

3. Duplicate the ItemSlot GameObject 3 times so there are 4 ItemSlots in total(複製出四個ItemSlot槽)

4. Name them: ItemSlot0, ItemSlot1, ItemSlot2 and ItemSlot3

 

1. Select the Inventory GameObject

2. Add a Vertical Layout Group component(在Inventory新增元件Vertical Layout Group)

 

1. Find the Inventory’s Rect Transform component

2. Set the width to 135 and the height to 600

3. From the anchor selection dropdown, choose middle-right

4. Set the position to -95, 0, 0

 

Item script

Inventory script

P184

 

 

 

 

 

 

 

在寫for後按兩下Tab,能自動出完整迴圈