Unity技术问题:如何在本地空间绕枢轴点旋转子物体武器
2D游戏武器动态挥砍实现难题
我正在开发一款2D游戏,玩家Prefab下挂载了剑这类武器子物体:
- 日常状态下,武器随玩家在世界空间平移,保持固定的本地位置(攻击状态除外)
- 武器会自动指向附近敌人,当距离达标时发起挥砍攻击
核心需求
- 挥砍时,武器需绕特定枢轴点沿圆弧运动:该枢轴点定义为「武器射程一半、朝向敌人的位置」
- 挥砍启动后,弧线的本地位置与旋转需固定,不再响应敌人位置变化,仅随玩家在世界空间同步平移
- 攻击分为三个阶段:后摆(Backswing)、前挥(Foreswing)、收招(Recovery),重点要实现前挥阶段的圆弧轨迹,其余阶段可通过本地旋转与插值完成
- 由于射程需要动态调整,关键帧动画方案不可行
遇到的问题
RotateAround仅支持世界空间操作,当武器与目标枢轴随玩家平移时会出现异常- 尝试用
Vector3.Slerp控制transform.localPosition,无法实现理想的圆形挥砍弧线
现有代码
const int BACKSWING = 0; const int FORESWING = 1; const int RECOVER = 2; float[] timeFrac = { .15f, .25f, .6f }; float[] rotations = { 120f, -240f, 120f }; float backSwingDistMultiplier = .5f; //Swing Attack public override IEnumerator Attack(float startAngle) { var totalAttackTime = GetAttackTime(); var backSwingDist = backSwingDistMultiplier * Range; var startPos = transform.localPosition; var slerpCenterDiff = PerpDir(dir).normalized; //Interpolation arrays float[] swingTimes = { timeFrac[BACKSWING] * totalAttackTime, timeFrac[FORESWING] * totalAttackTime, timeFrac[RECOVER] * totalAttackTime }; float[] startAngles = { startAngle, startAngle + rotations[BACKSWING], startAngle + rotations[BACKSWING] + rotations[FORESWING] }; Vector3[] swingPositions = { startPos - (dir - slerpCenterDiff ) * backSwingDist, startPos + dir * Range + slerpCenterDiff * backSwingDist }; Vector3[] slerpCenters = { (startPos + swingPositions[BACKSWING]) * .5f + slerpCenterDiff , ((swingPositions[BACKSWING] + swingPositions[FORESWING]) * .5f) + slerpCenterDiff }; Vector3[] slerpStarts = { startPos - slerpCenters[BACKSWING], swingPositions[BACKSWING] - slerpCenters[FORESWING]}; Vector3[] slerpEnds = { swingPositions[BACKSWING] - slerpCenters[BACKSWING], swingPositions[FORESWING] - slerpCenters[FORESWING]}; timer = 0; float percentDone; //A swing attack has backswing, foreswing, and recovery for (int swing = 0; swing <= 2; swing++) { while (timer < swingTimes[swing]) { percentDone = timer / swingTimes[swing]; //Backswing and Foreswing will slerp if (swing < RECOVER) { transform.localPosition = Vector3.Slerp(slerpStarts[swing], slerpEnds[swing], percentDone); transform.localPosition += slerpCenters[swing]; } else { //Recover will lerp transform.localPosition = Vector3.Lerp(swingPositions[FORESWING], startPos, percentDone); } transform.localRotation = Quaternion.Euler(0, 0, startAngles[swing] + rotations[swing] * percentDone); timer += Time.deltaTime; yield return null; } transform.localRotation = Quaternion.Euler(0, 0, startAngles[swing] + rotations[swing]); timer -= swingTimes[swing]; } transform.localPosition = startPos; }
内容的提问来源于stack exchange,提问作者Daniel Haacke
相关产品推荐
相关产品推荐

