效果图
废话不多说,直接上效果图
原理
原理就是创建一个 轨迹球,在第二场景中模拟白球的物理运动轨迹,并记录轨迹! 也就是创建一个不可见的场景,用来模拟球的运动轨迹绘制。
碰撞后,被碰撞物体的运动轨迹绘制 将动量传递给碰撞对象,得到碰撞的对象。 从而记录被碰撞对象的运动轨迹
场景
Physics为物理场景,GoBallList用来存放要反射的小球,TrackBallTransform为要模拟的轨迹球
代码
有两个关键的代码:
调用 physicsScene.Simulate(0.02f);完成轨迹预测;
这个API 需要 Physics.autoSimulation = false;//关闭 物理模拟
具体代码如下:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;
using Lean.Touch;
using DG.Tweening;
using UnityEngine.SceneManagement;
public class BallPool : MonoBehaviour
{
public List<GameObject> GoBallList = new List<GameObject>();//所有的反射小球
public Transform trackBallTransform;//轨迹球(即需要物理模拟的小球)
private Rigidbody2D trackBallRigidbody;//轨迹球的刚体
private PhysicsScene2D physicsScene; //物理场景
public Vector3 vecBallPoint;//轨迹球的位置
private void Start()
{
CreateBallReflect();//创建反射小球
CreatePhysicsScene();//创建一个用于模拟的场景
}
private void OnEnable()
{
LeanTouch.OnFingerDown += OnFingerDown;
LeanTouch.OnFingerSet += OnFingerSet;
LeanTouch.OnFingerUp += OnFingerUp;
}
private void OnDisable()
{
LeanTouch.OnFingerDown -= OnFingerDown;
LeanTouch.OnFingerSet -= OnFingerSet;
LeanTouch.OnFingerUp -= OnFingerUp;
}
//创建反射小球
private void CreateBallReflect()
{
//创建轨迹球
trackBallTransform = ObjectPool.Instance.Spawn("BallTrack", LobbyCtrl.Instance.transform.parent).transform;
trackBallTransform.name = "TrackBall";
trackBallTransform.position = vecBallPoint;
trackBallRigidbody = trackBallTransform.GetComponent<Rigidbody2D>();
UIHelper.SetActive(false, trackBallTransform);
//创建20个白色反射小球,并隐藏
for (int i = 0; i < 20; i++)
{
GameObject ball = ObjectPool.Instance.Spawn(Const.Prefab_Obj_BallReflect, transform);
ball.name = "BallReflect";
GoBallList.Add(ball);
}
for (int i = 0; i < GoBallList.Count; i++)
{
UIHelper.SetActive(false, GoBallList[i]);
}
}
//创建一个用于模拟的场景
private void CreatePhysicsScene()
{
var scene = SceneManager.CreateScene("Physics");
physicsScene = scene.GetPhysicsScene2D();
//将轨迹球移动到物理场景里
SceneManager.MoveGameObjectToScene(trackBallTransform.gameObject, scene);
}
private void MoveFinger(LeanFinger finger)
{
//显示轨迹球
UIHelper.SetActive(true, trackBallTransform);
//关闭 物理
Physics2D.autoSimulation = false;
//每次移动需要重置轨迹球的位置和力
trackBallTransform.position = ballCtrl.transform.position;
trackBallRigidbody.velocity = Vector3.zero;
Vector2 screenPoint = Camera.main.ScreenToWorldPoint(finger.ScreenPosition);
var dir = (screenPoint - (Vector2)ballCtrl.transform.position).normalized;
//让轨迹球开始物理模拟
trackBallRigidbody.AddForce(dir * Const.BallSpeed);
for (int i = 0; i < GoBallList.Count; i++)
{
GameObject ball = GoBallList[i];
UIHelper.SetActive(true, ball);
physicsScene.Simulate(0.02f);//必须加这一句,值越小白色反射球间距越小
ball.transform.position = trackBallTransform.position;//所有的白色反射小球会放置到轨迹球经过的位置上
}
}
//按下
private void OnFingerDown(LeanFinger finger)
{
MoveFinger(finger);
}
//移动
private void OnFingerSet(LeanFinger finger)
{
MoveFinger(finger);
}
//松开
private void OnFingerUp(LeanFinger finger)
{
//打开物理
Physics2D.autoSimulation = true;
}
//回收弹球
void ClearBallList()
{
UIHelper.SetActive(false, trackBallTransform);
for (int i = 0; i < GoBallList.Count; i++)
{
ObjectPool.Instance.Unspawn(GoBallList[i]);
}
}
}