当前位置: 首页 > article >正文

Unity3D仿星露谷物语开发17之空库存栏UI

1、目标

将库存栏放在游戏界面中,一般情况下角色居中展示时库存栏在底部,当角色位于界面下方时库存栏展示在顶部避免遮挡。

2、CanvasGroup组件

用于集中控制UI元素的透明度、交互性和射线投射行为。CanvasGroup的Alpha属性允许渐变效果,Interactable决定元素是否可交互,BlocksRaycasts影响图形射线检测,而IgnoreParentGroups选项则控制是否忽略父对象的CanvasGroup设置。这些特性在创建互动游戏场景时尤为有用。

3、Aspect Ratio Fitter组件

Aspect Ratio Fitter 组件的核心作用是按照给定的宽高比调整 UI 元素的尺寸。它可以根据宽度调整高度,也可以根据高度调整宽度,从而确保 UI 元素的宽高比始终固定,不会因为外部布局的变化而拉伸或压缩。

它有以下几种模式:

  • None:不做任何宽高比调整,元素保持原始尺寸。
  • Width Controls Height:根据宽度来调整高度,确保元素的宽高比保持不变。
  • Height Controls Width:根据高度来调整宽度,以确保比例正确。
  • Fit In Parent:在父容器内缩放元素,保持宽高比不变,同时确保元素的大小适合父容器。
  • Envelope Parent:让元素包裹住父容器,保持比例,同时元素可能会超过父容器的边界。

这个属性用于设置 UI 元素的目标宽高比。通常,宽高比是通过 宽度 / 高度 的形式表示。例如,如果想保持 16:9 的比例,则需要将 Aspect Ratio 设置为 16 / 9

4、创建UI

在Hierarchy -> PersistentScene中创建空对象命名为UI。

在UI下创建Canvas命名为MainGameUICanvas。Canvas是UI组件的容器。相关属性设置如下:

在MainGameUICanvas下创建空物体命名为UICanvasGroup,添加两个组件Canvas Group和Aspect Ratio Fitter。

在UICanvasGroup下创建空物体命名为UIInventoryBar。

添加Image组件,并设置下列属性。

对于位置信息,按Shift + Alt键选中中间底部,此时Pos X/Y/Z均为0,修改Pos Y为2.5。

(Shift -> Shift + Alt键)

效果如下:

5、编写脚本

在Assets -> Scripts下新增UI目录,同时新增UIInventory子目录,在此目录下新增UIInventorybar.cs脚本。

(1)优化Player类

首先,我们需要根据角色的位置判断bar到底是处于底部还是顶部,所以Player类需要对外提供坐标信息,而且是相对屏幕的坐标。

修改Player.cs如下:

private Camera mainCamera;

mainCamera = Camera.main;

public Vector3 GetPlayerViewportPosition()
{
    // Vector3 viewport position for player (0,0) viewport bottom left, (1,1) viewport top right
    return mainCamera.WorldToViewportPoint(gameObject.transform.position);
}

此时Player.cs完整代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : SingletonMonobehaviour<Player>
{
    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>();

        mainCamera = Camera.main;
    }

    private void Update()
    {
        #region  Player Input
        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
    }

    private void FixedUpdate()
    {
        PlayerMovement();
    }

    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);
    }
}

(2)编写UIInventorybar类

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIInventoryBar : MonoBehaviour
{
    private RectTransform rectTransform;

    private bool _isInventoryBarPositionBottom = true;

    public bool IsInventoryBarPositionBottom { get { return _isInventoryBarPositionBottom;} set { _isInventoryBarPositionBottom = value; } }

    private void Awake()
    {
        rectTransform = GetComponent<RectTransform>();
    }

    private void Update()
    {
        // Switch inventory bar position depending on player position
        SwitchInventoryBarPosition();
    }

    private void SwitchInventoryBarPosition()
    {
        Vector3 playerViewportPosition = Player.Instance.GetPlayerViewportPosition();

        if (playerViewportPosition.y > 0.3f && IsInventoryBarPositionBottom == false)
        {
            rectTransform.pivot = new Vector2(0.5f, 0f);
            rectTransform.anchorMin = new Vector2(0.5f, 0f);
            rectTransform.anchorMax = new Vector2(0.5f, 0f);
            rectTransform.anchoredPosition = new Vector2(0f, 2.5f);

            IsInventoryBarPositionBottom = true;
        }
        else if (playerViewportPosition.y <= 0.3f && IsInventoryBarPositionBottom == true) 
        {
            rectTransform.pivot = new Vector2(0.5f, 1f);
            rectTransform.anchorMin = new Vector2(0.5f, 1f);
            rectTransform.anchorMax = new Vector2(0.5f, 1f);
            rectTransform.anchoredPosition = new Vector2(0f, -2.5f);

            IsInventoryBarPositionBottom = false;
        }
    }
}

以上参数的值对应Rect Transform的值,比如当位于底部时:

在顶部时对应的值:

将UIInventoryBar脚本添加到UIInventoryBar对象上。

运行程序,效果如下:


http://www.kler.cn/a/469045.html

相关文章:

  • 【连续学习之LwM算法】2019年CVPR顶会论文:Learning without memorizing
  • 密码学原理技术-第十一章-Hash Functions
  • Haskell语言的多线程编程
  • Kafka 消费者专题
  • 125个Docker的常用命令
  • 【工具类】RedisUtil 操作相关
  • vue3如何实现防抖?
  • atrust异常导致ERR_NETWORK_CHANGED
  • 2025-01-04 Unity插件 YodaSheet2 —— 基础用法
  • vscode中设置默认格式化工具pretter
  • 【图像处理】数据集合集!
  • 【软考网工笔记】计算机基础理论与安全——网络安全
  • 借助提示词工程,解锁高效应用开发之道
  • 计算机网络--UDP和TCP课后习题
  • 限时特惠,香港服务器,低至53元/年
  • 数据结构漫游记:初识栈(stack)
  • 探秘 AI Agent 之 Coze 智能体:从简介到搭建全攻略(4/30)
  • 超大规模分类(二):InfoNCE
  • ffmpeg之yuv格式转h264
  • 人工智能-Python网络编程-TCP
  • 数据库基础:SQL 与 NoSQL 的区别与应用场景
  • BERT的中文问答系统61
  • 桌面开发 的设计模式(Design Patterns)核心知识
  • Qt实现使用TCP与RS485串口设备通信————附带详细实践方法
  • KCP技术原理
  • HTML——77.网页编码及乱码处理