场景布局,设置static属性,设置Layer层,调整属性(Carmera,Lighting)
设置light的效果:
Light中的Culling Mask表示有灯光作用的物体标签类型,不选择中的标签不受光照影响
增加一盏场景灯和报警灯,场景灯提供场景关照,报警灯当发现玩家后进行报警的视觉和声音效果:
public class AlarmLight : MonoBehaviour
{
public float fadeSpeed = 2f; //灯光报警fade的速度(默认2s变化一次)
public float hightIntensity = 4f; //最高最低亮度
public float lowIntensity = 0.5f;
public float changeMargin = 0.2f; //插值阈值
public bool alarmOn;
private float targetIntensity; //目标亮度值
private Light alarmLight;
private AudioSource audioSource;
private void Awake()
{
alarmLight = GetComponent<Light>();
audioSource = GetComponent<AudioSource>();
alarmLight.intensity = 0;
targetIntensity = hightIntensity;
}
// Update is called once per frame
void Update()
{
if (alarmOn)
{
if (!audioSource.isPlaying)
audioSource.Play();
alarmLight.intensity = Mathf.Lerp(alarmLight.intensity, targetIntensity, fadeSpeed * Time.deltaTime);
if (Mathf.Abs(targetIntensity - alarmLight.intensity) < changeMargin)
{
if (targetIntensity == hightIntensity)
targetIntensity = lowIntensity;
else
targetIntensity = hightIntensity;
}
}
else
{
if (audioSource.isPlaying)
audioSource.Stop();
alarmLight.intensity = Mathf.Lerp(alarmLight.intensity, 0, fadeSpeed * Time.deltaTime);
}
}
}
//烘焙场景是使用bake类型的灯光对场景进行烘焙,生成贴图贴到物体表面,用于表现灯光效果
烘焙的意义:单独使用 Unity 实时光源的光线时,这些光线不会自动进行反射。为了使用全局光照等技术创建更逼真的场景,我们需要启用 Unity 的预计算光照解决方案;Unity 可以计算复杂的静态光照效果(使用称为全局光照(简称 GI)的技术)并将它们存储在称为光照贴图的纹理贴图中作为参考。这一计算过程称为烘焙。对光照贴图进行烘焙时,会计算光源对场景中静态对象的影响,并将结果写入纹理中,这些纹理覆盖在场景几何体上以营造出光照效果。
通过这种方法,我们可在游戏中移动我们的光照,通过降低实时光计算量潜在提高性能,适应性能较低的硬件,如移动平台)
通过这种方法,可创建具有丰富全局光照和反射光的光照环境,能够实时响光照变化。这方面的一个典型例子是一天的时间系统:光源的位置和颜色随时间变化。如果使用传统的烘焙光照,这是无法实现的
必须根据特定项目和所需目标平台的性质来决定采用哪种方法。请记住,在面向一系列不同硬件时,通常情况下,性能最低的硬件将决定选取哪种方法。
Render Mode表示渲染的类型:Important表示逐像素渲染灯光,Not Impritant表示逐顶点渲染灯光,Auto表示自动
设置渲染质量:Project Setting -> Quality面板,因为我们游戏场景中的资源偏多,可能存在效率问题,所以我们我们渲染质量选择Good; 设置Rendering中 Pixel Light Cout(逐像素渲染的灯光的数量),因为我们灯光都选择的Auto的类型,所有应该Unity会挑6盏灯逐像素渲染,其他都逐顶点渲染(Unity怎么挑的???)
具体参数可以参考Unity官方文档,2018开始Unity的Lightmapper中提供了一种新的烘焙方式Progressive,此方式进行渐进式的光照贴图烘焙,一个简单的场景烘焙时间都到10个小时起
烘焙完成后的贴图自动贴到了场景物体上,此时关闭所有灯光,物体依旧具有关照的效果
public class ScreenFadeInOut : MonoBehaviour
{
public float fadeSpeed = 1.5f;
private bool sceneStarting;
private RawImage rawImage;
// Start is called before the first frame update
void Start()
{
sceneStarting = true;
rawImage = this.GetComponent<RawImage>();
}
// Update is called once per frame
void Update()
{
if (sceneStarting)
{
rawImage.color = Color.Lerp(rawImage.color, Color.clear, fadeSpeed * Time.deltaTime);
if (rawImage.color.a <= 0.05f)
{
rawImage.color = Color.clear;
sceneStarting = false;
rawImage.enabled = false;
}
}
}
public void EndScene()
{
rawImage.enabled = true;
rawImage.color = Color.Lerp(rawImage.color, Color.black, fadeSpeed * Time.deltaTime);
if (rawImage.color.a > 0.95f)
SceneManager.LoadScene(0);
}
}
public class LastPlayerSighting : MonoBehaviour
{
public Vector3 position = new Vector3(1000f, 1000f, 1000f); //表示玩家最后一次被发现的位置,如果没有被发现,就设置为默认值
public Vector3 resetPosition = new Vector3(1000f, 1000f, 1000f);
public float lightHighIntensity = 0.25f; //主灯光的亮度范围
public float lightLowIntensity = 0f;
public float lightFadeSpeed = 7f;
public float musicFadeSpeed = 1f; //音乐变化的fade速率
public bool isPlayerFound = false;
private AlarmLight alarmLightScript;
private Light mainLight; //主灯光
private AudioSource mainMusic; //主音乐和panic时播放的音乐
private AudioSource panicMusic;
private AudioSource[] sirens; //报警音乐
private const float muteVolume = 0f; //音乐的变化范围
private const float normalVolume = 0.8f;
// Start is called before the first frame update
void Start()
{
alarmLightScript = GameObject.FindGameObjectWithTag(Tags.ALARM_LIGHT).GetComponent<AlarmLight>();
mainLight = GameObject.FindGameObjectWithTag(Tags.MAIN_LIGHT).GetComponent<Light>();
mainMusic = this.GetComponent<AudioSource>();
panicMusic = this.transform.Find("Secondary_music").GetComponent<AudioSource>();
//sirens = new AudioSource[];
}
// Update is called once per frame
void Update()
{
isPlayerFound = (position != resetPosition);
//当玩家被发现时,调低主灯光,打开报警灯,淡出主音乐,淡入panic音乐, 但玩家脱离危险后恢复;
mainLight.intensity = Mathf.Lerp(mainLight.intensity, isPlayerFound ? lightLowIntensity : lightHighIntensity, lightFadeSpeed * Time.deltaTime);
alarmLightScript.alarmOn = isPlayerFound;
mainMusic.volume = Mathf.Lerp(mainMusic.volume, isPlayerFound ? muteVolume : normalVolume, musicFadeSpeed);
panicMusic.volume = Mathf.Lerp(panicMusic.volume, isPlayerFound ? normalVolume : muteVolume, musicFadeSpeed);
}
}
public class CCTVCollision : MonoBehaviour
{
private LastPlayerSighting lastPlayerSighting;
private void Start()
{
lastPlayerSighting = GameObject.FindGameObjectWithTag(Tags.GAMECONTROLLER).GetComponent<LastPlayerSighting>();
}
private void OnTriggerStay(Collider other)
{
if (other.tag == Tags.PLAYER)
{
lastPlayerSighting.position = other.transform.position;
}
}
private void OnTriggerExit(Collider other)
{
if (other.tag == Tags.PLAYER)
{
lastPlayerSighting.position = lastPlayerSighting.resetPosition;
}
}
}
public class LasterBlinking : MonoBehaviour
{
public float onTime; //灯灭的时间间隔
public float offTime; //灯亮的时间间隔
private float timer; //流逝的时间
private Renderer laserRenerer;
private Light laserLight;
// Start is called before the first frame update
void Start()
{
laserRenerer = GetComponent<Renderer>();
laserLight = GetComponent<Light>();
timer = 0;
}
// Update is called once per frame
void Update()
{
timer += Time.deltaTime;
if (laserRenerer.enabled && timer >= onTime)
{
laserRenerer.enabled = false;
laserLight.enabled = false;
timer = 0;
}
else if (!laserRenerer.enabled && timer >= offTime)
{
laserRenerer.enabled = true;
laserLight.enabled = true;
timer = 0;
}
}
}
public class LaserPlayerDetection : MonoBehaviour
{
private void OnTriggerStay(Collider other)
{
if (other.tag == Tags.PLAYER && this.GetComponent<Renderer>().enabled)
{
LastPlayerSighting.Instance.position = other.transform.position;
}
}
}原文:https://www.cnblogs.com/raymondking123/p/11491549.html