IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> [UGUI进阶知识十七]跟随UI的屏幕出界限制判断[一] -> 正文阅读

[游戏开发][UGUI进阶知识十七]跟随UI的屏幕出界限制判断[一]

项目中摘取出来的部分
效果如下,做了之后就感觉不难,但还是记录一下结果,指不定哪天就能用到,
有点类似于PC游戏上,跟随鼠标运动的UI在边界时候做的反应,
或者topdown游戏里面的跟随
目前直接更改位置有点生硬,可以加个过度的动画。
请添加图片描述

思路

有横向两个标志位左右,竖直两个标志位上下,组成四个不同的情况,各对应不同的偏移值。 当触碰到屏幕边距的时候,改变标志位,然后根据标志位重新刷新偏移值,蓝色方块根据红色方块和偏移值来确定自身位置

代码


using System;
using UnityEngine;


public partial class VerBOutBoundUI 
{

    private Const.HorizontalPosFlag currentHorizontalPosFlagVerB;
    private Const.VerticalPosFlag currentVerticalPosFlagVerB;

    [SerializeField] private RectTransform toAlignRecttransform;
    [SerializeField] private RectTransform targetRecttransform;


    private void Awake()
    {
        InitPosOffset();
    }

    private void Update()
    {
        JudgeOutScreenByBounce();
        
        toAlignRecttransform.position = targetRecttransform.position + new Vector3(
            currentPosOffset.x, 
            currentPosOffset.y,
            0);
    }


    void JudgeOutScreenByBounce()
    {
        JudgeImageVerticalOutOfScreenByBounceVerB();
        JudgeImageHorizontalOutOfScreenByBounceVerB();
        ResetOffsetPosVerB();
    }

    
    
    
    /// <summary>
    /// 判断相机画布是否竖直方向超出屏幕
    /// 以及超出屏幕后设置标志位
    /// 要求预览图的pivot在中心
    /// </summary>
    void JudgeImageVerticalOutOfScreenByBounceVerB()
    {
        if (toAlignRecttransform != null)
        {
            Vector3 worldPos = toAlignRecttransform.position;
            
            
            
            float halfHeight = toAlignRecttransform.rect.height / 2f;

            float topPlaceYPos = worldPos.y + halfHeight;
            float bottomPlaceYPos = worldPos.y - halfHeight;

            

#if !UNITY_EDITOR
        float maxHeight = Screen.currentResolution.height;
#else
            int canvasDisplay = RootTransformCanvas.targetDisplay;
            float maxHeight = 0;
            if (Display.displays[canvasDisplay] != null)
            {
                maxHeight = Display.displays[canvasDisplay].renderingHeight;
            }
#endif

            Vector3 screenPos = RectTransformUtility.WorldToScreenPoint(Camera.main, worldPos);
            
            Debug.Log(" topPlaceHeight " + topPlaceYPos + 
                      " bottomPlaceYPos " + bottomPlaceYPos +
                      " maxHeight " + maxHeight + 
                      " worldPos " + worldPos + 
                      " halfHeight " + halfHeight + 
                      " screenPos " + screenPos);

            if (topPlaceYPos > maxHeight)
            {
                currentVerticalPosFlagVerB = Const.VerticalPosFlag.Bottom;
            }
            else if (bottomPlaceYPos < 0)
            {
                currentVerticalPosFlagVerB = Const.VerticalPosFlag.Top;
            }
        }

    }

    
    /// <summary>
    /// 判断相机画布是否水平方向超出屏幕
    /// 以及超出屏幕后设置标志位
    /// 要求预览图的pivot在中心
    /// </summary>
    void JudgeImageHorizontalOutOfScreenByBounceVerB()
    {
        Vector3 worldPos = toAlignRecttransform.position;
        float halfWidth = toAlignRecttransform.rect.width / 2f;

        float rightPlaceXPos = worldPos.x + halfWidth;
        float leftPlaceXPos = worldPos.x - halfWidth;
        
        // Debug.Log(" topPlaceHeight " + topPlaceHeight);
        // Debug.Log(" halfWidth " + halfWidth);


#if !UNITY_EDITOR
        float maxWidth = Screen.currentResolution.width;
#else
        float maxHeight = 0;

        int canvasDisplay = RootTransformCanvas.targetDisplay;
        float maxWidth = 0;
        if (Display.displays[canvasDisplay] != null)
        {
            maxWidth = Display.displays[canvasDisplay].renderingWidth;
        }
#endif
        
        if (rightPlaceXPos > maxWidth)
        {
            currentHorizontalPosFlagVerB = Const.HorizontalPosFlag.Left;
        }
        else if (leftPlaceXPos < 0)
        {
            currentHorizontalPosFlagVerB = Const.HorizontalPosFlag.Right;
        }
    }

