最终效果展示
主要步骤
一. 扇形开牌
二. 鼠标指向卡牌时,卡牌强调动画
①卡牌高度提升
②卡牌旋转归零
③卡牌层级高于其他手牌
三. 卡牌使用效果
1. 攻击类型卡牌
①拖拽超过一定高度之后卡牌会移动到手牌中心位置
②出现攻击引导箭头
③成功指向目标怪物后打出
2. 技能能力类型卡牌
①可自由拖动
②脱离手牌高度后打出
四. 卡牌使用结束效果
1. 播放攻击特效
2. 播放卡牌收尾特效
①卡牌从当前位置移动到中心位置
②卡牌居中悬停展示几毫秒
③播放回归弃牌堆动画
代码详解
一. 扇形开牌
核心代码
public class CardItem : MonoBehaviour
{
/// <summary>
/// 卡牌扇形展开中心点
/// </summary>
public Vector3 root;
/// <summary>
/// 展开角度
/// </summary>
public float rot;
/// <summary>
/// 展开半径
/// </summary>
public float size;
/// <summary>
/// 动画速度
/// </summary>
public float animSpeed = 10;
/// <summary>
/// 高度值(决定卡牌层级)
/// </summary>
public float zPos=0;
public void RefreshData(Vector3 root,float rot, float size,float zPos)
{
this.root = root;
this.rot = rot;
this.size = size;
this.zPos = -zPos*0.02f;
}
// Update is called once per frame
void Update()
{
SetPos();
}
public void SetPos()
{
//设置卡牌位置
float x = root.x + Mathf.Cos(rot) * size;
float y = root.y + Mathf.Sin(rot) * size;
transform.position = Vector3.Lerp(transform.position, new Vector3(x, y, root.z+this.zPos), Time.deltaTime * animSpeed);
//设置卡牌角度
float rotZ = GetAngleInDegrees(root, transform.position);
Vector3 localEulerAngles = transform.localEulerAngles;
Quaternion rotationQuaternion = Quaternion.Euler(new Vector3(0, 0, rotZ));
transform.rotation = Quaternion.RotateTowards(transform.rotation, rotationQuaternion, Time.deltaTime * animSpeed * 30);
}
/// <summary>
/// 获取两个向量之间的弧度值0-2π
/// </summary> /// <param name="positionA">点A坐标</param>
/// <param name="positionB">点B坐标</param>
/// <returns></returns>
public static float GetAngleInDegrees(Vector3 positionA, Vector3 positionB)
{
// 计算从A指向B的向量
Vector3 direction = positionB - positionA;
// 将向量标准化
Vector3 normalizedDirection = direction.normalized;
// 计算夹角的弧度值
float dotProduct = Vector3.Dot(normalizedDirection, Vector3.up);
float angleInRadians = Mathf.Acos(dotProduct);
//判断夹角的方向:通过计算一个参考向量与两个物体之间的叉乘,可以确定夹角是顺时针还是逆时针方向。这将帮助我们将夹角的范围扩展到0到360度。
Vector3 cross = Vector3.Cross(normalizedDirection, Vector3.up);
if (cross.z > 0)
{
angleInRadians = 2 * Mathf.PI - angleInRadians;
}
// 将弧度值转换为角度值
float angleInDegrees = angleInRadians * Mathf.Rad2Deg;
return angleInDegrees;
}}
public class CardManager : MonoBehaviour
{
/// <summary>
/// 卡牌起始位置
/// </summary>
public Vector3 rootPos=new Vector3(0,-33.5f,20);
/// <summary>
/// 卡牌对象
/// </summary>
public GameObject cardItem;
/// <summary>
/// 扇形半径
/// </summary>
public float size =30f;
/// <summary>
/// 卡牌出现最大位置
/// </summary>
private float minPos = 1.415f;
/// <summary>
/// 卡牌出现最小位置
/// </summary>
private float maxPos = 1.73f;
/// <summary>
/// 手牌列表
/// </summary>
private List<CardItem> cardList;
/// <summary>
/// 手牌位置
/// </summary>
private List<float> rotPos;
/// <summary>
/// 最大手牌数量
/// </summary>
private int CardMaxCount=8;
void Start()
{ InitCard();
} /// <summary>
/// 数据初始化
/// </summary>
public void InitCard()
{
rotPos=InitRotPos(CardMaxCount);
}
/// <summary>
/// 初始化位置
/// </summary>
/// <param name="count"></param>
/// <param name="interval"></param>
/// <returns></returns>
public List<float> InitRotPos(int count)
{
List<float> rotPos=new List<float>();
float interval = (maxPos - minPos)/count;
for (int i = 0; i < count; i++)
{
float nowPos = maxPos - interval * i;
rotPos.Add(nowPos);
}
return rotPos;
}
// Update is called once per frame
void Update()
{
TaskItemDetection();
RefereshCard();
}
/// <summary>
/// 添加卡牌
/// </summary>
public void AddCard()
{
if (cardList==null)
{
cardList=new List<CardItem>();
}
if (cardList.Count>=CardMaxCount)
{
Debug.Log("手牌数量上限");
return;
}
GameObject item = Instantiate(cardItem,this.transform);
CardItem text=item.GetComponent<CardItem>();
text.RefreshData(rootPos,0,0,0);
cardList.Add(text);
}
/// <summary>
/// 手牌状态刷新
/// </summary>
public void RefereshCard()
{
if (cardList==null)
{
return;
}
for (int i = 0; i < cardList.Count; i++)
{
cardList[i].RefreshData(rootPos,rotPos[i],size,i);
}
}
/// <summary>
/// 销毁卡牌
/// </summary>
public void RemoveCard()
{
if (cardList==null)
{
return;
}
CardItem item = cardList[cardList.Count - 1];
cardList.Remove(item);
Destroy(item.gameObject);
}
/// <summary>
/// 销毁卡牌
/// </summary>
/// <param name="item"></param>
public void RemoveCard(CardItem item)
{
if (cardList==null)
{
return;
}
cardList.Remove(item);
Destroy(item.gameObject);
}
private Vector3 oldmousePosition;
/// <summary>
/// 玩家操作检测
/// </summary>
public void TaskItemDetection()
{
if (Input.GetKeyDown(KeyCode.A))
{
AddCard();
}
}
}