Unity工具——LightTransition(光照过渡)
需求描述
在游戏中,开发者为了让玩家更直接地看到待拾取的物品从而为其添加一种闪烁效果,或者模拟现实中闪烁的灯光效果,我能够想到的一种方案则是通过控制光照强度来实现,那么本篇文章我们就尝试通过这个方案来实现一下,看看是否能够满足这类需求,这也能够作为我们个人资源库的一部分,以后如果在开发中有这方面需求,就可以直接把这个方案搬过来用,虽然这可能只是一个小小的功能,但这是一个积少成多的过程,只要我们能够完整地实现并使之通过测试,那么就算是一种成功,也能够从中获得收获。
功能描述
如果大家了解过Light和Light2D组件,那么就应该知道其中的intensity属性用于控制光照强度,本质上闪烁就是通过改变光照强度的值来控制的,从暗到明,则对应intensity的值从小到大。
首先我们需要两个属性——光照强度起始值beginValue和光照强度最终值endValue,还有从beginValue到endValue的光照强度变化的步长值stepValue,同时还要确定等待时间的属性timeSpan。为了使得这个组件应用更广泛,我们不公开beginValue和endValue,而是让使用者明确光照强度的最小值minValue以及光照强度最大值maxValue,所以beginValue既可以是minValue也可以是maxValue,这取决于使用者的需求。
其次就是需要明确从beginValue到endValue的过渡方式了,我首先能够想到的是是否需要循环闪烁,假定属性Loop用于明确是否循环闪烁,如果不循环闪烁,那么只要从beginValue过渡到endValue就结束,若需要循环闪烁则需要明确循环的方式,如果每次循环都是从beginValue过渡到endValue则可以假定这种方式叫BeginToEnd,除此之外还可以是先从beginValue过渡到endValue然后再过渡到beginValue,类似一个钟摆一样,假定这种方式叫Pendulum。
最后我们还可以规定beginValue的取值,我们规定它要么是minValue,要么是maxValue,只要确定了beginValue,就可以确定endValue,所以我们假定属性beginValueType用于明确光照强度起始值的类型。
属性 | 解释 |
Light | Unity的Light组件 |
Light2D | Universal RP中的Light2D组件 |
intensity | Light/Light2D组件的光照强度属性 |
beginValue | 光照强度起始值 |
endValue | 光照强度最终值 |
stepValue | 光照强度变化的步长值 |
timeSpan | 光照强度变化的时间间隔 |
minValue | 光照强度的最小值 |
maxValue | 光照强度的最大值 |
Loop | 是否循环闪烁 |
BeginToEnd | 每次循环都是从beginValue过渡到endValue |
Pendulum | 先从beginValue过渡到endValue然后再过渡到beginValue,类似一个钟摆 |
beginValueType | 光照强度起始值的类型 |
代码展示(C#)
CommonLightTransition.cs
using System.Collections;
using UnityEngine;namespace Tools
{public class CommonLightTransition : MonoBehaviour{[Header("必要属性")][Tooltip("光照强度变化平均值,默认值为0.1(值>0)")][SerializeField] private float IntensityStepValue = 0.1f;[Tooltip("光照强度最小值,默认值为1(值属于[0,IntensityMaxValue))")][SerializeField] private float IntensityMinValue = 1;[Tooltip("光照强度最大值,默认值为2(值>IntensityMinValue)")][SerializeField] private float IntensityMaxValue = 2;[Tooltip("过渡时间间隔,默认值为0.05,单位s(值>0)")][SerializeField] private float TransitionTimeSpan = 0.05f;[Tooltip("是否开启光照过渡循环,默认值为true")][SerializeField] private bool Loop = true;[Tooltip("光照过渡循环方式,需要勾选Loop该选项才有效,BeginToEnd是每次循环从光照过渡起始值开始,Pendulum是从光照过渡起始值至光照过渡最终值再过渡至光照过渡起始值(钟摆式过渡)")][SerializeField] private LoopMode TheLoopMode;[Tooltip("光照过渡起始值类型,Min代表起始值从IntensityMinValue开始,Max同理")][SerializeField] private BeginValueType TransitionBeginValueType;protected bool toMax;protected bool lockUnLoopTransition;protected int index;protected bool _isInit { get => isInit; }protected float[] _changedValues { get => changedValues; }protected BeginValueType _transitionBeginValueType { get => TransitionBeginValueType; }protected bool _loop { get => Loop; }protected LoopMode _loopMode { get => TheLoopMode; }protected float _intensityMinValue { get => IntensityMinValue; }protected float _intensityMaxValue { get => IntensityMaxValue; }private bool isInit, endTransition;private float[] changedValues;private IEnumerator coroutine;/// <summary>/// 启动过渡/// </summary>public void StartTransition(){if (isInit && endTransition){StartCoroutine(coroutine);endTransition = false;}}/// <summary>/// 停止过渡/// </summary>public void StopTransition(){if (isInit && !endTransition){StopCoroutine(coroutine);endTransition = true;}}/// <summary>/// 初始化游戏对象相关组件/// <para>返回值:初始化组件成功则返回true,否则返回false</para>/// </summary>protected virtual bool InitComponents() { return false; }/// <summary>/// 光照过渡类型处理/// </summary>protected virtual void TransitionTypeDeal() { }/// <summary>/// 非循环光照过渡/// </summary>protected virtual void UnLoopLightTransition() { }/// <summary>/// 循环光照过渡/// </summary>protected virtual void LoopLightTransition() { }/// <summary>/// 组件检测控制台提示方法/// <para>声明:该方法仅在Unity Editor模式下且当Inspector面板中组件属性发生更改时执行</para>/// </summary>protected virtual void ComponentLog() { }/// <summary>/// 光照过渡起始值类型/// </summary>protected enum BeginValueType{Min, Max}/// <summary>/// 循环光照过渡方式/// </summary>protected enum LoopMode{BeginToEnd, Pendulum}private void Start(){isInit = InitComponents() && InitParameters();}//初始化游戏对象相关参数private bool InitParameters(){if (IntensityStepValue <= 0 || IntensityMinValue < 0 || IntensityMaxValue <= 0) return false;if (IntensityMinValue >= IntensityMaxValue) return false;if (TransitionTimeSpan <= 0) return false;changedValues = NumberRange.FloatRange(IntensityMinValue, IntensityMaxValue, IntensityStepValue, true);if (changedValues == null && changedValues.Length == 0) return false;TransitionTypeDeal();coroutine = UnLoopTransition();if (Loop){lockUnLoopTransition = true;coroutine = LoopTransition();}endTransition = true;return true;}private IEnumerator LoopTransition(){while (true){LoopLightTransition();yield return new WaitForSeconds(TransitionTimeSpan);}}private IEnumerator UnLoopTransition(){while (!lockUnLoopTransition){UnLoopLightTransition();yield return new WaitForSeconds(TransitionTimeSpan);}endTransition = true;}#if UNITY_EDITORprivate void OnValidate(){ComponentLog();}
#endif}
}
LightTransition2D.cs
using UnityEngine.Experimental.Rendering.Universal;
using UnityEngine;namespace Tools
{public class LightTransition2D : CommonLightTransition{[Header("必要组件(需要下载扩展包:Universal RP)")][Tooltip("Light2D组件")][SerializeField] private Light2D Light2D;private bool isLight2DLog;//初始化游戏对象相关组件protected sealed override bool InitComponents(){if (Light2D == null) return false;return true;}//光照过渡类型处理protected sealed override void TransitionTypeDeal(){if (_transitionBeginValueType == BeginValueType.Min){Light2D.intensity = _intensityMinValue;index = 0;toMax = true;}else{Light2D.intensity = _intensityMaxValue;index = _changedValues.Length - 1;toMax = false;}}//非循环光照过渡protected sealed override void UnLoopLightTransition(){if (_isInit && !lockUnLoopTransition){if (_transitionBeginValueType == BeginValueType.Min){if (index >= _changedValues.Length){lockUnLoopTransition = true;return;}Light2D.intensity = _changedValues[index++];}else{if (index < 0){lockUnLoopTransition = true;return;}Light2D.intensity = _changedValues[index--];}}}//循环光照过渡protected sealed override void LoopLightTransition(){if (_isInit && _loop){if (_loopMode == LoopMode.Pendulum){if (index <= 0) toMax = true;else if (index >= _changedValues.Length - 1) toMax = false;}else if (index < 0 || index > _changedValues.Length - 1) TransitionTypeDeal();if (toMax) Light2D.intensity = _changedValues[index++];else Light2D.intensity = _changedValues[index--];}}//组件检测控制台提示方法protected sealed override void ComponentLog(){if (Light2D == null){if (!isLight2DLog){Debug.LogWarning("The component \"<color=orange><b>Light2D</b></color>\" is null.");isLight2DLog = true;}}else isLight2DLog = false;}}
}
LightTransition.cs
using UnityEngine;namespace Tools
{public class LightTransition : CommonLightTransition{[Header("必要组件")][Tooltip("Light组件")][SerializeField] private Light Light;private bool isLightLog;//初始化游戏对象相关组件protected sealed override bool InitComponents(){if (Light == null) return false;return true;}//光照过渡类型处理protected sealed override void TransitionTypeDeal(){if (_transitionBeginValueType == BeginValueType.Min){Light.intensity = _intensityMinValue;index = 0;toMax = true;}else{Light.intensity = _intensityMaxValue;index = _changedValues.Length - 1;toMax = false;}}//非循环光照过渡protected sealed override void UnLoopLightTransition(){if (_isInit && !lockUnLoopTransition){if (_transitionBeginValueType == BeginValueType.Min){if (index >= _changedValues.Length){lockUnLoopTransition = true;return;}Light.intensity = _changedValues[index++];}else{if (index < 0){lockUnLoopTransition = true;return;}Light.intensity = _changedValues[index--];}}}//循环光照过渡protected sealed override void LoopLightTransition(){if (_isInit && _loop){if (_loopMode == LoopMode.Pendulum){if (index <= 0) toMax = true;else if (index >= _changedValues.Length - 1) toMax = false;}else if (index < 0 || index > _changedValues.Length - 1) TransitionTypeDeal();if (toMax) Light.intensity = _changedValues[index++];else Light.intensity = _changedValues[index--];}}//组件检测控制台提示方法protected sealed override void ComponentLog(){if (Light == null){if (!isLightLog){Debug.LogWarning("The component \"<color=orange><b>Light</b></color>\" is null.");isLightLog = true;}}else isLightLog = false;}}
}
NumberRange.cs
using System.Collections.Generic;
using System.Linq;namespace Tools
{/// <summary>/// 数值范围数组工具类/// </summary>public static class NumberRange{/// <summary>/// 获取指定范围内指定步长的Float数值数组/// <para>p_start:起始值</para>/// <para>p_end:终点值</para>/// <para>p_step:步长值</para>/// <para>[ContainsEnd]:是否包括终点值,默认为false</para>/// <para>返回值:Float[]</para>/// </summary>public static float[] FloatRange(float p_start, float p_end, float p_step, bool ContainsEnd = false){if (!ContainsEnd) return DoFloatRange(p_start, p_end, p_step).ToArray();else{List<float> result = DoFloatRange(p_start, p_end, p_step).ToList();result.Add(p_end);return result.ToArray();}}static IEnumerable<float> DoFloatRange(float p_start, float p_end, float p_step){for (float i = p_start; i <= p_end; i += p_step){yield return i;}}}
}
界面展示


部分演示效果
LightTransition2D组件的简单演示效果
LightTransition2D - Demo
资源下载
GitHub_LightTransition 百度网盘
如果这篇文章对你有帮助,请给作者点个赞吧!
相关文章:

Unity工具——LightTransition(光照过渡)
需求描述 在游戏中,开发者为了让玩家更直接地看到待拾取的物品从而为其添加一种闪烁效果,或者模拟现实中闪烁的灯光效果,我能够想到的一种方案则是通过控制光照强度来实现,那么本篇文章我们就尝试通过这个方案来实现一下ÿ…...

【深度学习】 Python 和 NumPy 系列教程(十四):Matplotlib详解:1、2d绘图(下):箱线图、热力图、面积图、等高线图、极坐标图
目录 一、前言 二、实验环境 三、Matplotlib详解 1、2d绘图类型 0. 设置中文字体 1-5. 折线图、散点图、柱状图、直方图、饼图 6. 箱线图(Box Plot) 7. 热力图(Heatmap) 8. 面积图(Area Plot) 9. 等…...

IMU+摄像头实现无标记运动捕捉
惯性传感和计算机视觉的进步为在临床和自然环境中获得精准数据带来了新可能。然而在临床应用时需要仔细地将传感器与身体对齐,这减慢了数据收集过程。 随着无标记运动捕捉的发展,研究者们提出了一个新的深度学习模型,利用来自视觉、惯性传感…...

前后端分离,JSON数据如何交互
如何接收: 在配置文件商法加上相应注解 EnableWebMvc 在接收的路径上加上RequestBody注解 注解的作用:在Spring框架中,RequestBody注解用于将HTTP请求的body中的内容转换为Java对象,并将其作为参数传递给控制器方法。它通常用…...

docker中已创建容器的修改方法
环境信息以CentOS8为例 停止容器 #docker stop 容器名或id docker stop mysql停止docker服务 systemctl stop docker修改docker配置文件 配置文件在: /var/lib/docker/containers/{容器id} 如:/var/lib/docker/containers/92acfba87567bcca981ad17c0e…...

uniapp中video播放视频上按钮没显示的问题
video标签层级很高,尝试了添加z-index,但无效果 通过查阅资料,得知cover-view层级比video层级高 效果图 需求是为了使直播时,可选是原画/流畅 解决方案 首先,在pages.json中配置右上角的图标 {"path" : …...

docker学习:dockerfile和docker-compose
学习如何使用dockerfile 以下内容,部分来自gpt生成,里面的描述可能会出现问题,但代码部分,我都会进行测试。 1. 需求 对于一个docker,例如python,我们需要其在构建成容器时,就有np。有以下两种方…...

Pycharm 配置python项目本地运行环境
1.打开Pycharm,打开Setting 2. 新建本地环境 3.如果报错如上图所示,请通过cmd来新建本地环境,具体步骤如下 在对应的代码路径下,通过virtualenv venv来创建虚拟路径 安装好之后,安装对应的依赖包即可 pip3 install -r ./require…...

DevEco Studio中如何设置HarmonyOS/OpenHarmony应用开发
DevEco Studio内置有帮助中心,初学HarmonyOS 及OpenHarmony应用、元服务的开发者,通过内置的帮助中去系统的学习相关内容,是边练边学,快速上手的最佳方式。 一、帮助 二、快速开始 三、HarmonyOS应用、元服务开发相关 四、OpenHa…...

Matlab图像处理-三原色
三原色 根据详细的实验结果,人眼中负责颜色感知的细胞中约有65%对红光敏感,33%对绿光敏感,只有2%对蓝光敏感。正是人眼的这些吸收特性决定了所看到的彩色是一般所谓的原色红(R)、绿(G)和蓝&…...
QLExpress代码解读,运行原理解析
简介: 本文针对上图的功能详细图,进行逐个的简单介绍:代码入口、代码的主要逻辑和算法。 调用代码实例 //本文以helloworld案例,开启了两个打印日志的参数,实际使用通常不建议打开。 boolean printParseLog true;//语法分析日志开…...
M1 Mac创建虚拟环境遇到的问题
报错信息 PackagesNotFoundError: The following packages are not available from current channels: python3.7 Current channels: https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/osx-arm64 https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/noarch htt…...
flutter 与H5交互
主要是flutter内嵌H5页面,之后就是两者之间的交互 flutter:webview_flutter 4.2.2 H5: uniapp 1、flutter向H5传参 //在flutter 中的web页面,可在onPageFinished中向H5进行传参onPageFinished: (String url) async {WebViewCont…...

【Java 基础篇】Java类型通配符:解密泛型的神秘面纱
在Java中,类型通配符(Type Wildcard)是泛型的重要概念之一。它使得我们能够更加灵活地处理泛型类型,使代码更通用且可复用。本文将深入探讨Java类型通配符的用法、语法和最佳实践。 什么是类型通配符? 类型通配符是一…...
《极客时间:如何成为学习高手》【方法论】
本篇博客是学习过程中的笔记整理和个人思考。原文链接:https://time.geekbang.org/column/intro/100081501?tabcatalog 底层逻辑01|如何减少对学习的排斥和厌恶心理,使其变得相对愉悦?02|学会这 4 点,你也…...
如何处理ChatGPT在文本生成中的语法错误和不合理性?
ChatGPT是一种强大的自然语言处理模型,但它并不是完美的,有时会产生语法错误或不合理的文本。这些问题可能会影响模型生成的内容的质量和可信度。在处理ChatGPT中的语法错误和不合理性时,有许多方法和策略可以采用,以下是一些详细…...
GitHub常用命令
1. 将本文件夹初始化为一个本地git仓库 git init 2. 将github的远程克隆到本地 git clone XXX 3. 添加所有文件到暂存区 git add . 4. 删除工作区文件 git rm [file] 5. 提交 git commit -m "提交信息(比如:my first commit fileÿ…...

【Linux学习笔记】 - 常用指令学习及其验证(上)
前言:本文主要记录对Linux常用指令的使用验证。环境为阿里云服务器CentOS 7.9。关于环境如何搭建等问题,大家可到同平台等各大资源网进行搜索学习,本文不再赘述。 由于本人对Linux学习程度尚且较浅,本文仅介绍验证常用指令的常用…...

火山引擎边缘云助力智能科技赋予生活更多新意
当下,先进的科学技术使得我们的日常生活变得快捷、舒适。大到上百层智能大厦、高端公共场所、社会智能基础设施,小到智能家居监控、指纹密码锁等,在这个充满想象力的时代,科技以更加智能化的方式改变和守护我们的生活。 引入智能…...
【无标题】CTreeCtrl更改-/+展开按钮颜色
#pragma once #include <list>// CMyTreeCtrlclass CMyTreeCtrl : public CTreeCtrl {private:std::list<std::...

CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...
深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙
WebGL:在浏览器中解锁3D世界的魔法钥匙 引言:网页的边界正在消失 在数字化浪潮的推动下,网页早已不再是静态信息的展示窗口。如今,我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室,甚至沉浸式的V…...