Unity MOBA类型游戏的战争迷雾效果
基于视野(FOV)的战争迷雾,例如LOL的视野:鼠标右键点击地板,目标移动,同时显示角色周围视野,鼠标滚轮可以调节远近。
Unity版本:2019.4.1f1
1.新建工程---右键3D Object---Terrain,随便刷一个地形,尽量高低错落,设置地形大小为100*100
2.导入文件,在Camera上添加Fog Of War Effect脚本,脚本会自动添加<Flare Layer>组件,Unity 2018之前的版本需要添加<GUI Layer>组件,2019以后版本被舍弃,无需添加
3.右键创建一个胶囊,模拟玩家,添加NavMeshAgent组件,添加Fog Of War Explorer脚本
using UnityEngine;
using UnityEngine.AI;/// <summary>
/// 视野数据-由于计算fov是在子线程操作,通过将视野数据以object类型参数传入,
/// 使用简单数据类型或结构体会产生装箱操作,因此将视野封装成类
/// </summary>
public class FOWFieldData
{public float radiusSquare;public Vector3 position;public float radius;public FOWFieldData(Vector3 position, float radius){this.position = position;this.radius = radius;this.radiusSquare = radius * radius;}
}/// <summary>
/// Player
/// </summary>
public class FogOfWarExplorer : MonoBehaviour
{[Range(10, 25)] public float radius = 15;//视野半径private Vector3 m_OriginPosition;private FOWMapPos m_FowMapPos;private FOWFieldData m_FieldData;private bool m_IsInitialized;private float distance = 24;//摄像机高度private float angle = 45;//摄像机偏移角度private Vector3 m_CameraPosition;private NavMeshAgent m_Agent;void Start(){m_FieldData = new FOWFieldData(transform.position, radius);m_Agent = gameObject.GetComponent<NavMeshAgent>();Camera.main.transform.rotation = Quaternion.Euler(angle, 0, 0);Camera.main.transform.position = transform.position - Camera.main.transform.forward * distance;}void Update(){if (radius <= 0)return;if (m_OriginPosition != transform.position){m_OriginPosition = transform.position;var pos = FogOfWarEffect.WorldPositionToFOW(transform.position);if (m_FowMapPos.x != pos.x || m_FowMapPos.y != pos.y || !m_IsInitialized){m_FowMapPos = pos;m_IsInitialized = true;m_FieldData.position = transform.position;m_FieldData.radius = radius;//FogOfWarEffect.SetVisibleAtPosition(m_FieldData);FogOfWarEffect.UpdateFOWFieldData(m_FieldData);}}m_CameraPosition = transform.position - Camera.main.transform.forward * distance;Camera.main.transform.position = Vector3.Lerp(Camera.main.transform.position, m_CameraPosition, Time.deltaTime * 3f);BasicOperation();}void OnDestroy(){if (m_FieldData != null)FogOfWarEffect.ReleaseFOWFieldData(m_FieldData);m_FieldData = null;}void OnDrawGizmosSelected(){Gizmos.color = Color.blue;Gizmos.DrawWireSphere(transform.position, radius);}void BasicOperation() {if (Input.GetMouseButtonDown(1))//鼠标右键点击地板{Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hit;if (Physics.Raycast(ray, out hit)){m_Agent.SetDestination(hit.point);}}if (Input.GetAxis("Mouse ScrollWheel") > 0){if (distance >= 7)distance -= 2;}if (Input.GetAxis("Mouse ScrollWheel") < 0){if (distance <= 35)distance += 2;}}}
4.Scene视角切换成俯视视角,方便调整参数。调整战争迷雾蒙版类型、宽度、高度、战争迷雾中心位置,将特效shader、模糊shader、小地图shader拖入Main Camera上的Fog Of War Effect上
using ASL.FogOfWar;
using System.Collections.Generic;
using UnityEngine;public struct FOWMapPos
{public int x;public int y;public FOWMapPos(int x, int y){this.x = x;this.y = y;}
}/// <summary>
/// 屏幕空间战争迷雾
/// </summary>
[RequireComponent(typeof(FlareLayer))]
public class FogOfWarEffect : MonoBehaviour
{//迷雾蒙版类型public enum FogMaskType{/// <summary>/// 精确计算的FOV/// </summary>AccurateFOV,/// <summary>/// 基础FOV/// </summary>BasicFOV,/// <summary>/// 简单圆形/// </summary>Circular,}//实例化public static FogOfWarEffect Instance{get{if (instance == null)instance = FindObjectOfType<FogOfWarEffect>();return instance;}}private static FogOfWarEffect instance;/// <summary>/// 迷雾蒙版类型/// </summary>public FogMaskType fogMaskType { get { return m_FogMaskType; } }/// <summary>/// 战争迷雾颜色(RGB迷雾颜色,Alpha已探索区域透明度)/// </summary>public Color fogColor { get { return m_FogColor; } }/// <summary>/// 迷雾区域宽度/// </summary>public float xSize { get { return m_XSize; } }/// <summary>/// 迷雾区域高度/// </summary>public float zSize { get { return m_ZSize; } }/// <summary>/// 迷雾贴图宽度/// </summary>public int texWidth { get { return m_TexWidth; } }/// <summary>/// 迷雾贴图高度/// </summary>public int texHeight { get { return m_TexHeight; } }/// <summary>/// 迷雾区域中心坐标/// </summary>public Vector3 centerPosition { get { return m_CenterPosition; } }public float heightRange { get { return m_HeightRange; } }public Texture2D fowMaskTexture{get{if (m_Map != null)return m_Map.GetFOWTexture();return null;}}public RenderTexture minimapMask{get{if (!m_GenerateMinimapMask)return null;return m_Renderer.GetMimiMapMask();}}[Header("战争迷雾蒙版类型")][SerializeField]private FogMaskType m_FogMaskType;[Header("战争迷雾颜色")][SerializeField]private Color m_FogColor = Color.black;[Header("战争迷雾宽度")][SerializeField]private float m_XSize = 77f;[Header("战争迷雾高度")][SerializeField]private float m_ZSize = 77f;[Header("战争迷雾贴图宽度")][SerializeField]private int m_TexWidth = 66;[Header("战争迷雾贴图高度")][SerializeField]private int m_TexHeight = 66;[Header("战争迷雾中心位置")][SerializeField]private Vector3 m_CenterPosition;[Header("高度随机值")][SerializeField]private float m_HeightRange = 1.23f;/// <summary>/// 模糊偏移量/// /// </summary>[Header("模糊偏移量")][SerializeField]private float m_BlurOffset = 0.003f;/// <summary>/// 模糊迭代次数/// </summary>[Header("模糊迭代次数")][SerializeField]private int m_BlurInteration = 2;/// <summary>/// 是否生成小地图蒙版/// </summary>private bool m_GenerateMinimapMask;/// <summary>/// 迷雾特效shader/// </summary>[Header("战争特效Shader")] public Shader effectShader;/// <summary>/// 模糊shader/// </summary>[Header("模糊Shader")] public Shader blurShader;/// <summary>/// 小地图蒙版渲染shader/// </summary>[Header("小地图蒙版渲染Shader")] public Shader minimapRenderShader;[Header("更新周期")][Range(0.0f,1.0f)]public float UpdateTime = 1.0f;/// <summary>/// 预生成的地图FOV数据(如果为空则使用实时计算FOV)/// </summary>//public FOWPregenerationFOVMapData pregenerationFOVMapData;/// <summary>/// 战争迷雾地图对象/// </summary>private FOWMap m_Map;/// <summary>/// 战争迷雾渲染器/// </summary>private FOWRenderer m_Renderer;private bool m_IsInitialized;private float m_MixTime = 0.0f;private float m_RefreshTime = 0.0f;private float m_DeltaX;private float m_DeltaZ;private float m_InvDeltaX;private float m_InvDeltaZ;private Camera m_Camera;private const float kDispearSpeed = 3f;private const float kRefreshTextureSpeed = 4.0f;private Vector3 m_BeginPos;private List<FOWFieldData> m_FieldDatas;private bool m_IsFieldDatasUpdated;void Awake(){m_IsInitialized = Init();}void OnDestroy(){if (m_Renderer != null)m_Renderer.Release();if (m_Map != null)m_Map.Release();if (m_FieldDatas != null)m_FieldDatas.Clear();m_FieldDatas = null;m_Renderer = null;m_Map = null;instance = null;}void FixedUpdate(){/*更新迷雾纹理*/if (m_MixTime >= UpdateTime){if (m_RefreshTime >= UpdateTime){m_RefreshTime = 0.0f;if (m_Map.RefreshFOWTexture()){m_Renderer.SetFogFade(0);m_MixTime = 0;m_IsFieldDatasUpdated = false;//m_Renderer.SetFogTexture(m_Map.GetFOWTexture());}}else{m_RefreshTime += Time.deltaTime * kRefreshTextureSpeed;}}else{m_MixTime += Time.deltaTime * kDispearSpeed;m_Renderer.SetFogFade(m_MixTime);}}private bool Init(){if (m_XSize <= 0 || m_ZSize <= 0 || m_TexWidth <= 0 || m_TexHeight <= 0)return false;if (effectShader == null || !effectShader.isSupported)return false;m_Camera = gameObject.GetComponent<Camera>();if (m_Camera == null)return false;m_Camera.depthTextureMode |= DepthTextureMode.Depth;m_DeltaX = m_XSize / m_TexWidth;m_DeltaZ = m_ZSize / m_TexHeight;m_InvDeltaX = 1.0f / m_DeltaX;m_InvDeltaZ = 1.0f / m_DeltaZ;m_BeginPos = m_CenterPosition - new Vector3(m_XSize * 0.5f, 0, m_ZSize * 0.5f);m_Renderer = new FOWRenderer(effectShader, blurShader, minimapRenderShader, m_CenterPosition, m_XSize, m_ZSize, m_FogColor, m_BlurOffset, m_BlurInteration);m_Map = new FOWMap(m_FogMaskType, m_BeginPos, m_XSize, m_ZSize, m_TexWidth, m_TexHeight, m_HeightRange);IFOWMapData md = gameObject.GetComponent<IFOWMapData>();if (md != null)m_Map.SetMapData(md);else{m_Map.SetMapData(new FOWMapData(m_TexHeight, m_TexHeight));m_Map.GenerateMapData(m_HeightRange);}if (minimapRenderShader != null)m_GenerateMinimapMask = true;return true;}/// <summary>/// 世界坐标转战争迷雾坐标/// </summary>/// <param name="position"></param>/// <returns></returns>public static FOWMapPos WorldPositionToFOW(Vector3 position){if (!Instance)return default(FOWMapPos);if (!Instance.m_IsInitialized)return default(FOWMapPos);int x = Mathf.FloorToInt((position.x - Instance.m_BeginPos.x) * Instance.m_InvDeltaX);int z = Mathf.FloorToInt((position.z - Instance.m_BeginPos.z) * Instance.m_InvDeltaZ);return new FOWMapPos(x, z);}public static Vector2 WorldPositionTo2DLocal(Vector3 position){if (!Instance)return default(Vector2);if (!Instance.m_IsInitialized)return default(Vector2);Vector2 pos = default(Vector2);pos.x = (position.x - Instance.m_BeginPos.x) / Instance.m_XSize;pos.y = (position.z - Instance.m_BeginPos.z) / Instance.m_ZSize;return pos;}/ <summary>/ 将指定位置设置为可见/ </summary>/ <param name="fieldData">视野</param>//public static void SetVisibleAtPosition(FOWFieldData fieldData)//{// if (!Instance)// return;// if (!Instance.m_IsInitialized)// return;// if (fieldData == null)// return;// Instance.m_Map.SetVisible(fieldData);//}public static void UpdateFOWFieldData(FOWFieldData data){if (!Instance)return;if (!Instance.m_IsInitialized)return;if (Instance.m_FieldDatas == null)Instance.m_FieldDatas = new List<FOWFieldData>();if (!Instance.m_FieldDatas.Contains(data)){Instance.m_FieldDatas.Add(data);}if (!Instance.m_IsFieldDatasUpdated){//lock (Instance.m_FieldDatas){Instance.m_Map.SetVisible(Instance.m_FieldDatas);Instance.m_IsFieldDatasUpdated = true;}}}public static void ReleaseFOWFieldData(FOWFieldData data){if (!instance)return;if (!instance.m_IsInitialized)return;//lock (instance.m_FieldDatas){if (instance.m_FieldDatas != null && instance.m_FieldDatas.Contains(data))instance.m_FieldDatas.Remove(data);}}/// <summary>/// 是否在地图中可见/// </summary>/// <param name="position"></param>/// <returns></returns>public static bool IsVisibleInMap(Vector3 position){if (!Instance)return true;if (!Instance.m_IsInitialized)return true;int x = Mathf.FloorToInt((position.x - Instance.m_BeginPos.x) * Instance.m_InvDeltaX);int z = Mathf.FloorToInt((position.z - Instance.m_BeginPos.z) * Instance.m_InvDeltaZ);return Instance.m_Map.IsVisibleInMap(x, z);}void OnRenderImage(RenderTexture src, RenderTexture dst){if (!m_IsInitialized)Graphics.Blit(src, dst);else{m_Renderer.RenderFogOfWar(m_Camera, m_Map.GetFOWTexture(), src, dst);}}void OnDrawGizmosSelected(){FOWUtils.DrawFogOfWarGizmos(m_CenterPosition, m_XSize, m_ZSize, m_TexWidth, m_TexHeight, m_HeightRange);}
}
5.单击Terrain 右上角勾选静态Static,Windows----AI---Navigation,Bake---Bake
6.运行即可查看效果,你还可以添加小地图和右键点击动画等效果。
如果你的场景和我的不一样,那也没关系,我改了光照设置,不改也没问题,我的光照设置如下:
资源下载:点击下载
网盘下载:访问码:2oeb
参考资料:GitHub
Unity MOBA类型游戏的战争迷雾效果相关推荐
- 在Unity中为即时战略游戏实现战争迷雾(上)
本文将由游戏开发工程师Ariel Coppes分享在Unity中为即时战略游戏实现战争迷雾效果. 过去三年中,我一直在Ironhide Game Studio开发移动即时战略游戏<钢铁战队> ...
- 在Unity中为即时战略游戏实现战争迷雾(下)
本文将在Unity中为即时战略游戏实现战争迷雾的一种新方法. 在上一篇文章中,游戏开发工程师Ariel Coppes分享了<钢铁战队>中战争迷雾效果的实现方法,本文他将介绍新的一种实现方法 ...
- 2D游戏的战争迷雾实现方式
转自: http://bbs.gameres.com/forum.php?mod=viewthread&tid=201878&extra=page%3D16%26filter%3Dso ...
- 【笨木头Cocos2dx 041】战争迷雾效果 第4章_真正的迷雾来了!
错过了前面章节? 没关系,传送门在这: 战争迷雾效果 第1章_要探索,不要地图全开! 战争迷雾效果 第2章_先把地图加进来 战争迷雾效果 第3章_准确地获取屏幕上的瓦片位置 经过这么多铺垫,我们要来正 ...
- 战争迷雾效果 第4章_真正的迷雾来了!
原文地址:http://www.benmutou.com/blog/archives/485 经过这么多铺垫,我们要来正式编写实现迷雾效果的代码了. (小若:快点开始写,别唠叨了!) 笨木头花心贡献, ...
- 战争迷雾效果 第05章 项目源码下载
笨木头花心贡献,啥?花心?不呢,是用心~ 转载请注明,原文地址:http://www.benmutou.com/blog/archives/502 正文: 关于战争迷雾效果的项目源码一直没有放出来,原 ...
- Unity3D技术开发之战争迷雾效果
相信玩过Dota,英雄联盟等即时竞技类游戏的朋友都知道战争迷雾,这次做了一个战争迷雾的效果: 战争迷雾大家应该很熟悉了,一开始地图全部都是黑的,只有主角的一定范围内能看得到.随着主角的移动,未探索的区 ...
- cocos2dx 实现战争迷雾效果
游戏里面的战争迷雾或者刮刮乐效果可以用下面的方法实现 function MainScene:onCreate()local strVertSource = "attribute vec4 a ...
- Unity3D战争迷雾效果
战争迷雾demo视频 这次做了一个战争迷雾的效果: 战争迷雾大家应该很熟悉了,一开始地图全部都是黑的,只有主角的一定范围内能看得到.随着主角的移动,未探索的区域变成了可见. 我这个demo还做了视角切 ...
最新文章
- 基于easyui开发Web版Activiti流程定制器详解(四)——页面结构(下)
- 陈鑫136201010502
- mysql show schema_快速入门 · xiaoboluo768/mysql-system-schema Wiki · GitHub
- 从知乎了解到,为什么Mysql禁用存储过程、外键和级联?
- SAP Spartacus的ProductAdapter和OccProductAdapter
- Linux环境编程导引
- php 判断用户是否刷新,如何在php和ajax中创建一个注册页面,它会在不刷新页面的情况下检查某个用户名是否已经存在? - php...
- 怎么更改wifi频段_wifi信号差?网速慢?这样做不浪费每一兆宽带
- matlab中使用libsvm工具箱训练的svm分类器model保存
- 技术文档模板_腾讯文档-轻松操作指南
- ffmpeg历史版本下载
- Java 链表元素如何从键盘输入 面试 笔试高频
- 关于编程-R语言跟Python到底学哪个好?
- win10黑科技,新建桌面非常好用
- UE4入门序列08(Unreal制作MMO游戏范围巡逻AI)
- 记war exploded部署不成功
- 使用TextPaint实现自由加粗字体:BoldTextView,支持中粗
- GITLAB服务常用命令
- 维谛技术(Vertiv)隆重举行“笃行——数据中心基础设施智能化管理研讨会”...
- html语言中kbd的含义,HTML kbd键盘元素
热门文章
- 德勤《全球AI发展白皮书》出炉!八大新趋势,三个关键技术一文扫尽【附下载】...
- Virtual script not found, may missing <script lang=“ts“> / “allowJs“: true / jsconfig.json. 报错解决
- java我的世界填充方块_我的世界填充指令 填充TNT的指令是什么
- Excel导入数据时间格式问题处理
- 2022年危险化学品经营单位安全管理人员考试练习题模拟考试平台操作
- js、html、jsp完美在线格式化工具
- 【正点原子FPGA连载】第十一章 触摸按键控制LED灯实验 -摘自【正点原子】领航者ZYNQ之FPGA开发指南_V2.0
- 光模块价格由带宽还是距离决定_光模块传输距离估算方法
- 【高级篇 / SNMP】(7.0) ❀ 04. PRTG 监控 FortiGate 状态 (下) ❀ FortiGate 防火墙
- 一文掌握模型调参神器:Hyperopt