百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

子弹反射和曲线激光——用Unity还原东方弹幕(下)

bigegpt 2024-08-10 12:15 7 浏览

作者:QXYO


前言

在上篇中只介绍了两种弹幕样式的生成,很明显对于一款弹幕游戏来说是远远不够的,所以本次就再来尝试还原一下东方的两种弹幕,反射子弹和曲线激光。

同样的先来看看效果

本文主要内容:

  1. 控制子弹的反射

2. 曲线激光的生成


一、子弹在矩形范围内反射

虽然标题是矩形,但同样可以控制子弹是否只在单面反射。在Unity中可以用Vector3.Reflect

public static Vector3 Reflect(Vector3 inDirection, Vector3 inNormal)

来获取到子弹与指定平面的反射角,并且有多方法来判断子弹是否到了指定平面,碰撞检测、射线、数学运算等方式。这里我就用数学方法来实现子弹反射。

首先定义矩形参数

public float RectangleX = 0; //长方形的一个边

public float RectangleZ = 0; //长方形的一个边

public Transform CenterPos; //图形中心点

如果是未旋转的矩形那么边界平面就很好计算了,就是中心点位置+长或宽/2的位置,如果是旋转过的矩形那么就需要点简单的数学计算了,这里就不再展示。


var disX = transform.position.x - CenterPos.position.x;

var AbsdisX = disX > 0 ? disX : -disX;

//取x轴距离的绝对值,在数值不溢出的情况下比Mathf.Abs()效率高

var disZ = transform.position.z - CenterPos.position.z;

var AbsdisZ = disZ > 0 ? disZ : -disZ;


获取到边界后通过之前提到的 Vector3.Reflect方法就可以获取到反射角,传入的参数为方向也就是transform.forward和平面的法向量。

...

return Vector3.Reflect(transform.forward, disX > 0 ? -CenterPos.right : CenterPos.right);

...

return Vector3.Reflect(transform.forward, disZ > 0 ? -CenterPos.forward : CenterPos.forward);

...

如果中心点位置每帧移动速度过快,内部的子弹就会“逃出”反射范围,但仍然会在原范围内进行反射移动,所以可以添加判断在范围外的子弹不进行检测。

下面给出完整代码

if (isRectangleRef) //长方形检测

{

var disX = transform.position.x - CenterPos.position.x;

var AbsdisX = disX > 0 ? disX : -disX; //取x轴距离的绝对值,在数值不溢出的情况下比Mathf.Abs()效率高

var disZ = transform.position.z - CenterPos.position.z;

var AbsdisZ = disZ > 0 ? disZ : -disZ;

if (RectangleX !=0 && !isOut && AbsdisX > RectangleX)

{

isOut = true;

return Vector3.Reflect(transform.forward, disX > 0 ? -CenterPos.right : CenterPos.right);

}

if (RectangleZ != 0 && !isOut && AbsdisZ > RectangleZ)

{

isOut = true;

return Vector3.Reflect(transform.forward, disZ > 0 ? -CenterPos.forward : CenterPos.forward);

}

if (AbsdisX < RectangleX && AbsdisZ < RectangleZ)

{

isOut = false;

}

}


二、子弹在圆形范围内反射

原理和之前一样,只不过要通过算距离来判断是否到达边界。需要参数:距离圆心的半径(radius)。注意检测距离一般用距离的平方来判断,减少开根号带来的性能消耗。

var dis =(transform.position - CenterPos.position).sqrMagnitude;

到达边界之后的法线向量其实就是该点朝向圆心的向量,即(CenterPos.position - transform.position)

if (!isOut) //防止在圈外重复检测

{

if (dis > Radius * Radius && dis < Radius * Radius + 4) //防止移动过快导致圆圈外的子弹的运动问题

{

isOut = true;

return Vector3.Reflect(transform.forward, (CenterPos.position - transform.position).normalized);//法线向量就是当前位置朝向圆形半径的向量

}

}

else

{

if (dis < Radius * Radius)

{

isOut = false;

}

}

来看下效果

三、曲线激光

形成直线激光子弹的方式有很多,特效粒子、长方形预制体等。但这些方法实现方便配置的曲线激光比较困难,所以本次使用的是LineRenderer组件。生成的曲线为正、余弦曲线。

本次主要用到的LineRenderer 属性:

Positions: 设置线的开始点和结束点的位置。曲线就是生成了许多的位置信息并将其连接起来形成曲线。

Start Width:设置线开始时的宽度。

End Width:设置线结束时的宽度。

Use World Space:是否用世界坐标,可以根据需求判断是否勾选,本方法取消了勾选。

同样的先设置参数

public float frequency; //频率

public float amplitude; //振幅

public float lineDistance; //相邻两个点的距离

public float width; //设置宽度

public int lineCount; //曲线生成所需点个数,越多越平滑


正、余弦曲线的偏移量(Y的值)可以很简单的通过 Mathf.Cos()来获取,曲线的移动有几种方法:

1、通过开始就计算出Y轴的偏移量,使LineRenderer的每个Position的相对于自身旋转的X轴不变,Y轴随时间变化为计算的偏移量,因为取消勾选了Use World Space,所以可以通过修改自身的transform.position来实现移动。

void GetCurve() //获取曲线坐标

{

for (int i = 0; i < lineCount; i++)

{

float t = frequency * Mathf.PI / lineCount * i;

linePos[i] = new Vector3(disI * i, 1, Mathf.Cos(t) * amplitude);

}

}

2、LineRenderer的前一个点的位置是后一个点下一次移动到的位置,这样每帧修改第一个点的位置即可。为了防止激光突兀的全部显示,点位要逐个生成。本次生成和移动的方式是通过协程来实现。

float GetPosY(float x) //获取Y轴偏移量

{

return Mathf.Cos(frequency * x * Mathf.PI) * amplitude;

}

...

IEnumerator Move()

{

if (CreatCount == lineCount) //判断点位是否全部生成完毕

{

linePos = new Vector3[lineRenderer.positionCount];

lineRenderer.GetPositions(linePos); // 重新获取当前点位数据

}

var offset = new Vector3(GetPosY(lineDistance / lineCount * disI), 1, lineDistance / lineCount * disI);

//获取本次移动后第一个点的位置

disI++;

if (CreatCount < lineCount) //逐步生成点位

{

CreatCount++;

lineRenderer.positionCount = CreatCount;

}

lineRenderer.SetPosition(CreatCount - 1, offset);

linePos[CreatCount - 1] = offset;

for (int i = CreatCount - 2; i >= 0; i--) //跟随前一个点位

{

lineRenderer.SetPosition(i, linePos[i + 1]);

}

yield return new WaitForSeconds(speed * Time.fixedDeltaTime);

}


以上都是在3D场景下的弹幕,大家有兴趣也可以修改成3D样式。

由于还原东方弹幕所需要大量时间进行微调参数,所以本次就只将一些基础弹幕样式展现出来供大家参考,最后放上工程链接,建议使用2019以上的版本打开:

地址:https://pan.baidu.com/share/init?surl=WbHvaViGDLlwBTP3hIwziA

?提取码:vf43



对游戏开发学习感兴趣的盆友,欢迎访问:http://levelpp.com/

同时,也欢迎加入游戏开发群搅基:610475807

相关推荐

C#.NET Autofac 详解(c# autoit)

简介Autofac是一个成熟的、功能丰富的.NET依赖注入(DI)容器。相比于内置容器,它额外提供:模块化注册、装饰器(Decorator)、拦截器(Interceptor)、强o的属性/方法注...

webapi 全流程(webapi怎么部署)

