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

版权声明:本文为博主原创文章,转载请声明原创网址。 https://blog.csdn.net/lagoon_lala/article/details/84556441

目录

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,能自动出完整循环

猜你喜欢

转载自blog.csdn.net/lagoon_lala/article/details/84556441
今日推荐