1、目标
当点击库存栏上可以carry的道具时,首先arms替换为carry状态,同时手上拿着被点击的道具。当再次点击同一个道具时,ams替换为idle状态,手上放下之前的道具。
这个最主要的是要学会使用AnimatorOverrideController类。
2、概念
AnimatorOverrideController类:用于控制动画其重写控制器的接口。
动画器重写控制器的用途是重写某个控制器的动画剪辑,从而为给定化身定制动画。在运行时基于相同的AnimatorController交换Animator.runtimeAnimatorController和AnimatorOverrideController不会重置状态机的当前状态。
(1)一般使用方法
定义变量:AnimatorOverrideController animatorOverrideController;
初始化变量:animatorOverrideController = new AnimatorOverrideController(animator.runtimeAnimatorController);
animator.runtimeAnimatorController = animatorOverrideController;
通过上面的赋值,后续对animatorOverrideController的修改将直接作用于animator.runtimeAnimatorController(运行态的动画控制器)。
运行中更新动画:animatorOverrideController["shot"] = weaponAnimationClip[weaponIndex];
(2)每帧更新多个动画剪辑
使用AnimatorOverrideController.ApplyOverrides方法,它能够将动画器剪辑绑定重新分配的数量减少到每次调用只有一个。
定义新老动画的映射:List<KeyValuePair<AnimationClip, AnimationClip>> clipOverrides;
初始化:animatorOverrideController.GetOverrides(clipOverrides);
运行中更新动画:animatorOverrideController.ApplyOverrides(clipOverrides);
其中ApplyOverrides函数:对该动画器重写控制器应用写列表
GetOverrides函数:获取该动画器重写控制器中当前定义的动画剪辑重写的列表。
3、思路
首先,创建SO_AnimationType类描述所有的动画剪辑。
其次,创建CharacterAttribute类定义想要替换的动画信息。
然后,基于AnimatorOverrideController类,根据CharacterAttribute类定义的动画信息,将Player下所有当前状态的动画替换为CharacterAttribute类定义的动画。
最后,如果是carry状态,给Player下的equippedItem对象赋以点击道具的图像。
4、创建可交互的动画的描述类
在Assets -> Scripts -> Animation下创建SO_AnimationType.cs脚本。
[CreateAssetMenu(fileName = "so_AnimationType", menuName = "Scriptable Objects/Animation/Animation Type")]
public class SO_AnimationType : ScriptableObject
{
public AnimationClip animationClip; // a reference to the actual animation clip 动画剪辑
public AnimationName animationName; // an enum of the animation name like "AnimationName.IdleUp" 动画名称
public CharacterPartAnimator characterPart; // the gameobject name the Animator is on that controls these animation clips e.g. "arms" 动画位置对象
public PartVariantColour partVariantColour; // to enable colour variations on a animation type to be specified e.g. "none", "bronze", "silver", "gold" 动画颜色变化
public PartVariantType partVariantType; // the variant type to specify what variant this animation type refers to e.g. "none", "carry", "hoe", "pickaxe", "axe"..etc 动画类型
}
5、创建一个角色属性结构描述想要交换的动画
在Assets -> Scripts -> Animation 下创建CharacterAttribute.cs脚本,目标动画剪辑的属性结构。
[System.Serializable]
public struct CharacterAttribute
{
public CharacterPartAnimator characterPart; // 示例: CharacterPartAnimator.arms 动画位置对象
public PartVariantColour partVariantColour; // 示例: ParVariantColour.none 动画颜色变化
public PartVariantType partVariantType; // 示例: PartVariantType.carry 动画类型
public CharacterAttribute(CharacterPartAnimator characterPart, PartVariantColour partVariantColour, PartVariantType partVariantType)
{
this.characterPart = characterPart;
this.partVariantColour = partVariantColour;
this.partVariantType = partVariantType;
}
}
6、创建Enum对象
在Assets -> Scripts -> Enums -> Enums.cs 中增加如下信息:
public enum AnimationName
{
idleDown,
idleUp,
idleLeft,
idleRight,
walkUp,
walkDown,
walkLeft,
walkRight,
runUp,
runDown,
runLeft,
runRight,
useToolUp,
useToolDown,
useToolLeft,
useToolRight,
swingToolUp,
swingToolDown,
swingToolLeft,
swingToolRight,
liftToolUp,
liftToolDown,
liftToolLeft,
liftToolRight,
holdToolUp,
holdToolDown,
holdToolLeft,
holdToolRight,
pickUp,
pickDown,
pickLeft,
pickRight,
count
}
public enum CharacterPartAnimator
{
body,
arms,
hair,
tool,
hat,
count
}
public enum PartVariantColour
{
none,
count
}
public enum PartVariantType
{
none,
carry,
hoe,
pickaxe,
axe,
scythe,
wateringCan,
count
}
7、创建动画重写控制器AnimationOverrides
流程:
1)创建2个动画剪辑的映射,第1个是 动画剪辑 到 动画描述类的映射,第2个是 动画表示名 到 动画描述类的映射。
2)通过配置的动画描述信息,分别填充上一步的两个映射表。
3)输入characterAttributesList,需要的动作的动画描述信息,比如partVariantType为carry的动画描述。
4)根据characterPart(比如arm)扫描当前角色下已有的动画剪辑,找到characterPart这个名称的动画剪辑为currentAnimator
5)找到characterPart对应controller下所有的动画剪辑,得到animationsList列表
我们找到了arms的animatorController,
再点击进入控制器的Run分类,
点击RunRight,其对应的动画剪辑为ArmsNoneNoneRunRight = characterPart + partVariantColour + partVariantType + animationName。
6)在animationsList列表中,依次遍历得到动画剪辑animationClip对应的动画描述类so_AnimationType(已有的动画)
7)然后根据characterAttribute(目标动画属性结构)中的信息+ 动画名称(比如RunRight)搜索目标动画剪辑swapSO_AnimationType
8)然后将animationClip 和 swapSO_AnimationType.animationClip的动画剪辑KeyValuePair<AnimationClip, AnimationClip>结构的animsKeyValuePairList中
9)通过aoc.ApplyOverrides让这些动画剪辑替换生效。
代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AnimationOverrides : MonoBehaviour
{
[SerializeField] private GameObject character = null;
[SerializeField] private SO_AnimationType[] soAnimationTypeArray = null;
private Dictionary<AnimationClip, SO_AnimationType> animationTypeDictionaryByAnimation;
private Dictionary<string, SO_AnimationType> animationTypeDictionaryByCompositeAttributeKey;
private void Start()
{
// Initialise animation type dictionary keyed by animation clip
animationTypeDictionaryByAnimation = new Dictionary<AnimationClip, SO_AnimationType>();
foreach(SO_AnimationType item in soAnimationTypeArray)
{
animationTypeDictionaryByAnimation.Add(item.animationClip, item);
}
// Initialise animation type dictionary keyed by string
animationTypeDictionaryByCompositeAttributeKey = new Dictionary<string, SO_AnimationType>();
foreach (SO_AnimationType item in soAnimationTypeArray)
{
string key = item.characterPart.ToString() + item.partVariantColour.ToString() + item.partVariantType.ToString() + item.animationName.ToString();
animationTypeDictionaryByCompositeAttributeKey.Add(key, item);
}
}
public void ApplyCharacterCustomisationParameters(List<CharacterAttribute> characterAttributesList)
{
// Loop through all character attributes and set the animation override controller for each
foreach (CharacterAttribute characterAttribute in characterAttributesList)
{
Animator currentAnimator = null;
List<KeyValuePair<AnimationClip, AnimationClip>> animsKeyValuePairList = new List<KeyValuePair<AnimationClip, AnimationClip>>();
string animatorSOAssetName = characterAttribute.characterPart.ToString();
// Find animators in scene that match scriptable object animator type
Animator[] animatorArray = character.GetComponentsInChildren<Animator>();
foreach (Animator animator in animatorArray)
{
if (animator.name == animatorSOAssetName)
{
currentAnimator = animator;
break;
}
}
// Get base current animations for animator
AnimatorOverrideController aoc = new AnimatorOverrideController(currentAnimator.runtimeAnimatorController);
List<AnimationClip> animationsList = new List<AnimationClip>(aoc.animationClips);
foreach (AnimationClip animationClip in animationsList)
{
// find animation in dictionary
SO_AnimationType so_AnimationType;
bool foundAnimation = animationTypeDictionaryByAnimation.TryGetValue(animationClip, out so_AnimationType);
if (foundAnimation)
{
string key = characterAttribute.characterPart.ToString() + characterAttribute.partVariantColour.ToString() +
characterAttribute.partVariantType.ToString() + so_AnimationType.animationName.ToString(); // 目标动画string
SO_AnimationType swapSO_AnimationType;
bool foundSwapAnimation = animationTypeDictionaryByCompositeAttributeKey.TryGetValue(key, out swapSO_AnimationType);
if (foundSwapAnimation)
{
AnimationClip swapAnimationClip = swapSO_AnimationType.animationClip;
animsKeyValuePairList.Add(new KeyValuePair<AnimationClip, AnimationClip>(animationClip, swapAnimationClip));
}
}
}
// Apply animation updates to animation override controller and then update animator with the new controller
aoc.ApplyOverrides(animsKeyValuePairList);
currentAnimator.runtimeAnimatorController = aoc;
}
}
}
8、修改Player.cs脚本
创建相关的变量:
private AnimationOverrides animationOverrides; // 动画重写控制器
private List<CharacterAttribute> characterAttributeCustomisationList; // 目标动作列表
[Tooltip("Should be populated in the prefab with the equippped item sprite renderer")]
[SerializeField] private SpriteRenderer equippedItemSpriteRenderer = null; // 武器的图片
在Awake中初始化相关变量:
// Initialise swappable character attributes
armsCharacterAttribute = new CharacterAttribute(CharacterPartAnimator.arms, PartVariantColour.none, PartVariantType.none);
// Initialise character attribute list
characterAttributeCustomisationList = new List<CharacterAttribute>();
展示拿起物体/放下物体的动画:
public void ShowCarriedItem(int itemCode)
{
ItemDetails itemDetails = InventoryManager.Instance.GetItemDetails(itemCode);
if(itemDetails != null)
{
equippedItemSpriteRenderer.sprite = itemDetails.itemSprite;
equippedItemSpriteRenderer.color = new Color(1f, 1f, 1f, 1f);
// Apply 'carry' character arms customisation
armsCharacterAttribute.partVariantType = PartVariantType.carry;
characterAttributeCustomisationList.Clear();
characterAttributeCustomisationList.Add(armsCharacterAttribute);
animationOverrides.ApplyCharacterCustomisationParameters(characterAttributeCustomisationList);
isCarrying = true;
}
}
public void ClearCarriedItem()
{
equippedItemSpriteRenderer.sprite = null;
equippedItemSpriteRenderer.color = new Color(1f, 1f, 1f, 0f);
// Apply base character arms customisation
armsCharacterAttribute.partVariantType = PartVariantType.none;
characterAttributeCustomisationList.Clear();
characterAttributeCustomisationList.Add(armsCharacterAttribute);
animationOverrides.ApplyCharacterCustomisationParameters(characterAttributeCustomisationList);
isCarrying = false;
}
完整的代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : SingletonMonobehaviour<Player>
{
private AnimationOverrides animationOverrides; // 动画重写控制器
private List<CharacterAttribute> characterAttributeCustomisationList; // 目标动作列表
[Tooltip("Should be populated in the prefab with the equippped item sprite renderer")]
[SerializeField] private SpriteRenderer equippedItemSpriteRenderer = null; // 武器的图片
// Player attributes that can be swapped
private CharacterAttribute armsCharacterAttribute;
private CharacterAttribute toolCharacterAttribute;
private float xInput;
private float yInput;
private bool isWalking;
private bool isRunning;
private bool isIdle;
private bool isCarrying = false;
private ToolEffect toolEffect = ToolEffect.none;
private bool isUsingToolRight;
private bool isUsingToolLeft;
private bool isUsingToolUp;
private bool isUsingToolDown;
private bool isLiftingToolRight;
private bool isLiftingToolLeft;
private bool isLiftingToolUp;
private bool isLiftingToolDown;
private bool isPickingRight;
private bool isPickingLeft;
private bool isPickingUp;
private bool isPickingDown;
private bool isSwingToolRight;
private bool isSwingToolLeft;
private bool isSwingToolUp;
private bool isSwingToolDown;
private Camera mainCamera;
private Rigidbody2D rigidbody2D;
private Direction playerDirection;
private float movementSpeed;
private bool _playerInputIsDisabled = false;
public bool PlayerInputIsDisabled { get => _playerInputIsDisabled; set => _playerInputIsDisabled = value; }
protected override void Awake()
{
base.Awake();
rigidbody2D = GetComponent<Rigidbody2D>();
animationOverrides = GetComponentInChildren<AnimationOverrides>();
// Initialise swappable character attributes
armsCharacterAttribute = new CharacterAttribute(CharacterPartAnimator.arms, PartVariantColour.none, PartVariantType.none);
// Initialise character attribute list
characterAttributeCustomisationList = new List<CharacterAttribute>();
mainCamera = Camera.main;
}
private void Update()
{
#region Player Input
if (!PlayerInputIsDisabled)
{
ResetAnimationTrigger();
PlayerMovementInput();
PlayerWalkInput();
// Send event to any listeners for player movement input
EventHandler.CallMovementEvent(xInput, yInput, isWalking, isRunning, isIdle, isCarrying, toolEffect,
isUsingToolRight, isUsingToolLeft, isUsingToolUp, isUsingToolDown,
isLiftingToolRight, isLiftingToolLeft, isLiftingToolUp, isLiftingToolDown,
isPickingRight, isPickingLeft, isPickingUp, isPickingDown,
isSwingToolRight, isSwingToolLeft, isSwingToolUp, isSwingToolDown,
false, false, false, false);
}
#endregion Player Input
}
private void FixedUpdate()
{
PlayerMovement();
}
/// <summary>
/// 展示拿东西的动画
/// </summary>
/// <param name="itemCode"></param>
public void ShowCarriedItem(int itemCode)
{
ItemDetails itemDetails = InventoryManager.Instance.GetItemDetails(itemCode);
if(itemDetails != null)
{
equippedItemSpriteRenderer.sprite = itemDetails.itemSprite;
equippedItemSpriteRenderer.color = new Color(1f, 1f, 1f, 1f);
// Apply 'carry' character arms customisation
armsCharacterAttribute.partVariantType = PartVariantType.carry;
characterAttributeCustomisationList.Clear();
characterAttributeCustomisationList.Add(armsCharacterAttribute);
animationOverrides.ApplyCharacterCustomisationParameters(characterAttributeCustomisationList);
isCarrying = true;
}
}
public void ClearCarriedItem()
{
equippedItemSpriteRenderer.sprite = null;
equippedItemSpriteRenderer.color = new Color(1f, 1f, 1f, 0f);
// Apply base character arms customisation
armsCharacterAttribute.partVariantType = PartVariantType.none;
characterAttributeCustomisationList.Clear();
characterAttributeCustomisationList.Add(armsCharacterAttribute);
animationOverrides.ApplyCharacterCustomisationParameters(characterAttributeCustomisationList);
isCarrying = false;
}
private void PlayerMovement()
{
Vector2 move = new Vector2(xInput * movementSpeed * Time.deltaTime, yInput * movementSpeed * Time.deltaTime);
rigidbody2D.MovePosition(rigidbody2D.position + move);
}
private void ResetAnimationTrigger()
{
toolEffect = ToolEffect.none;
isUsingToolRight = false;
isUsingToolLeft = false;
isUsingToolUp = false;
isUsingToolDown = false;
isLiftingToolRight = false;
isLiftingToolLeft = false;
isLiftingToolUp = false;
isLiftingToolDown = false;
isPickingRight = false;
isPickingLeft = false;
isPickingUp = false;
isPickingDown = false;
isSwingToolRight = false;
isSwingToolLeft = false;
isSwingToolUp = false;
isSwingToolDown = false;
}
private void PlayerMovementInput()
{
xInput = Input.GetAxisRaw("Horizontal");
yInput = Input.GetAxisRaw("Vertical");
// 斜着移动
if (xInput != 0 && yInput != 0)
{
xInput = xInput * 0.71f;
yInput = yInput * 0.71f;
}
// 在移动
if (xInput != 0 || yInput != 0)
{
isRunning = true;
isWalking = false;
isIdle = false;
movementSpeed = Settings.runningSpeed;
// Capture player direction for save game
if (xInput < 0)
{
playerDirection = Direction.left;
}
else if (xInput > 0)
{
playerDirection = Direction.right;
}
else if (yInput < 0)
{
playerDirection = Direction.down;
}
else
{
playerDirection = Direction.up;
}
}
else if(xInput == 0 && yInput == 0)
{
isRunning = false;
isWalking = false;
isIdle = true;
}
}
// 按住Shift键移动为walk
private void PlayerWalkInput()
{
if(Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
{
isRunning = false;
isWalking = true;
isIdle = false;
movementSpeed = Settings.walkingSpeed;
}
else
{
isRunning = true;
isWalking = false;
isIdle = false;
movementSpeed = Settings.runningSpeed;
}
}
public Vector3 GetPlayerViewportPosition()
{
// Vector3 viewport position for player (0,0) viewport bottom left, (1,1) viewport top right
return mainCamera.WorldToViewportPoint(gameObject.transform.position);
}
public void DisablePlayerInputAndResetMovement()
{
DisablePlayerInpupt();
ResetMovement();
// Send event to any listeners for player movement input
EventHandler.CallMovementEvent(xInput, yInput, isWalking, isRunning, isIdle, isCarrying, toolEffect,
isUsingToolRight, isUsingToolLeft, isUsingToolUp, isUsingToolDown,
isLiftingToolRight, isLiftingToolLeft, isLiftingToolUp, isLiftingToolDown,
isPickingRight, isPickingLeft, isPickingUp, isPickingDown,
isSwingToolRight, isSwingToolLeft, isSwingToolUp, isSwingToolDown,
false, false, false, false);
}
private void ResetMovement()
{
// Reset movement
xInput = 0f;
yInput = 0f;
isRunning = false;
isWalking = false;
isIdle = true;
}
public void DisablePlayerInpupt()
{
PlayerInputIsDisabled = true;
}
public void EnablePlayerInput()
{
PlayerInputIsDisabled = false;
}
}
9、修改UIInventorySlot.cs脚本
在SetSelectedItem中新增如下代码:
if (itemDetails.canBeCarried == true)
{
// Show player carrying item
Player.Instance.ShowCarriedItem(itemDetails.itemCode);
}
else
{
Player.Instance.ClearCarriedItem();
}
在ClearSelectedItem中新增如下代码:
// Clear player carrying item
Player.Instance.ClearCarriedItem();
完整的代码如下:
using UnityEngine;
using TMPro;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;
public class UIInventorySlot : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler
{
private Camera mainCamera;
private Transform parentItem; // 场景中的物体父类
private GameObject draggedItem; // 被拖动的物体
private Canvas parentCanvas;
public Image inventorySlotHighlight;
public Image inventorySlotImage;
public TextMeshProUGUI textMeshProUGUI;
[SerializeField] private UIInventoryBar inventoryBar = null;
[SerializeField] private GameObject itemPrefab = null;
[SerializeField] private int slotNumber = 0; // 插槽的序列号
[SerializeField] private GameObject inventoryTextBoxPrefab = null;
[HideInInspector] public ItemDetails itemDetails;
[HideInInspector] public int itemQuantity;
[HideInInspector] public bool isSelected = false;
private void Awake()
{
parentCanvas = GetComponentInParent<Canvas>();
}
private void Start()
{
mainCamera = Camera.main;
parentItem = GameObject.FindGameObjectWithTag(Tags.ItemsParentTransform).transform;
}
public void OnBeginDrag(PointerEventData eventData)
{
if(itemDetails != null)
{
// Disable keyboard input
Player.Instance.DisablePlayerInputAndResetMovement();
// Instatiate gameobject as dragged item
draggedItem = Instantiate(inventoryBar.inventoryBarDraggedItem, inventoryBar.transform);
// Get image for dragged item
Image draggedItemImage = draggedItem.GetComponentInChildren<Image>();
draggedItemImage.sprite = inventorySlotImage.sprite;
SetSelectedItem();
}
}
public void OnDrag(PointerEventData eventData)
{
// move game object as dragged item
if(!draggedItem != null)
{
draggedItem.transform.position = Input.mousePosition;
}
}
public void OnEndDrag(PointerEventData eventData)
{
// Destroy game object as dragged item
if (draggedItem != null)
{
Destroy(draggedItem);
// if drag ends over inventory bar, get item drag is over and swap then
if (eventData.pointerCurrentRaycast.gameObject != null && eventData.pointerCurrentRaycast.gameObject.GetComponent<UIInventorySlot>() != null)
{
// get the slot number where the drag ended
int toSlotNumber = eventData.pointerCurrentRaycast.gameObject.GetComponent<UIInventorySlot>().slotNumber;
// Swap inventory items in inventory list
InventoryManager.Instance.SwapInventoryItems(InventoryLocation.player, slotNumber, toSlotNumber);
// Destroy inventory text box
DestroyInventoryTextBox();
// Clear selected item
ClearSelectedItem();
}
else
{
// else attemp to drop the item if it can be dropped
if (itemDetails.canBeDropped)
{
DropSelectedItemAtMousePosition();
}
}
// Enable player input
Player.Instance.EnablePlayerInput();
}
}
/// <summary>
/// Drops the item(if selected) at the current mouse position. called by the DropItem event
/// </summary>
private void DropSelectedItemAtMousePosition()
{
if(itemDetails != null && isSelected)
{
Vector3 worldPosition = mainCamera.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, -mainCamera.transform.position.z));
// Create item from prefab at mouse position
GameObject itemGameObject = Instantiate(itemPrefab, worldPosition, Quaternion.identity, parentItem);
Item item = itemGameObject.GetComponent<Item>();
item.ItemCode = itemDetails.itemCode;
// Remove item from player's inventory
InventoryManager.Instance.RemoveItem(InventoryLocation.player, item.ItemCode);
// If no more of item then clear selected
if(InventoryManager.Instance.FindItemInInventory(InventoryLocation.player, item.ItemCode) == -1)
{
ClearSelectedItem();
}
}
}
public void OnPointerEnter(PointerEventData eventData)
{
// Populate text box with item details
if(itemQuantity != 0)
{
// Instantiate inventory text box
inventoryBar.inventoryTextBoxGameobject = Instantiate(inventoryTextBoxPrefab, transform.position, Quaternion.identity);
inventoryBar.inventoryTextBoxGameobject.transform.SetParent(parentCanvas.transform, false);
UIInventoryTextBox inventoryTextBox = inventoryBar.inventoryTextBoxGameobject.GetComponent<UIInventoryTextBox>();
// Set item type description
string itemTypeDescription = InventoryManager.Instance.GetItemTypeDescription(itemDetails.itemType);
// Populate text box
inventoryTextBox.SetTextboxText(itemDetails.itemDescription, itemTypeDescription, "", itemDetails.itemLongDescription, "", "");
// Set text box position according to inventory bar position
if (inventoryBar.IsInventoryBarPositionBottom)
{
inventoryBar.inventoryTextBoxGameobject.GetComponent<RectTransform>().pivot = new Vector2(0.5f, 0f);
inventoryBar.inventoryTextBoxGameobject.transform.position = new Vector3(transform.position.x, transform.position.y + 50f, transform.position.z);
}
else
{
inventoryBar.inventoryTextBoxGameobject.GetComponent<RectTransform>().pivot = new Vector2(0.5f, 1f);
inventoryBar.inventoryTextBoxGameobject.transform.position = new Vector3(transform.position.x, transform.position.y - 50f, transform.position.z);
}
}
}
public void OnPointerExit(PointerEventData eventData)
{
DestroyInventoryTextBox();
}
private void DestroyInventoryTextBox()
{
if (inventoryBar.inventoryTextBoxGameobject != null)
{
Destroy(inventoryBar.inventoryTextBoxGameobject);
}
}
public void OnPointerClick(PointerEventData eventData)
{
// if left click
if (eventData.button == PointerEventData.InputButton.Left)
{
// if inventory slot currently selected then deselect
if (isSelected == true)
{
ClearSelectedItem();
}
else // 未被选中且有东西则显示选中的效果
{
if(itemQuantity > 0)
{
SetSelectedItem();
}
}
}
}
/// <summary>
/// Set this inventory slot item to be selected
/// </summary>
private void SetSelectedItem()
{
// Clear currently highlighted items
inventoryBar.ClearHighlightOnInventorySlots();
// Highlight item on inventory bar
isSelected = true;
// Set highlighted inventory slots
inventoryBar.SetHighlightedInventorySlots();
// Set item selected in inventory
InventoryManager.Instance.SetSelectedInventoryItem(InventoryLocation.player, itemDetails.itemCode);
if (itemDetails.canBeCarried == true)
{
// Show player carrying item
Player.Instance.ShowCarriedItem(itemDetails.itemCode);
}
else
{
Player.Instance.ClearCarriedItem();
}
}
private void ClearSelectedItem()
{
// Clear currently highlighted item
inventoryBar.ClearHighlightOnInventorySlots();
isSelected = false;
// set no item selected in inventory
InventoryManager.Instance.ClearSelectedInventoryItem(InventoryLocation.player);
// Clear player carrying item
Player.Instance.ClearCarriedItem();
}
}
10、创建对象/资源
(1)创建动画描述资源
在Assets -> Scriptable Object Assets下创建Animation目录。
在其下再新建Animation Types的目录,在其下再创建arms的目录,在其下再创建NoneCarry(partVariantColour=None, partVariantType=Carry)和NoneNone的目录。
新建动画描述示例:
创建的内容罗列如下:其中NoneCarryxxx的放在NoneCarry目录下,NoneNonexxx的放在NoneNone目录下。
Name | Animation Clip | Animation Name | Character Part | Part Variant Colour | Part Variant Type |
ArmsNoneCarryIdleDown | ArmsNoneCarryIdleDown | Idle Down | Arms | None | Carry |
ArmsNoneCarryIdleLeft | ArmsNoneCarryIdleLeft | Idle Left | Arms | None | Carry |
ArmsNoneCarryIdleRight | ArmsNoneCarryIdleRight | Idle Right | Arms | None | Carry |
ArmsNoneCarryIdleUp | ArmsNoneCarryIdleUp | Idle Up | Arms | None | Carry |
ArmsNoneCarryRunDown | ArmsNoneCarryRunDown | Run Down | Arms | None | Carry |
ArmsNoneCarryRunLeft | ArmsNoneCarryRunLeft | Run Left | Arms | None | Carry |
ArmsNoneCarryRunRight | ArmsNoneCarryRunRight | Run Right | Arms | None | Carry |
ArmsNoneCarryRunUp | ArmsNoneCarryRunUp | Run Up | Arms | None | Carry |
ArmsNoneCarryWalkDown | ArmsNoneCarryWalkDown | Walk Down | Arms | None | Carry |
ArmsNoneCarryWalkLeft | ArmsNoneCarryWalkLeft | Walk Left | Arms | None | Carry |
ArmsNoneCarryWalkRight | ArmsNoneCarryWalkRight | Walk Right | Arms | None | Carry |
ArmsNoneCarryWalkUp | ArmsNoneCarryWalkUp | Walk Up | Arms | None | Carry |
ArmsNoneNoneIdleDown | ArmsNoneNoneIdleDown | Idle Down | Arms | None | None |
ArmsNoneNoneIdleLeft | ArmsNoneNoneIdleLeft | Idle Left | Arms | None | None |
ArmsNoneNoneIdleRight | ArmsNoneNoneIdleRight | Idle Right | Arms | None | None |
ArmsNoneNoneIdleUp | ArmsNoneNoneIdleUp | Idle Up | Arms | None | None |
ArmsNoneNoneRunDown | ArmsNoneNoneRunDown | Run Down | Arms | None | None |
ArmsNoneNoneRunLeft | ArmsNoneNoneRunLeft | Run Left | Arms | None | None |
ArmsNoneNoneRunRight | ArmsNoneNoneRunRight | Run Right | Arms | None | None |
ArmsNoneNoneRunUp | ArmsNoneNoneRunUp | Run Up | Arms | None | None |
ArmsNoneNoneWalkDown | ArmsNoneNoneWalkDown | Walk Down | Arms | None | None |
ArmsNoneNoneWalkLeft | ArmsNoneNoneWalkLeft | Walk Left | Arms | None | None |
ArmsNoneNoneWalkRight | ArmsNoneNoneWalkRight | Walk Right | Arms | None | None |
ArmsNoneNoneWalkUp | ArmsNoneNoneWalkUp | Walk Up | Arms | None | None |
(2)创建动画重写控制器物体
在Hierarchy -> Player下创建新物体命名为CharacterCustomiser。
添加Animation Overriders组件。
(3)修改equippedItem对象
修改position y 为1.5。
(4)Player对象设置equip对象
运行程序,效果如下: