前言

前几日在游戏技术群里吹水时,有个人问了下面图片中的效果怎么做

当时我就觉得这个效果应该不难,研究了一段时间后,便在Unity里完成了2D聚光灯的效果,闲言少叙,先上图!

思路

首先可以确定的是,这个效果肯定是要结合碰撞体去做的,从光源点发射射线去检测碰撞,再将碰撞点按照顺序整合成一个网格面片,就可以做出聚光灯效果。

问题就在于怎么去检测碰撞..................................

最初想法

我最初的想法是:光源点向着碰撞体的每个顶点P发射一条射线,当检测到碰撞,并且检测到的点不为P时,便将该点存储起来用于生成网格面片,如下图

但是后来发现这个方法有问题,做出来的效果就像后面那张图一样。很显然,这个方法行不通,射线检测后,虽然检测到了碰撞点,但是这些点并不能完整的组成一个网格面片。例如:点1和点2之间、点2和点3之间其实应该再连接一个蓝色的点,但是该蓝色点并没有算进去;点4并不应该算进去等.......

改进

原先的方法虽然行不通,但不是彻底没啥用。后面为了检测这些特殊的点,在原来的基础上,我采用了将原射线一分为二的方法,原射线分别向左和向右偏移,再去检测碰撞:

左右两边各检测一遍,这样就可以正确检测点了。

最后,上代码!注释全都有!拷走直接用!!!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;[RequireComponent(typeof(EdgeCollider2D))]
public class Light2D : MonoBehaviour
{[Range(0.1f,179.9f)]public float range;public float length;public LayerMask castLayers;public Collider2D[] colliders;//用于检测的碰撞盒MeshFilter meshFilter;EdgeCollider2D myCollider;Vector2 start, end;//光的左边和右边/// <summary>/// 射线向左和向右偏移的距离/// </summary>float rayOffsetDis = 0.001f;/// <summary>/// 用于检测点的射线/// </summary>Vector2[] rays;/// <summary>/// 用于生成光面片的顶点/// </summary>List<Vector2> vertics;private void Awake(){myCollider = GetComponent<EdgeCollider2D>();meshFilter = GetComponent<MeshFilter>();}// Start is called before the first frame updatevoid Start(){start = Quaternion.AngleAxis(-range / 2, transform.forward) * -transform.up;end = Quaternion.AngleAxis(range / 2, transform.forward) * -transform.up;GenerateCollider();}// Update is called once per framevoid Update(){start = Quaternion.AngleAxis(-range / 2, transform.forward) * -transform.up;end = Quaternion.AngleAxis(range / 2, transform.forward) * -transform.up;Calculate();Debug.DrawRay(transform.position, start,Color.red);Debug.DrawRay(transform.position, end,Color.green);}private void OnDrawGizmos(){if(vertics == null){ return; }for (int i = 0; i < vertics.Count; i++){Gizmos.color = new Color((float)i / vertics.Count, 0, 0, 1);Gizmos.DrawSphere(vertics[i], 0.003f);Gizmos.DrawLine(transform.position, vertics[i]);}}/// <summary>/// 生成一个扇形碰撞体/// </summary>void GenerateCollider(){List<Vector2> ps = new List<Vector2>();float angAdd = 5f;float ang = 0;do{Vector3 dir = Quaternion.AngleAxis(ang, transform.forward) * -transform.right;ps.Add(dir * length);ang += angAdd;} while (ang <= 180);this.myCollider.points = ps.ToArray();}/// <summary>/// 计算光/// </summary>void Calculate(){rays = GetRays();vertics = new List<Vector2>();vertics.Add(transform.position);//网格顶点第一个为本身坐标foreach (var item in rays){var hit = Physics2D.Raycast(transform.position, item, length, castLayers);//射线检测,检测到碰撞点就加入顶点列表if(hit.collider != null)vertics.Add(hit.point);}GenerateMesh();}/// <summary>/// 生成面片/// </summary>void GenerateMesh(){Mesh mesh = new Mesh();int[] tris = new int[vertics.Count * 3 - 6];for (int i = 0; i < tris.Length/3; i ++){tris[i * 3] = 0;tris[i * 3 + 1] = i + 1;tris[i * 3 + 2] = i + 2;}var vts = new Vector3[vertics.Count];for (int i = 0; i < vts.Length; i++){vts[i] = transform.InverseTransformPoint(vertics[i]);}mesh.SetVertices(vts);mesh.triangles = tris;mesh.RecalculateNormals();mesh.RecalculateTangents();meshFilter.mesh = mesh;}/// <summary>/// 获取所有用于检测的射线/// </summary>/// <returns></returns>Vector2[] GetRays(){List<Vector2> rays = new List<Vector2>();rays.Add(start);rays.Add(end);foreach (var col in colliders){var colPoints = GetColliderPoints(col);foreach (var point in colPoints){Vector3 p = point;Vector3 dir = p - transform.position;//光源点到碰撞盒点的向量if (Vector3.Cross(start, dir).z <= 0 || Vector3.Cross(end, dir).z >= 0)//如果超出光的边界,则不计算该点continue;Vector3 dir2 = Vector3.Cross(dir, Vector3.forward).normalized;//用于计算射线偏移的向量//分别得到向右和向左偏移的向量var p0 = p + dir2 * rayOffsetDis;var p1 = p - dir2 * rayOffsetDis;rays.Add(p0 - transform.position);rays.Add(p1 - transform.position);}}//下面根据从左到右的顺序重排射线,该步骤主要用于后面获取正确的网格面片顶点顺序for (int i = 0; i <= rays.Count - 1; i++){for (int j = 0; j < rays.Count - i - 1; j++){if (Vector2.Dot(-transform.right, rays[j].normalized) > Vector2.Dot(-transform.right, rays[j + 1].normalized)){Vector2 t = rays[j];rays[j] = rays[j + 1];rays[j + 1] = t;}}}return rays.ToArray();}/// <summary>/// 获取组成碰撞盒的点的世界坐标/// </summary>/// <param name="collider2D"></param>/// <returns></returns>Vector2[] GetColliderPoints(Collider2D collider2D){Vector2[] ps = new Vector2[0];if(collider2D is PolygonCollider2D){ps = ((PolygonCollider2D)collider2D).points;}else if (collider2D is EdgeCollider2D){ps = ((EdgeCollider2D)collider2D).points;}else if (collider2D is BoxCollider2D){var bc = ((BoxCollider2D)collider2D);ps = new Vector2[4];ps[0] = bc.offset - bc.size * 0.5f;ps[1] = bc.offset + new Vector2(bc.size.x * -0.5f, bc.size.y * 0.5f);ps[2] = bc.offset + bc.size * 0.5f;ps[3] = bc.offset + new Vector2(bc.size.x * 0.5f, bc.size.y * -0.5f);}for (int i = 0; i < ps.Length; i++){ps[i] = collider2D.transform.TransformPoint(ps[i]);}return ps;}}

【游戏算法】2D游戏中聚光灯效果相关推荐

  1. 【269期门诊集锦】iOS游戏开发—2D游戏编程之我见

    技术门诊是51CTO社区品牌栏目,每周邀请一位客座专家,为广大技术网友解答疑问.从热门技术到前沿知识,从技术答疑到职业规划.每期一个主题,站在最新最热的技术前沿为你引航! 本期门诊特邀iOS游戏开发专 ...

  2. 【小游戏】2D游戏黄金矿工GoldMiner(关卡模式)

    难度系数: ★★★☆☆ 游戏玩法: 黄金矿工,在恰当的时机点击屏幕放出钩子捡金块 项目简介: 功能完善,关卡模式,适合初中级练手学习 本文内容: 简单记录一下主要代码逻辑 转向机钩子的逻辑设定 1.钩 ...

  3. 【小游戏】2D游戏棍子英雄StickHero(无尽模式)

    欢迎加入Unity业内qq交流群:956187480 文末有源工程地址 难度系数: ★☆☆☆☆ 游戏玩法: 棍子英雄,鼠标长按生成棍子搭桥,走过沟壑. 本文内容: 简单记录一下主要代码逻辑,给代码添加 ...

  4. 【小游戏】2D游戏拼图Puzzle华容道风格(两种模式)

    目录 一:初始化游戏界面 二:图块逻辑脚本编写 三:结果判定 欢迎加入Unity业内qq交流群:956187480    文末有源工程地址 难度系数: ★☆☆☆☆ 游戏玩法: 拼图游戏,传统华容道类型 ...

  5. 【小游戏】2D游戏炸弹超人BombSuperman(无限关卡模式)

    目录 一:简介 二:制作逻辑 1.地图关卡生成逻辑 2.对象管理逻辑

  6. 2d游戏和 3d游戏的区别

    2D游戏和3D游戏的主要区别 一.总结 一句话总结:2D中的单位就是贴图,3D中的单位还有高 1. 3D 和 2D 游戏的区别主要体现在呈现画面和文件体积上: 2. 借助 3D 引擎可以提升 2D 游 ...

  7. 2D游戏和3D游戏的主要区别

    游戏的体现形式最主要是 2D 和 3D.最近比较流行的 AR/VR 等,都是属于 3D 类的体现形式.       最初的游戏,2D 是绝对的主流.虽然现如今 3D 游戏大行其道,但是 2D 游戏还是 ...

  8. WEBGL 2D游戏引擎研发系列 第一章 新的开始

    WEBGL 2D游戏引擎研发系列 第一章 <新的开始> ~\(≥▽≤)/~HTML5游戏开发者社区(群号:326492427) 转载请注明出处:http://html5gamedev.or ...

  9. WEBGL 2D游戏引擎研发系列 第四章 感想以及矩阵

    WEBGL 2D游戏引擎研发系列 第四章 <感想以及矩阵> HTML5游戏开发者社区(群号:326492427) 转载请注明出处:http://html5gamedev.org/ HTML ...

最新文章

  1. 希尔排序及C语言实现
  2. 一块网卡绑定多个ip
  3. 浏览器的垃圾回收机制
  4. linux学习笔记-第六课-/etc/passwd,/etc/shadow,useradd,su,sudo等
  5. python word
  6. 华为上机试---购物单(算法:背包问题)
  7. 买g 怀旧 被封号_防火防盗防封号 《魔兽世界》怀旧服自救指南
  8. 关于Platinum库的MediaRender具体C++代码实现探讨
  9. Android 耳机插入过程分析 (AudioManager部分)
  10. 3ds Max 2012 简体中文版 带注册机32位64位
  11. 电视剧《春草》剧情介绍
  12. DC-DC电源设计[基于MP2315]
  13. 12.Opencv大作业——实现鼠标绘制基本图形
  14. 实时操作系统和非实时操作系统的区别
  15. iPhone6对flex的兼容
  16. c语言程序设计(微课版),C语言程序设计教程(微课版)
  17. The type java.lang.Object cannot be resolved It is indirectly referenced ... .
  18. 深入理解xhr responseType blob arrayBuffer document text json使用
  19. 【ESP 保姆级教程】疯狂传感器篇 —— 案例:ESP8266 + MQ2烟雾传感器 + webserver(局域网内曲线变化图)
  20. 从二本到ICLR杰出论文奖,我用了20年

热门文章

  1. kingcms php,KingCMS php版网站标签模版制作教程(二)
  2. Linux vsftp
  3. 一个程序员老总的年终总结2010版 1
  4. python SM2明文密码加解密
  5. AutoMagic使用说明
  6. 计算机用用技巧,计算机使用技巧介绍汇总
  7. 程序员七夕特刊,绝无狗粮添加
  8. java咖啡机提示除钙,请注意:咖啡机的14种错误用法!
  9. 【罗技】M590 鼠标驱动
  10. 仿微信div可编辑ctrl+enter换行,enter发送