2015-02-10 224 views
0

我有兩個Vec3s,Camera Forward和Turret Forward。這兩種載體都在不同的飛機上,其中「攝像機前進」基於自由視角攝像機,「炮塔前進」由其所在的坦克決定,坦克開啓的地形等。塔塔向上和攝像頭向上幾乎不會比賽。在2D平面上旋轉3D矢量

我的問題如下:我希望炮塔能夠以固定的速度(每秒44度)旋轉,以便它始終與照相機指向的方向會聚。如果坦克處於一個奇怪的角度,它不能與相機會聚,它應該找到最近的地方並坐在那裏,而不是無限期地抖動。

我不能爲我的生活似乎解決了這個問題。我嘗試了幾種我在網上發現的方法,總是會產生奇怪的結果。

local forward = player.direction:rotate(player.turret, player.up) 
    local side  = forward:cross(player.up) 
    local projection = self.camera.direction:dot(forward) * forward + self.camera.direction:dot(side) * side 
    local angle  = math.atan2(forward.y, forward.x) - math.atan2(projection.y, projection.x) 

    if angle ~= 0 then 
     local dt = love.timer.getDelta() 

     if angle <= turret_speed * dt then 
      player.turret_velocity = turret_speed 
     elseif angle >= -turret_speed * dt then 
      player.turret_velocity = -turret_speed 
     else 
      player.turret_velocity = 0 
      player.turret   = player.turret + angle 
     end 
    end 

Figure 1

回答

0

經過一些更多的研究和測試,我結束了以下解決方案。它運作順暢!

function Gameplay:moved_axisright(joystick, x, y) 
    if not self.manager.id then return end 

    local turret_speed = math.rad(44) 
    local stick  = cpml.vec2(-x, -y) 
    local player  = self.players[self.manager.id] 

    -- Mouse and axis control camera view 
    self.camera:rotateXY(stick.x * 18, stick.y * 9) 

    -- Get angle between Camera Forward and Turret Forward 
    local fwd = cpml.vec2(0, 1):rotate(player.orientation.z + player.turret) 
    local cam = cpml.vec2(1, 0):rotate(math.atan2(self.camera.direction.y, self.camera.direction.x)) 
    local angle = fwd:angle_to(cam) 

    -- If the turret is not true, adjust it 
    if math.abs(angle) > 0 then 
     local function new_angle(direction) 
      local dt  = love.timer.getDelta() 
      local velocity = direction * turret_speed * dt 
      return cpml.vec2(0, 1):rotate(player.orientation.z + player.turret + velocity):angle_to(cam) 
     end 

     -- Rotate turret into the correct direction 
     if new_angle(1) < 0 then 
      player.turret_velocity = turret_speed 
     elseif new_angle(-1) > 0 then 
      player.turret_velocity = -turret_speed 
     else 
      -- If rotating the turret a full frame will overshoot, set turret to camera position 
      -- atan2 starts from the left and we need to also add half a rotation. subtract player orientation to convert to local space. 
      player.turret   = math.atan2(self.camera.direction.y, self.camera.direction.x) + (math.pi * 1.5) - player.orientation.z 
      player.turret_velocity = 0 
     end 
    end 

    local direction   = cpml.mat4():rotate(player.turret, { 0, 0, 1 }) * cpml.mat4():rotate(player.orientation.z, { 0, 0, 1 }) 
    player.turret_direction = cpml.vec3(direction * { 0, 1, 0, 1 }) 
end 
0

我會做不同

  1. 在GCS獲得攝像機的方向矢量c(全局座標系)

  2. 獲得GCS

    炮塔方向矢量t
    • 相同子彈1.
  3. 計算在展臺方向

    旋轉轉塔方向矢量
    • t0=rotation(-44.0deg/s)*t
    • t1=rotation(+44.0deg/s)*t
  4. 現在計算點產品

    • a =dot(c,t)
    • a0=dot(c,t0)
    • a1=dot(c,t1)
  5. 確定轉塔的旋轉

    • 如果最大值(A0,A,A1)== A0旋轉(-44.0deg /秒)`
    • 如果最大值(A0,A,A1)== A1旋轉(44 。0deg /秒)`

[註釋]

  • 這應該收斂到期望的方向
  • 角度步驟應被調整到用於更新這個
  • 的時間間隔相匹配您可以使用任何常見的子彈1,2的座標系統,而不僅僅是GCS
  • 在這種情況下,點積是cos(angle between vectors),因爲兩個c,t是單位向量(如果取自標準變換矩陣)
  • 所以如果cos(角度)== 1那麼方向是相同的
  • 但您的相機可以在不同的軸上旋轉,所以只需找到最大的cos角度)