《海岛奇兵》是由芬兰Supercell Oy公司开发,Supercell Oy及昆仑游戏发行的一款战斗策略类、全球同服的手机游戏。估计大部分人都玩过,即使没有玩过也应该知道这款游戏吧。本人之前就热衷于这款游戏,对于热爱游戏开发的我来说,看见这款游戏的效果,实在是叹为观止,甚至想把所有的效果都模拟过来放入自己的游戏中。这不,现在就来用Unity模拟它收获资源产生大量资源图标飞入到背包的效果。
204913367.png我就取名为WeiButEffect
C#脚本,主要就是这个类实现的所有功能,先上源码。
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 模拟《海岛奇兵》收获资源的爆炸效果
/// weibut.com
/// </summary>
public class WeiButEffect : MonoBehaviour {
/// <summary>
/// 移动到的目标
/// </summary>
public Transform target;
/// <summary>
/// 运动时间
/// </summary>
public float factor = 1f;
/// <summary>
/// 生成个数
/// </summary>
public int amount;
/// <summary>
/// 需要生成的物体
/// </summary>
public Transform prefab;
/// <summary>
/// 爆炸范围
/// </summary>
public float explosionRadius = 200;
public System.Action onFinish;//完成后回调
float time0 = 0;
List<Vector3> ctrlPoints = new List<Vector3>();
List<Transform> particles = new List<Transform>();
public void PlayEffect()
{
int n = Mathf.Max(1, amount);
for (int i = 0; i < n; i++)
{
if (prefab)
{
GenerateParticle(prefab);
}
}
time0 = Time.time;
}
void GenerateParticle(Transform prefab)
{
var p = Instantiate(prefab, Vector3.zero, Quaternion.identity).gameObject;
p.transform.SetParent(transform, false);
particles.Add(p.transform);
ctrlPoints.Add(Random.insideUnitSphere * explosionRadius);
}
// Update is called once per frame
void Update () {
if (!this.target)
{
OnFinish();
return;
}
float t = (Time.time - time0) / Mathf.Max(0.1f, factor);
if (t > 1)
{
t = 1;
OnFinish();
}
Vector3 target = GetTargetPositionLocal();
for (int i = 0; i < ctrlPoints.Count; i++)
{
Vector3 ctrl = ctrlPoints[i];
Vector3 begin = Vector3.zero;
Vector3 pos = Vector3.Lerp(Vector3.Lerp(begin, ctrl, t), Vector3.Lerp(ctrl, target, t), t);
particles[i].localPosition = pos;
}
}
void OnFinish()
{
Destroy(gameObject);
if (onFinish != null)
{
onFinish();
}
}
Vector3 GetTargetPositionLocal()
{
var screenPoint = target.GetScreenPoint();
Vector2 localPoint = Vector2.zero;
GetComponent<RectTransform>().ScreenPointToLocalPosition(screenPoint, out localPoint);
return localPoint;
}
/// <summary>
/// 模拟《海岛奇兵》收获资源的爆炸效果
/// </summary>
/// <param name="parent">创建在哪</param>
/// <param name="target">移动到哪</param>
/// <param name="prefab">移动物体</param>
/// <param name="amount">个数</param>
/// <param name="explosionRadius">扩散范围</param>
/// <param name="onFinish">移动完成回调</param>
/// <returns></returns>
public static WeiButEffect CreateEffect(Transform parent, Transform target, Transform prefab, int amount, float explosionRadius = 200, System.Action onFinish = null)
{
GameObject instance = new GameObject(prefab.name);
instance.transform.SetParent(parent, false);
instance.AddComponent<RectTransform>();
var effect = instance.AddComponent<WeiButEffect>();
effect.prefab = prefab;
effect.amount = amount;
effect.target = target;
effect.onFinish = onFinish;
effect.explosionRadius = explosionRadius;
effect.PlayEffect();
return effect;
}
}
/// <summary>
/// TransForm的扩展
/// </summary>
public static class TRE
{
/// <summary>
/// 获取Canvas里transform的屏幕坐标
/// </summary>
/// <param name="trans"></param>
/// <returns></returns>
public static Vector3 GetScreenPoint(this Transform trans)
{
var canvas = trans.GetComponentInParent<Canvas>();
if (canvas)
{
var uiCamera = canvas.worldCamera ?? Camera.main;
if (canvas.renderMode == RenderMode.WorldSpace)
{
uiCamera.WorldToScreenPoint(trans.position);
}
else if (uiCamera && canvas.renderMode != RenderMode.ScreenSpaceOverlay)
{
return uiCamera.WorldToScreenPoint(trans.position);
}
else
{
return trans.position;
}
}
return Camera.main.WorldToScreenPoint(trans.position);
}
public static bool ScreenPointToLocalPosition(this RectTransform rect, Vector2 screenPoint, out Vector2 localPoint)
{
if (rect)
{
Transform current = rect;
Canvas canvas = null;
for (; current != null; current = current.parent)
{
canvas = current.GetComponent<Canvas>();
if (canvas != null)
{
break;
}
}
var cam = canvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : (canvas.renderMode == RenderMode.ScreenSpaceCamera ? canvas.worldCamera : canvas.worldCamera ?? Camera.main);
return RectTransformUtility.ScreenPointToLocalPointInRectangle(rect.parent.GetComponent<RectTransform>(), screenPoint, cam, out localPoint);
}
localPoint = Vector2.zero;
return false;
}
}
代码这么多,其实很简单,就只调用CreateEffect
静态函数就可以了,参数的意思也都有注释。还有一个静态类TRE
,主要是transform的扩展。
可以这样
1.gif也可以这样
2.gif甚至还可以这样
3.gif当然你想怎样就怎样!!!
这个版本是无音效版的,如果需要请自行扩展。
网友评论