Vehicle template: /vehicle_follow_cam.lua — code sample - Stingray Lua API Reference

Vehicle template: /vehicle_follow_cam.lua — code sample

Code

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