--[[ A basic Input utility with controls for move and pan. Used to support simple input in the templates. ]]-- require 'core/appkit/lua/util' require 'core/appkit/lua/class' Appkit.InputMapper = Appkit.class(Appkit.InputMapper) local InputMapper = Appkit.InputMapper local Application = stingray.Application local Keyboard = stingray.Keyboard local Pad1 = stingray.Pad1 local Vector3 = stingray.Vector3 local Vector3Box = stingray.Vector3Box InputMapper.pc_azerty_move_keys = { forward = 'z', backward = 's', left = 'q', right = 'd' } InputMapper.pc_qwerty_move_keys = { forward = 'w', backward = 's', left = 'a', right = 'd' } function InputMapper:set_pc_move_keys(pc_move_keys) self.pc_move_keys = pc_move_keys end function InputMapper:init() self:set_pc_move_keys(InputMapper.pc_qwerty_move_keys) self.input = { pan = Vector3Box(Vector3(0, 0, 0)), move = Vector3Box(Vector3(0, 0, 0)) } self.touch_state = { -- Contact id for pan controller pan_id = nil, -- Contact id for move controller move_id = nil, pan_ref = Vector3Box(0, 0, 0) } end function InputMapper:get_motion_input() local input = self.input return {move = input.move:unbox(), pan = input.pan:unbox()} end local function update_button_input(self) local move = Vector3(0, 0, 0) local pan = Vector3(0, 0, 0) local input = self.input if Appkit.Util.is_pc() then pan = stingray.Mouse.axis(stingray.Mouse.axis_id("mouse")) move = Vector3( Keyboard.button(Keyboard.button_id(self.pc_move_keys.right)) - Keyboard.button(Keyboard.button_id(self.pc_move_keys.left)), Keyboard.button(Keyboard.button_id(self.pc_move_keys.forward)) - Keyboard.button(Keyboard.button_id(self.pc_move_keys.backward)), 0 ) input.jump = Keyboard.pressed(Keyboard.button_id("space")) input.crouch = Keyboard.pressed(Keyboard.button_id("left ctrl")) input.run = Keyboard.button(Keyboard.button_id("left shift")) > 0 if Pad1 and Pad1.active() then if pan.x == 0 and pan.y ==0 and pan.z == 0 then pan = Pad1.axis(Pad1.axis_id("right")) * 10 Vector3.set_y(pan, -pan.y) end if move.x == 0 and move.y ==0 and move.z == 0 then move = Pad1.axis(Pad1.axis_id("left")) end input.jump = (input.jump == true) or Pad1.pressed(Pad1.button_id(Appkit.Util.plat(nil, "a", nil, "cross"))) input.crouch = (input.crouch == true) or Pad1.pressed(Pad1.button_id(Appkit.Util.plat(nil, "b", nil, "circle"))) input.run = (input.run == true) or Pad1.button(Pad1.button_id(Appkit.Util.plat(nil, "x", nil, "square" ))) > 0 end --Todo: multiple controller support elseif Application.platform() == "xb1" or Application.platform() == "ps4" then pan = Pad1.axis(Pad1.axis_id("right")) * 10 Vector3.set_y(pan, -pan.y) move = Pad1.axis(Pad1.axis_id("left")) input.jump = Pad1.pressed(Pad1.button_id(Appkit.Util.plat(nil, "a", nil, "cross"))) input.crouch = Pad1.pressed(Pad1.button_id(Appkit.Util.plat(nil, "b", nil, "circle"))) input.run = Pad1.button(Pad1.button_id(Appkit.Util.plat(nil, "x", nil, "square" ))) > 0 end input.move:store(Vector3.normalize(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 Appkit.Util.use_touch() then update_touch_input(self) else update_button_input(self) end end return InputMapper