C#中的WebAPIMinimalApi没有控制器,普通api有控制器,MinimalApi是直达型,精简了很多中间代码,广泛适用于微服务架构MinimalApi一切都在组控制台应用程序类【Progr...

.NET外挂系列:3. 了解 harmony 中灵活的纯手工注入方式

一:背景1.讲故事上一篇我们讲到了注解特性,harmony在内部提供了20个HarmonyPatch重载方法尽可能的让大家满足业务开发,那时候我也说了,特性虽然简单粗暴,但只能解决95%...

C# 使用SemanticKernel调用本地大模型deepseek

一、先使用ollama部署好deepseek大模型。具体部署请看前面的头条使用ollama进行本地化部署deepseek大模型二、创建一个空的控制台dotnetnewconsole//添加依赖...

C#.NET 中间件详解(.net core中间件use和run)

简介中间件(Middleware)是ASP.NETCore的核心组件,用于处理HTTP请求和响应的管道机制。它是基于管道模型的轻量级、模块化设计,允许开发者在请求处理过程中插入自定义逻辑。...

IoC 自动注入:让依赖注册不再重复劳动

在ASP.NETCore中,IoC(控制反转)功能通过依赖注入(DI)实现。ASP.NETCore有一个内置的依赖注入容器,可以自动完成依赖注入。我们可以结合反射、特性或程序集扫描来实现自动...

C#.NET 依赖注入详解(c#依赖注入的三种方式)

简介在C#.NET中,依赖注入(DependencyInjection,简称DI)是一种设计模式,用于实现控制反转(InversionofControl,IoC),以降低代码耦合、提高可...

C#从零开始实现一个特性的自动注入功能

在现代软件开发中,依赖注入(DependencyInjection,DI)是实现松耦合、模块化和可测试代码的一个重要实践。C#提供了优秀的DI容器,如ASP.NETCore中自带的Micr...

C#.NET 仓储模式详解(c#仓库货物管理系统)

简介仓储模式(RepositoryPattern)是一种数据访问抽象模式,它在领域模型和数据访问层之间创建了一个隔离层,使得领域模型无需直接与数据访问逻辑交互。仓储模式的核心思想是将数据访问逻辑封装...

C#.NET 泛型详解(c# 泛型 滥用)

简介泛型(Generics)是指在类型或方法定义时使用类型参数,以实现类型安全、可重用和高性能的数据结构与算法为什么需要泛型类型安全防止“装箱/拆箱”带来的性能损耗,并在编译时检测类型错误。可重用同一...

数据分析-相关性分析(相关性 分析)

相关性分析是一种统计方法,用于衡量两个或多个变量之间的关系强度和方向。它通过计算相关系数来量化变量间的线性关系,从而帮助理解变量之间的相互影响。相关性分析常用于数据探索和假设检验,是数据分析和统计建模...

geom_smooth()函数-R语言ggplot2快速入门18

在每节,先运行以下这几行程序。library(ggplot2)library(ggpubr)library(ggtext)#用于个性化图表library(dplyr)#用于数据处理p...

规范申报易错要素解析(规范申报易错要素解析)

为什么要规范申报?规范申报是以满足海关监管、征税、统计等工作为目的,纳税义务人及其代理人依法向海关如实申报的行为,也是海关审接单环节依法监管的重要工作。企业申报的内容须符合《中华人民共和国海关进出口货...

「Eurora」海关编码归类 全球海关编码查询 关务服务

  海关编码是什么?  海关编码即HS编码,为编码协调制度的简称。  其全称为《商品名称及编码协调制度的国际公约》(InternationalConventionforHarmonizedCo...

9月1日起,河南省税务部门对豆制品加工业试行新政7类豆制品均适用投入产出法

全媒体记者杨晓川报道9月2日,记者从税务部门获悉,为减轻纳税人税收负担,完善农产品增值税进项税额抵扣机制,根据相关规定,结合我省实际情况,经广泛调查研究和征求意见,从9月1日起,我省税务部门对豆制品...