You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 15:41:47