go.property("acceleration", 100) go.property("deceleration", 200) go.property("max_speed", 400) go.property("wheel_base", 40) -- pixels between left and right wheels local UP = vmath.vector3(0, 1, 0) function init(self) msg.post(".", "acquire_input_focus") self.left_speed = 0 self.right_speed = 0 self.left_input = false self.right_input = false end function update(self, dt) -- each wheel accelerates when its key is held, decelerates otherwise if self.left_input then self.left_speed = math.min(self.left_speed + self.acceleration * dt, self.max_speed) else self.left_speed = math.max(self.left_speed - self.deceleration * dt, 0) end if self.right_input then self.right_speed = math.min(self.right_speed + self.acceleration * dt, self.max_speed) else self.right_speed = math.max(self.right_speed - self.deceleration * dt, 0) end -- differential drive: speed difference creates rotation, average creates forward motion local linear_speed = (self.left_speed + self.right_speed) / 2 local angular_vel = (self.right_speed - self.left_speed) / self.wheel_base local rot = go.get_rotation() rot = rot * vmath.quat_rotation_z(angular_vel * dt) go.set_rotation(rot) local p = go.get_position() p = p + vmath.rotate(rot, UP * linear_speed * dt) go.set_position(p) -- reset each frame (on_input re-sets if key is still held) self.left_input = false self.right_input = false end function on_input(self, action_id, action) if action_id == hash("a_key") then self.left_input = true elseif action_id == hash("d_key") then self.right_input = true end end