概要
本文根据教程(【【Unity教程搬运】Unity VFX Graph - 电弧教程】https://www.bilibili.com/video/BV1hm4y1r7H6?vd_source=033061353294ae0352cec4c059f20a65)所制作的电弧进行开发,小伙伴可以先观看一下视频来完成素材准备,当然也可以通过unity商店直接购买(我可没说淘宝也能买嗷),素材名称:VFX Graph - Procedural Electricity - Vol. 1。
效果先行展示
此为效果图,使用了基于VFX Property Binder的动态绑定方法,写了个新属性PosBinder继承了VFXBinderBase
思考过程
上文红字提到的教程中有说到,这个电弧可以根据自身携带的VFXPropertyBinder组件对几个坐标进行动态绑定,即在电弧的Inspect界面将带有transform的组件拖拽至绑定点Postion对应的target即可,如图。
下文我们会将这几个带绿色方块的东西称作VFX Property(因为我也不是很确定这东西是不是这么命名的,还没研究的非常透彻),如下图
(接上文黑字)但是这样导致一个严重的问题,如果不进行提前绑定,电流无法在游戏运行时主动的把敌人的信息绑定到Poston.target上来,而Unity自己提供的VFX Property数据是用private封装上的,虽然能在界面上看到这些经过序列化(SerializeField)的信息但是无法用代码获取到他们,所以依靠原本的VFX Property我们无法进行在运行时的动态绑定,此时我们需要自己写一个新的VFX Property来提供public的数据来供我们进行运行时的动态绑定。
经过查看VFXPropertyBinder的文档我们了解到,这些VFX Property是继承了一个叫做VFXBinderBase的东西实现的,如下图
于是我们自定义一个新的类,就叫PosBinder(这个随便大家怎么喜欢怎么来,起名字无所谓的),继承VFXBinderBase。然后对VFXBinderBase需要的函数进行实现。
理论可行,进入实践
写法如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.VFX;
using UnityEngine.VFX.Utility;
[ExecuteInEditMode]
public class PosBinder : VFXBinderBase
{
public ExposedProperty property;
public Transform Target;
public override bool IsValid(VisualEffect component)
{
return component.HasVector3(property);
}
public override string ToString()
{
return "Postion:"+ property.ToString()+"->"+ Target;
}
public override void UpdateBinding(VisualEffect component)
{
component.SetVector3(property, Target.position);
}
}
ExposedProperty是给我们绑定结点一个命名,
Target就是我们这个结点要绑定的目标,
IsValid方法用来校验结点是否被重复注册等问题,
ToString就是绿方块后边这串字的由来
其中最核心的部分,就是UpdateBinding函数,这个函数实现结点在游戏中的动态绑定,看见Update想必大家并不陌生,这个函数就负责每帧对结点的目标进行一次绑定以防止其脱轨,具体实现方法不多做赘述。
PosBinder实现完成后,我们需要在Unity界面将这个PosBinder用AddComponent的方式添加到该电弧的VFXPropertyBinder中,如图(这里用这种方法主要是博主不知道如何将PosBinder写到右下角那个加号里,如果有大佬有方法实现,还请多多指教)
放上去后PosBinder还需要默认绑定来保证创建它时游戏不会报错,所以我们将他作为父物体,随便创建几个空物体放上去就好,像这样
现在电弧部分就制作完成了,我们需要一个载体来实现调用它的属性并用他和敌人进行动态绑定,随便一个东西就行,实现代码如下
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEngine.VFX;
using UnityEngine.VFX.Utility;
[RequireComponent(typeof(Collider),typeof(Rigidbody),typeof(Transform))]
public class Bullet : MonoBehaviour
{
private VFXPropertyBinder[] binder;
private VisualEffect[] visualEffect;
//bullet property difine
public Collider BltColider;
public Rigidbody BltRigidbody;
public GameObject lightning;
public List<GameObject> lightnings = new List<GameObject>();
public int forwardForce=200;
// Start is called before the first frame update
void Start()
{
BltColider = gameObject.GetComponent<Collider>();
BltRigidbody = gameObject.GetComponent<Rigidbody>();
GetComponent<Rigidbody>().AddForce(transform.forward * forwardForce);
}
// Update is called once per frame
void Update()
{
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "enemy")
{
// Position v1;
Vector3 direction = other.transform.position - transform.position;
GameObject lightningAttack = Instantiate(lightning, transform.position, transform.rotation);
lightnings.Add(lightningAttack);
binder = lightningAttack.GetComponentsInChildren<VFXPropertyBinder>();
visualEffect = lightningAttack.GetComponentsInChildren<VisualEffect>();
PosBinder[] posBinders = lightningAttack.GetComponentsInChildren<PosBinder>();
posBinders[0].Target = transform;
posBinders[1].Target = transform;
posBinders[2].Target = transform;
posBinders[3].Target = other.transform;
posBinders[4].Target = transform;
posBinders[5].Target = transform;
posBinders[6].Target = transform;
posBinders[7].Target = other.transform;
}
}
private void OnDestroy()
{
for(int i = 0; i < lightnings.Count; i++)
{
Destroy(lightnings[i]);
}
}
}
完成后将这个脚本放到你的电弧承载物上,如果有电球的话那将是极好的。这个承载物需要有这些组件,并把制作好的电弧放到Lightning上
结语
好啦现在你的电弧已经实现对敌人的动态绑定啦,我知道你想学爆炸,想要电球,我会尽快将电球和爆炸相关的文章发表让你看到的,如果你喜欢还请点一个小小的赞,感谢你你是个好人,超级大好人。