local InputMapper = Appkit.InputMapper local Util = Appkit.Util local Application = stingray.Application local Keyboard = stingray.Keyboard local Mouse = stingray.Mouse local Pad1 = stingray.Pad1 local Gui = stingray.Gui local Vector3 = stingray.Vector3 local Vector3Box = stingray.Vector3Box local mouse_pan_speed = 1 local pad_pan_speed = 1000 function InputMapper:init() self.input = {pan = Vector3Box(0, 0, 0), move = Vector3Box(0, 0, 0)} end function InputMapper:get_motion_input() local input = self.input return {move = input.move:unbox(), pan = input.pan:unbox()} end function InputMapper:if_jump() return self.input.jump end function InputMapper:if_crouch() return self.input.crouch end function InputMapper:if_run() return self.input.run end function InputMapper:if_aim() return self.input.aim end function InputMapper:if_fire() return self.input.fire end function InputMapper:if_center_camera() return self.input.center_camera end function InputMapper:if_toggle_camera() return self.input.toggle_camera end function InputMapper:if_switch_perspective() return self.input.switch_perspective end function InputMapper:if_exit_level() return self.input.exit_level end local function update_button_input(self, dt) local move = Vector3(0, 0, 0) local pan = Vector3(0, 0, 0) local input = self.input if Util.is_pc() then pan = Mouse.axis(Mouse.axis_id("mouse")) * mouse_pan_speed move = Vector3( Keyboard.button(Keyboard.button_id("d")) - Keyboard.button(Keyboard.button_id("a")), Keyboard.button(Keyboard.button_id("w")) - Keyboard.button(Keyboard.button_id("s")), 0 ) input.jump = Keyboard.pressed(Keyboard.button_id("space")) input.crouch = Keyboard.button(Keyboard.button_id("left ctrl")) > 0 input.run = Keyboard.button(Keyboard.button_id("left shift")) > 0 input.aim = Mouse.button(Mouse.button_id("right")) > 0 input.fire = Mouse.pressed(Mouse.button_id("left")) input.center_camera = Keyboard.pressed(Keyboard.button_id("v")) input.toggle_camera = Keyboard.pressed(Keyboard.button_id("f3")) input.switch_perspective = Keyboard.pressed(Keyboard.button_id("f2")) input.exit_level = Keyboard.pressed(Keyboard.button_id("f5")) or Keyboard.pressed(Keyboard.button_id("esc")) if Pad1 and Pad1.active() then if Vector3.equal(pan, Vector3.zero()) then pan = Pad1.axis(Pad1.axis_id("right")) -- apply an acceleration curve so that we move faster as player presses stick further -- apply dt since gamepad is frame-dependent Vector3.set_x(pan, pan.x^3 * dt * pad_pan_speed) Vector3.set_y(pan, -pan.y^3 * dt * pad_pan_speed) end if Vector3.equal(move, Vector3.zero()) then move = Pad1.axis(Pad1.axis_id("left")) end input.jump = input.jump or Pad1.pressed(Pad1.button_id(Util.plat(nil, "a", nil, "cross"))) input.crouch = input.crouch or Pad1.button(Pad1.button_id(Util.plat(nil, "b", nil, "circle"))) > 0 input.run = input.run or Pad1.button(Pad1.button_id(Util.plat(nil, "left_thumb", nil, "l3" ))) > 0 input.aim = input.aim or Pad1.button(Pad1.button_id(Util.plat(nil, "left_trigger", nil, "l1"))) > 0 input.fire = input.fire or Pad1.pressed(Pad1.button_id(Util.plat(nil, "right_trigger", nil, "r1"))) input.center_camera = input.center_camera or Pad1.pressed(Pad1.button_id(Util.plat(nil, "right_thumb", nil, "r3"))) input.toggle_camera = input.toggle_camera or Pad1.pressed(Pad1.button_id(Util.plat(nil, "d_left", nil, "left"))) input.switch_perspective = input.switch_perspective or Pad1.pressed(Pad1.button_id(Util.plat(nil, "d_down", nil, "down"))) end -- Todo: multiple controller support elseif Application.platform() == "xb1" or Application.platform() == "ps4" then pan = Pad1.axis(Pad1.axis_id("right")) -- apply an acceleration curve so that we move faster as player presses stick further -- apply dt since gamepad is frame-dependent Vector3.set_x(pan, pan.x^3 * dt * pad_pan_speed) Vector3.set_y(pan, -pan.y^3 * dt * pad_pan_speed) move = Pad1.axis(Pad1.axis_id("left")) input.jump = Pad1.pressed(Pad1.button_id(Util.plat(nil, "a", nil, "cross"))) input.crouch = Pad1.button(Pad1.button_id(Util.plat(nil, "b", nil, "circle"))) > 0 input.run = Pad1.button(Pad1.button_id(Util.plat(nil, "left_thumb", nil, "l3" ))) > 0 input.aim = Pad1.button(Pad1.button_id(Util.plat(nil, "left_trigger", nil, "l1"))) > 0 input.fire = Pad1.pressed(Pad1.button_id(Util.plat(nil, "right_trigger", nil, "r1"))) input.center_camera = Pad1.pressed(Pad1.button_id(Util.plat(nil, "right_thumb", nil, "r3"))) input.toggle_camera = Pad1.pressed(Pad1.button_id(Util.plat(nil, "d_left", nil, "left"))) input.switch_perspective = Pad1.pressed(Pad1.button_id(Util.plat(nil, "d_down", nil, "down"))) end input.move:store(move) input.pan:store(pan) end local function update_touch_input(self) local move = Vector3(0, 0, 0) local pan = Vector3(0, 0, 0) local input = self.input local state = self.touch_state local util = Appkit.Util local touch = util.touch_interface() local has_pan_contact = state.pan_id and touch.has_contact(state.pan_id) local has_move_contact = state.move_id and touch.has_contact(state.move_id) -- Remove lifted sticks and handle tapping if state.pan_id and (not has_pan_contact or touch.is_touch_up(state.pan_id)) then local dt = Application.time_since_launch() - state.pan_t if has_pan_contact then local delta = util.location(touch, state.pan_id) - state.pan_ref:unbox() if dt < 0.5 and Vector3.length(delta) < 5 then input.jump = true end end state.pan_id = nil end if state.move_id and (not has_move_contact or touch.is_touch_up(state.move_id)) then local dt = Application.time_since_launch() - state.move_t if has_move_contact then local delta = util.location(touch, state.move_id) - state.move_ref:unbox() if dt < 0.5 and Vector3.length(delta) < 5 then input.crouch = true end end state.move_id = nil end -- Handle new touches local contacts = {touch.contacts()} for _, id in ipairs(contacts) do if touch.is_touch_down(id) then local pos = util.location(touch, id) local w, h = stingray.Gui.resolution() if pos.x > w / 2 and pos.y < h / 2 and not state.move_id then state.move_id = id state.move_ref = Vector3Box(pos) state.move_t = Application.time_since_launch() elseif pos.x < w / 2 and pos.y < h / 2 and not state.pan_id then state.pan_id = id state.pan_ref:store(pos) state.pan_t = Application.time_since_launch() end end end -- Track pan and move if state.move_id then local delta = util.location(touch, state.move_id) - state.move_ref:unbox() delta = delta / 100 move = delta end if state.pan_id then local delta = util.location(touch, state.pan_id) - state.pan_ref:unbox() delta = delta / 50 delta.y = -delta.y / 4 pan = delta end input.move:store(Vector3.normalize(move)) input.pan:store(pan) end -- Updates the cached input state function InputMapper:update(dt) if scaleform and Util.use_touch() then return elseif Util.use_touch() then update_touch_input(self, dt) else update_button_input(self, dt) end end return InputMapper