    void ResetOffsetPosVerB()
    {
        switch (currentVerticalPosFlagVerB)
        {
            case Const.VerticalPosFlag.Top:
                switch (currentHorizontalPosFlagVerB)
                {
                    case Const.HorizontalPosFlag.Left:
                        currentPosOffset = topLeftPosOffset;
                        break;
                    case Const.HorizontalPosFlag.Right:
                        currentPosOffset = topRightPosOffset;
                        break;
                }

                break;
            case Const.VerticalPosFlag.Bottom:
                switch (currentHorizontalPosFlagVerB)
                {
                    case Const.HorizontalPosFlag.Left:
                        currentPosOffset = bottomLeftPosOffset;
                        break;
                    case Const.HorizontalPosFlag.Right:
                        currentPosOffset = bottomRightPosOffset;
                        break;
                }

                break;
        }
    }

}

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

/// <summary>
/// 提取预览UI处理回弹问题的公共部分
/// </summary>
public partial class VerBOutBoundUI : MonoBehaviour
{
    [Header("预览窗口位置偏移")]
    //这些偏移只适用于在3840*2160的机器上
    //其他分辨率的机器如1920*1080的机器要做对应的比例换算
    [SerializeField]
    private float topPosYDelta = 300;

    [SerializeField] private float bottomPosYDelta = -300;
    [SerializeField] private float leftPosXDelta = -570;
    [SerializeField] private float rightPosXDelta = 570;

    [SerializeField] private Canvas RootTransformCanvas;

    private Vector3 currentPosOffset;

    private Vector2 topLeftPosOffset;
    private Vector2 topRightPosOffset;
    private Vector2 bottomRightPosOffset;
    private Vector2 bottomLeftPosOffset;

    

    void InitPosOffset()
    {
        topLeftPosOffset = new Vector2(leftPosXDelta, topPosYDelta);
        topRightPosOffset = new Vector2(rightPosXDelta, topPosYDelta);
        bottomRightPosOffset = new Vector2(rightPosXDelta, bottomPosYDelta);
        bottomLeftPosOffset = new Vector2(leftPosXDelta, bottomPosYDelta);

        ResetOffsetPosByResolution();

        currentHorizontalPosFlagVerB = Const.HorizontalPosFlag.Right;
        currentVerticalPosFlagVerB = Const.VerticalPosFlag.Top;
    }

    /// <summary>
    /// 根据屏幕分辨率重新调整偏移值
    /// 因为默认的偏移只适用于在3840*2160的机器上
    /// 其他分辨率的机器如1920*1080的机器要做对应的比例换算
    /// </summary>
    void ResetOffsetPosByResolution()
    {
#if UNITY_EDITOR
        float ratioWidth = 0;
        float ratioHeight = 0;
        if (RootTransformCanvas != null)
        {
            int canvasDisplay = RootTransformCanvas.targetDisplay;
            if (Display.displays[canvasDisplay] != null)
            {
                float editorWidth = Display.displays[canvasDisplay].renderingWidth;
                float editorHeight = Display.displays[canvasDisplay].renderingHeight;

                ratioWidth = (editorWidth * 1f) / (Const.standardResolutionWidth * 1f);
                ratioHeight = (editorHeight * 1f) / (Const.standardResolutionHeight * 1f);
            }
        }
#else
            float ratioWidth = (Screen.currentResolution.width * 1f) / (Const.standardResolutionWidth * 1f);
            float ratioHeight = (Screen.currentResolution.height * 1f) / (Const.standardResolutionHeight * 1f);
#endif

        topLeftPosOffset.x *= ratioWidth;
        topLeftPosOffset.y *= ratioHeight;

        topRightPosOffset.x *= ratioWidth;
        topRightPosOffset.y *= ratioHeight;


        bottomRightPosOffset.x *= ratioWidth;
        bottomRightPosOffset.y *= ratioHeight;

        bottomLeftPosOffset.x *= ratioWidth;
        bottomLeftPosOffset.y *= ratioHeight;

    }


}

注意点

在Unity中, 当CanvasSacler的ScaleMode值为Constant Pixel Size并且其他属性如下

在这里插入图片描述

, 并且Canvas的RenderMode为Overlay类型的UI画布时,屏幕分辨率和UI的position和RectTransform的rect的宽高属性,才是在同一个单位下的,可以直接进行运算;

或者如下图所示,当运行的分辨率与CanvasSacler的参考分辨率相同的时候,也有这三个属性值是在同一个单位下的特性
在这里插入图片描述
我的工程是在这种情况下进行的,如果是在其他情况下,应该是要用RectTransformUtility进行一些世界坐标到屏幕坐标的相应转换。

示例工程

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-04-09 18:49:29  更:2022-04-09 18:51:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/16 21:11:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码