代码之家  ›  专栏  ›  技术社区  ›  Led

二维游戏:通过预测射弹和单位的交集对移动目标射击

  •  19
  • Led  · 技术社区  · 14 年前

    好吧,这一切都发生在一个美好而简单的二维世界里…:)

    假设在apos位置有一个静止物体a,在bpos位置有一个直线运动物体b,速度为a velocity的弹药弹……

    考虑到B的线速度和A的弹药速度,我怎样才能知道A必须射向B的角度?

    现在目标是物体的当前位置,这意味着当我的射弹到达那里时,单位已经移动到更安全的位置。)

    11 回复  |  直到 7 年前
        1
  •  11
  •   Eric    12 年前

    B --> Bx
    |
    |
    V
    
    By
    
    
    Vy
    ^
    |
    |
    A ---> Vx
    

    Vx = Bx Sqrt(Vx*Vx + Vy*Vy) = Velocity of Ammo

        2
  •  40
  •   Jeffrey Hantin    14 年前

    xtank

    a * sqr(x) + b * x + c == 0
    

    sqr

    a := sqr(target.velocityX) + sqr(target.velocityY) - sqr(projectile_speed)
    b := 2 * (target.velocityX * (target.startX - cannon.X)
              + target.velocityY * (target.startY - cannon.Y))
    c := sqr(target.startX - cannon.X) + sqr(target.startY - cannon.Y)
    

    disc := sqr(b) - 4 * a * c
    

    t1 := (-b + sqrt(disc)) / (2 * a)
    t2 := (-b - sqrt(disc)) / (2 * a)
    

    disc == 0 t1 t2

    t

    aim.X := t * target.velocityX + target.startX
    aim.Y := t * target.velocityY + target.startY
    

    sqr(projectile.X - cannon.X) + sqr(projectile.Y - cannon.Y)
      == sqr(t * projectile_speed)
    

    target.X == t * target.velocityX + target.startX
    target.Y == t * target.velocityY + target.startY
    

    sqr(projectile.X - cannon.X) + sqr(projectile.Y - cannon.Y)
      == sqr(target.X - cannon.X) + sqr(target.Y - cannon.Y)
    

    sqr(projectile.X - cannon.X) + sqr(projectile.Y - cannon.Y)
      == sqr((t * target.velocityX + target.startX) - cannon.X)
       + sqr((t * target.velocityY + target.startY) - cannon.Y)
    

    sqr(t * projectile_speed)
      == sqr((t * target.velocityX + target.startX) - cannon.X)
       + sqr((t * target.velocityY + target.startY) - cannon.Y)
    

    sqr(t * projectile_speed)

    sqr((t * target.velocityX) + (target.startX - cannon.X))
      + sqr((t * target.velocityY) + (target.startY - cannon.Y))
      - sqr(t * projectile_speed)
      == 0
    

    sqr(target.velocityX) * sqr(t)
        + 2 * t * target.velocityX * (target.startX - cannon.X)
        + sqr(target.startX - cannon.X)
    + sqr(target.velocityY) * sqr(t)
        + 2 * t * target.velocityY * (target.startY - cannon.Y)
        + sqr(target.startY - cannon.Y)
    - sqr(projectile_speed) * sqr(t)
      == 0
    

    sqr(target.velocityX) * sqr(t)
        + sqr(target.velocityY) * sqr(t)
        - sqr(projectile_speed) * sqr(t)
    + 2 * t * target.velocityX * (target.startX - cannon.X)
        + 2 * t * target.velocityY * (target.startY - cannon.Y)
    + sqr(target.startX - cannon.X)
        + sqr(target.startY - cannon.Y)
      == 0
    

    (sqr(target.velocityX) + sqr(target.velocityY) - sqr(projectile_speed)) * sqr(t)
      + 2 * (target.velocityX * (target.startX - cannon.X)
           + target.velocityY * (target.startY - cannon.Y)) * t
      + sqr(target.startX - cannon.X) + sqr(target.startY - cannon.Y)
      == 0
    

    a * sqr(x) + b * x + c == 0
    x == (-b ± sqrt(sqr(b) - 4 * a * c)) / (2 * a)
    
        3
  •  21
  •   broofa    9 年前

    /**
     * Return the firing solution for a projectile starting at 'src' with
     * velocity 'v', to hit a target, 'dst'.
     *
     * @param Object src position of shooter
     * @param Object dst position & velocity of target
     * @param Number v   speed of projectile
     * @return Object Coordinate at which to fire (and where intercept occurs)
     *
     * E.g.
     * >>> intercept({x:2, y:4}, {x:5, y:7, vx: 2, vy:1}, 5)
     * = {x: 8, y: 8.5}
     */
    function intercept(src, dst, v) {
      var tx = dst.x - src.x,
          ty = dst.y - src.y,
          tvx = dst.vx,
          tvy = dst.vy;
    
      // Get quadratic equation components
      var a = tvx*tvx + tvy*tvy - v*v;
      var b = 2 * (tvx * tx + tvy * ty);
      var c = tx*tx + ty*ty;    
    
      // Solve quadratic
      var ts = quad(a, b, c); // See quad(), below
    
      // Find smallest positive solution
      var sol = null;
      if (ts) {
        var t0 = ts[0], t1 = ts[1];
        var t = Math.min(t0, t1);
        if (t < 0) t = Math.max(t0, t1);    
        if (t > 0) {
          sol = {
            x: dst.x + dst.vx*t,
            y: dst.y + dst.vy*t
          };
        }
      }
    
      return sol;
    }
    
    
    /**
     * Return solutions for quadratic
     */
    function quad(a,b,c) {
      var sol = null;
      if (Math.abs(a) < 1e-6) {
        if (Math.abs(b) < 1e-6) {
          sol = Math.abs(c) < 1e-6 ? [0,0] : null;
        } else {
          sol = [-c/b, -c/b];
        }
      } else {
        var disc = b*b - 4*a*c;
        if (disc >= 0) {
          disc = Math.sqrt(disc);
          a = 2*a;
          sol = [(-b-disc)/a, (-b+disc)/a];
        }
      }
      return sol;
    }
    
        4
  •  5
  •   Jim G.    7 年前

    origpos = initial position of shooter
    origvel = initial velocity of shooter
    
    targpos = initial position of target
    targvel = initial velocity of target
    
    projvel = velocity of the projectile relative to the origin (cause ur shooting from there)
    speed   = the magnitude of projvel
    t       = time
    

    t

    curprojpos(t) = origpos + t*origvel + t*projvel
    curtargpos(t) = targpos + t*targvel
    

    projvel

    origpos + t*origvel + t*projvel = targpos + t*targvel
        turns into ->
    projvel = (targpos - origpos)/t + targvel - origvel
    

    relpos = targetpos - originpos relvel = targetvel - originvel

    projvel = relpos/t + relvel
    

    projvel.projvel speed^2

    projvel^2 = (relpos/t + relvel)^2
        expands into ->
    speed^2 = relvel.relvel + 2*relpos.relvel/t + relpos.relpos/t^2
    

    a b c

    a  = relvel.relvel - speed^2
    b  = 2*relpos.relvel
    c  = relpos.relpos
    
    h  = -b/(2*a)
    k2  = h*h - c/a
    
    if k2 < 0, then there are no roots and there is no solution
    if k2 = 0, then there is one root at h
        if 0 < h then t = h
        else, no solution
    if k2 > 0, then there are two roots at h - k and h + k, we also know r0 is less than r1.
        k  = sqrt(k2)
        r0 = h - k
        r1 = h + k
        we have the roots, we must now solve for the smallest positive one
        if 0<r0 then t = r0
        elseif 0<r1 then t = r1
        else, no solution
    

     projvel = relpos/t + relvel
    

    globalpos = origpos
    globalvel = origvel + projvel
    

    local function lineartrajectory(origpos,origvel,speed,targpos,targvel)
        local relpos=targpos-origpos
        local relvel=targvel-origvel
        local a=relvel*relvel-speed*speed
        local b=2*relpos*relvel
        local c=relpos*relpos
        if a*a<1e-32 then--code translation for a==0
            if b*b<1e-32 then
                return false,"no solution"
            else
                local h=-c/b
                if 0<h then
                    return origpos,relpos/h+targvel,h
                else
                    return false,"no solution"
                end
            end
        else
            local h=-b/(2*a)
            local k2=h*h-c/a
            if k2<-1e-16 then
                return false,"no solution"
            elseif k2<1e-16 then--code translation for k2==0
                if 0<h then
                    return origpos,relpos/h+targvel,h
                else
                    return false,"no solution"
                end
            else
                local k=k2^0.5
                if k<h then
                    return origpos,relpos/(h-k)+targvel,h-k
                elseif -k<h then
                    return origpos,relpos/(h+k)+targvel,h+k
                else
                    return false,"no solution"
                end
            end
        end
    end
    
        5
  •  2
  •   Joe    14 年前

    http://www.turtlewar.org/

    
    // C++
    static const double pi = 3.14159265358979323846;
    inline double Sin(double a) { return sin(a*(pi/180)); }
    inline double Asin(double y) { return asin(y)*(180/pi); }
    
    bool/*ok*/ Rendezvous(double speed,double targetAngle,double targetRange,
       double targetDirection,double targetSpeed,double* courseAngle,
       double* courseRange)
    {
       // Use trig to calculate coordinate of future collision with target.
       //             c
       //
       //       B        A
       //
       // a        C        b
       //
       // Known:
       //    C = distance to target
       //    b = direction of target travel, relative to it's coordinate
       //    A/B = ratio of speed and target speed
       //
       // Use rule of sines to find unknowns.
       //  sin(a)/A = sin(b)/B = sin(c)/C
       //
       //  a = asin((A/B)*sin(b))
       //  c = 180-a-b
       //  B = C*(sin(b)/sin(c))
    
       bool ok = 0;
       double b = 180-(targetDirection-targetAngle);
       double A_div_B = targetSpeed/speed;
       double C = targetRange;
       double sin_b = Sin(b);
       double sin_a = A_div_B*sin_b;
       // If sin of a is greater than one it means a triangle cannot be
       // constructed with the given angles that have sides with the given
       // ratio.
       if(fabs(sin_a) <= 1)
       {
          double a = Asin(sin_a);
          double c = 180-a-b;
          double sin_c = Sin(c);
          double B;
          if(fabs(sin_c) > .0001)
          {
             B = C*(sin_b/sin_c);
          }
          else
          {
             // Sin of small angles approach zero causing overflow in
             // calculation. For nearly flat triangles just treat as
             // flat.
             B = C/(A_div_B+1);
          }
          // double A = C*(sin_a/sin_c);
          ok = 1;
          *courseAngle = targetAngle+a;
          *courseRange = B;
       }
       return ok;
    }
    
    
        7
  •  1
  •   Kentyman    11 年前

    private Vector3 CalculateProjectileDirection(Vector3 a_MuzzlePosition, float a_ProjectileSpeed, Vector3 a_TargetPosition, Vector3 a_TargetVelocity)
    {
        // make sure it's all in the horizontal plane:
        a_TargetPosition.y = 0.0f;
        a_MuzzlePosition.y = 0.0f;
        a_TargetVelocity.y = 0.0f;
    
        // create a normalized vector that is perpendicular to the vector pointing from the muzzle to the target's current position (a localized x-axis):
        Vector3 perpendicularVector = Vector3.Cross(a_TargetPosition - a_MuzzlePosition, -Vector3.up).normalized;
    
        // project the target's velocity vector onto that localized x-axis:
        Vector3 projectedTargetVelocity = Vector3.Project(a_TargetVelocity, perpendicularVector);
    
        // calculate the angle that the projectile velocity should make with the localized x-axis using the consine:
        float angle = Mathf.Acos(projectedTargetVelocity.magnitude / a_ProjectileSpeed) / Mathf.PI * 180;
    
        if (Vector3.Angle(perpendicularVector, a_TargetVelocity) > 90.0f)
        {
            angle = 180.0f - angle;
        }
    
        // rotate the x-axis so that is points in the desired velocity direction of the projectile:
        Vector3 returnValue = Quaternion.AngleAxis(angle, -Vector3.up) * perpendicularVector;
    
        // give the projectile the correct speed:
        returnValue *= a_ProjectileSpeed;
    
        return returnValue;
    }
    
        8
  •  0
  •   SpiderShlong    11 年前

    S = shooterPos, E = enemyPos, T = targetPos, Sr = shooter range, D = enemyDir
    V = distance from E to T, P = projectile speed, Es = enemy speed
    

    Sr = P*time
    

    V = D*Es*time
    

    iteration = 0;
    while(TargetPoint.hasNotPassedShooter)
    {
        TargetPoint = EnemyPos + (EnemyMovementVector)
        if(distanceFrom(TargetPoint,ShooterPos) < (ShooterRange))
            return TargetPoint;
        iteration++
    }
    
        11
  •  0
  •   Thomas Hyman    9 年前

      tvx = dst.vx;
      tvy = dst.vy;
    

      tvx = dst.vx - shooter.vx;
      tvy = dst.vy - shooter.vy;