目录
目录
一.参考文章:
游戏开发教程:如何实现杀戮尖塔中的选择箭头 (这篇讲的很详细了)
二.目标
实现杀戮尖塔的拖拽箭头:
1.贝塞尔曲线
2.从卡牌中心拖出
3.指向敌人变色
最终效果:
演示
三.贝塞尔曲线
看到这个箭头第一反应就是很像钢笔工具,然后搜了一下,就知道了是贝塞尔曲线
具体什么是贝塞尔曲线我就给别人的链接吧,没啥必要在这复制黏贴:
河流,道路,UI工具,贝塞尔曲线实战应用
最终代码(三阶):
/// <summary>
/// 三阶贝塞尔曲线
/// </summary>
/// <param name="t"></param>
/// <param name="controlP">0:起始点 1:控制点1 2:控制点2 3:重点</param>
/// <returns></returns>
private Vector2 ThirdOrderBezierCurve(float t, Vector2[] controlP) {
Vector2 res = new Vector2();
if (controlP.Length != 4) {
Debug.LogWarning("三阶贝塞尔坐标需要4个,ThirdOrderBezierCurve");
return res;
}
float u = 1 - t;
float partx0 = controlP[0].x * u * u * u;
float partx1 = 3 * t * u * u * controlP[1].x;
float partx2 = 3 * t * t * u * controlP[2].x;
float partx3 = t * t * t * controlP[3].x;
float x = partx0 + partx1 + partx2 + partx3;
res.x = x;
float party0 = controlP[0].y * u * u * u;
float party1 = 3 * t * u * u * controlP[1].y;
float party2 = 3 * t * t * u * controlP[2].y;
float party3 = t * t * t * controlP[3].y;
float y = party0 + party1 + party2 + party3;
res.y = y;
return res;
}
/// <summary>
/// 获取贝塞尔曲线[三阶]
/// </summary>
/// <param name="originPoint">0:起始点 1:控制点 2:终点</param>
/// <param name="stepNum">需要获取的节点数</param>
/// <returns></returns>
public List<Vector2> CreateThirdOrderCurve(Vector2[] originPoint, uint stepNum) {
if (originPoint.Length != 4) {
Debug.LogWarning("三阶贝塞尔坐标需要4个,请检查CreateThirdOrderCurve");
return new List<Vector2>();
}
List<Vector2> CurvePointList = new List<Vector2>();
float u = 1;
float CurveStep = 1 / (float) stepNum;
while (u > 0) {
Vector2 Point = ThirdOrderBezierCurve(u, originPoint);
CurvePointList.Add(Point);
u = u - CurveStep;
}
CurvePointList.Add(originPoint[0]);
return CurvePointList;
}
1.箭头优化
主要有几个吧:箭头指向,箭头缩放
2.箭头指向
这个只要后一个指向前一个就行,最后一个就和前一个保持一致就行:
//旋转
if (index > 0)
{
Vector3 vec3_angle = m_ArrowStem[index - 1].transform.position - item.transform.position;
Vector2 vec2_angle = new Vector2(vec3_angle.x, vec3_angle.y);
var Euler = new Vector3(0, 0, Vector2.SignedAngle(Vector2.up, vec2_angle));
item.transform.rotation = Quaternion.Euler(Euler);
}
//对大箭头特殊处理
m_ArrowStem[0].transform.rotation = m_ArrowStem[1].transform.rotation;
3.箭头缩放
直接贴代码吧,主要是选函数,手动调:
//缩放
float ScaleDivisor = Mathf.Log((int) CONST_STEP_NUM - index + 1, CONST_LOG_DIVISOR);
item.transform.localScale = new Vector3(ScaleDivisor, ScaleDivisor, ScaleDivisor) * CONST_SCALE_DIVISOR;
四.从卡牌中心拖出
这里主要是卡牌不是按钮,所以需要重写一下IPointerDownHandler,在鼠标按下的时候生成箭头就行。因为只是展示功能不想这么麻烦,所以我没有用生成,直接把场景中的箭头显示出来了。
//CardItem.cs
private void SetArrowStartPoint() {
var RectTransform = gameObject.GetComponent<RectTransform>();
Vector3[] Corners = new Vector3[4];
RectTransform.GetWorldCorners(Corners);
float x = Corners[0].x + (Corners[3].x - Corners[0].x) / 2;
float y = Corners[0].y + (Corners[1].y - Corners[0].y) / 2;
Vector3 StartPosition = new Vector3(x, y, 0);
m_DragArrowItem.SetStartPoint(StartPosition);
}
private void InitClickEvent() {
m_ClickCard.PointerDownEvent = () => {
go_Arrow.SetActive(true);
SetArrowStartPoint();
};
}
//ClickCard .cs
public class ClickCard : MonoBehaviour, IPointerDownHandler{
private Action m_PointerDownEvent;
public Action PointerDownEvent {
set => m_PointerDownEvent = value;
}
public void OnPointerDown(PointerEventData eventData) {
m_PointerDownEvent?.Invoke();
}
}
五.指向敌人变色
这边分情况吧,正常来说敌人是场景物体之类的,那只要发射射线就行。不过杀戮尖塔目测是live2d这种,这种算是UI,平常射线是检测不到的。所以我用的方法是UI射线穿透,通过点击事件向下发射线,找到鼠标下的其他UI,挂在卡牌UI上就行。射线穿透的话可以去看一下雨凇大佬的教程。
// ClickCard : MonoBehaviour , IDragHandler
public void OnDrag(PointerEventData eventData) {
List<RaycastResult> raycastResults = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventData, raycastResults);
if (raycastResults.Count == 0) {
m_RecoverEvent?.Invoke();
return;
}
foreach (var rayResult in raycastResults) {
if (rayResult.gameObject.tag == m_TargetName) {
m_DragEvent?.Invoke();
return;
}
}
m_RecoverEvent?.Invoke();
}
六.完整工程
完整的我就贴这边吧,传github了: