Vehicle template: /vehicle_follow_cam.lua code sample - Stingray Lua API Reference
require 'core/appkit/lua/class'
require 'core/appkit/lua/component_manager'
Project.VehicleFollowCam = Appkit.class(Project.VehicleFollowCam)
local VehicleFollowCam = Project.VehicleFollowCam
-- Add component support.
VehicleFollowCam.manager = VehicleFollowCam.manager or Appkit.ComponentManager()
function VehicleFollowCam:on_level_shutdown()
end
function VehicleFollowCam:init(entity, world, vehicle, camera_unit, camera_name, camera_offset, follow_rotational_speed, follow_behind_latency)
self.entity= entity
self.world = world
self.vehicle = vehicle
self.camera_unit = camera_unit
self.camera_name = camera_name
self.camera_offset = stingray.Vector3Box(camera_offset)
self.camera_rotation = stingray.QuaternionBox(stingray.Quaternion.from_elements(0,0,0,0))
self.follow_rotational_speed = follow_rotational_speed
self.follow_behind_latency = follow_behind_latency
self.is_enabled = true;
VehicleFollowCam.manager:add_component(entity, self)
end
function VehicleFollowCam:set_enabled(enabled)
self.is_enabled = enabled
end
local function no_roll_matrix_from_forward(forward)
forward = stingray.Vector3.normalize(forward)
local new_x = stingray.Vector3.cross(forward, stingray.Vector3(0,0,1))
new_x = stingray.Vector3.normalize(new_x)
local new_z = stingray.Vector3.cross(new_x, forward)
local mat = stingray.Matrix4x4.from_axes(new_x, forward, new_z, stingray.Vector3.zero())
return mat
end
function VehicleFollowCam:update(dt)
if not self.is_enabled then return end
local vehicle = self.vehicle
local veh_r = stingray.Vehicle.rotation(vehicle)
local veh_p = stingray.Vehicle.position(vehicle)
-- calculate no roll pose from vehicle forward vector - camera should not roll
local vehicle_forward = stingray.Quaternion.forward(veh_r)
local vehicle_pose_no_roll = no_roll_matrix_from_forward(vehicle_forward)
local vehicle_r_no_roll = stingray.Quaternion.from_matrix4x4(vehicle_pose_no_roll)
-- lerp camera world rotation to vehicle no roll rotation
local camera_rotation = self.camera_rotation
local new_camera_rotation = stingray.Quaternion.lerp(camera_rotation:unbox(), vehicle_r_no_roll, self.follow_rotational_speed * dt)
camera_rotation:store(new_camera_rotation)
-- convert camera to local space
local camera_rotation_local = stingray.Quaternion.multiply(stingray.Quaternion.inverse(veh_r), new_camera_rotation)
-- calculate camera position offset based on vehicle speed
local speed = stingray.Vehicle.forward_speed(vehicle)
local camera_offset = self.camera_offset
cam_p = stingray.Vector3(camera_offset.x,0,camera_offset.z) - stingray.Quaternion.forward(camera_rotation_local)*(camera_offset.y + speed * self.follow_behind_latency)
-- update camera position and rotation
local camera_unit = self.camera_unit
local camera = stingray.Unit.camera(camera_unit, self.camera_name)
stingray.Camera.set_local_position(camera, camera_unit, cam_p)
stingray.Camera.set_local_rotation(camera, camera_unit, camera_rotation_local)
-- update unit to sync camera pose to renderer
stingray.World.update_unit(self.world, camera_unit)
end
return VehicleFollowCam