I have two Vec3s, Camera Forward and Turret Forward. Both of these vectors are on different planes where Camera Forward is based on a free-look camera and Turret Forward is determined by the tank it sits on, the terrain the tank is on, etc. Turret Up and Camera Up are rarely ever going to match.
My issue is as follows: I want the turret to be able to rotate using a fixed velocity (44 degrees per second) so that it always converges with the direction that the camera is pointed. If the tank is at a weird angle where it simply cannot converge with the camera, it should find the closest place and sit there instead of jitter around indefinitely.
I cannot for the life of me seem to solve this problem. I've tried several methods I found online that always produce weird results.
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
I would do it differently
obtain camera direction vector c
in GCS (global coordinate system)
obtain turret direction vector t
in GCS
compute rotated turret direction vectors in booth directions
t0=rotation(-44.0deg/s)*t
t1=rotation(+44.0deg/s)*t
now compute the dot products
a =dot(c,t)
a0=dot(c,t0)
a1=dot(c,t1)
determine turret rotation
[Notes]
cos(angle between vectors)
because both c,t
are unit vectors (if taken from standard transform matrix) After some more research and testing, I ended up with the following solution. It works swimmingly!
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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.