Look rotation


Setup

This example shows how to orient a game object to look at the target game object in 3D space. For this purpose, we created the function quat_look_rotation (also called LookRotation or looking_at in the industry). This function creates a rotation matrix from the forward and upwards vectors and then converts it to a quaternion. The function also handles the case where no upwards direction is specified, using the default (0, 1, 0) in that case.

Note: to properly apply the resulting rotation, you must remember that your game object must face backwards to the “z” axis, i.e. in Defold the “forward” direction is vector (0, 0, -1).

In this demo you can rotate the camera by holding down the mouse button. And also switch “targets” by pressing any key.

The models used in this example are from Kenney’s Prototype Kit, licensed under CC0.

Scripts

look_rotation.script

--- Creates a rotation with the specified forward and upwards directions.
-- @param forward vector3 The forward direction.
-- @param upwards vector3|nil The upwards direction.
-- @return quat The rotation.
local function quat_look_rotation(forward, upwards)
    -- If no upwards direction is specified, use the default (0, 1, 0)
    upwards = upwards or vmath.vector3(0, 1, 0)

    -- No zero vectors
    if vmath.length_sqr(forward) < 0.0000000001 or vmath.length_sqr(upwards) < 0.0000000001 then
        return vmath.quat()
    end

    -- Create a rotation matrix from the forward and upwards vectors
    local matrix = vmath.matrix4_look_at(vmath.vector3(0), forward, upwards)

    -- Convert the matrix to a quaternion and return it
    return vmath.conj(vmath.quat_matrix4(matrix))
end

local function next_target(self)
    self.target = (self.target or 0) + 1
    if self.target > #self.targets then
        self.target = 1
    end

    local target_id = self.targets[self.target]

    local from = go.get_position("/sword")
    local to = go.get_position(target_id)

    self.target_rotation = quat_look_rotation(to - from)
end

function init(self)
    -- Acquire input focus to receive input events
    msg.post(".", "acquire_input_focus")

    -- List of target objects
    self.targets = {
        "/target1",
        "/target2",
        "/target3"
    }

    -- Set the initial target
    next_target(self)
end

function update(self, dt)
    -- If a target rotation is set, smoothly rotate the sword to face the target
    if self.target_rotation then
        -- Important: we must use vmath.slerp to animate quaternions
        local q = vmath.slerp(0.15, go.get_rotation("/sword"), self.target_rotation)
        go.set_rotation(q, "/sword")
    end
end

function on_input(self, action_id, action)
    -- If the action is pressed (any key or mouse button), set the next target
    if action.pressed then
        next_target(self)
    end
end

If you want to play with these examples, you can get the project on Github.

Do you want to see more examples? Why not write a few yourself and submit a pull request? We love contributions.

GITHUB