var time = use('time') var audio = use('sound') var math = use('math/radians') var gesture = {} gesture.MIN_SWIPE = 30 gesture.MAX_TIME = 500 gesture.PINCH_TH = 10 gesture.reset = function() { this.touches = {} // Track active touches by finger id this.gestureState = null // Current gesture being tracked this.startTime = 0 this.startDist = 0 } gesture.on_input = function(action_id, action) { if (search(action_id, 'gamepad_touchpad_') == null) return var finger = action.finger || 0 var touchpad = action.touchpad || 0 var fingerId = `${touchpad}_${finger}` if (action_id == 'gamepad_touchpad_down') { // Add new touch this.touches[fingerId] = { x: action.x, y: action.y, startX: action.x, startY: action.y, startTime: time.number() } var touchCount = length(array(this.touches)) if (touchCount == 1) { // Single touch started this.gestureState = 'single' this.startTime = time.number() } else if (touchCount == 2) { // Two touches - potential pinch this.gestureState = 'multi' var fingers = object.values(this.touches) this.startDist = this.dist(fingers[0], fingers[1]) } } else if (action_id == 'gamepad_touchpad_motion') { if (this.touches[fingerId]) { // Update touch position this.touches[fingerId].x = action.x this.touches[fingerId].y = action.y var touchCount = length(array(this.touches)) if (touchCount == 2 && this.gestureState == 'multi') { // Check for pinch gesture var fingers = object.values(this.touches) var currentDist = this.dist(fingers[0], fingers[1]) var d = currentDist - this.startDist if (abs(d) >= this.PINCH_TH) { var gesture_type = d > 0 ? 'pinch_out' : 'pinch_in' // scene.recurse(game.root, 'on_input', [gesture_type, { delta: d }]) this.startDist = currentDist } } } } else if (action_id == 'gamepad_touchpad_up') { if (this.touches[fingerId]) { var touch = this.touches[fingerId] var touchCount = length(array(this.touches)) // Check for swipe if this was the only/last touch if (touchCount == 1 && this.gestureState == 'single') { var dt = time.number() - touch.startTime var dx = action.x - touch.startX var dy = action.y - touch.startY if (dt < this.MAX_TIME / 1000) { // Convert to seconds var absX = abs(dx), absY = abs(dy) if (absX > this.MIN_SWIPE / 100 || absY > this.MIN_SWIPE / 100) { // Normalize for 0-1 range var dir = absX > absY ? (dx > 0 ? 'swipe_right' : 'swipe_left') : (dy > 0 ? 'swipe_down' : 'swipe_up') audio.play('swipe') // scene.recurse(game.root, 'on_input', [dir, {pressed:true}]) } } } // Remove touch delete this.touches[fingerId] // Reset if no touches left if (length(array(this.touches)) == 0) { this.gestureState = null } } } } gesture.dist = function(p1, p2) { var dx = p2.x - p1.x var dy = p2.y - p1.y return math.sqrt(math.power(dx, 2) + math.power(dy, 2)) } return function(options) { var obj = meme(gesture) if (options) { obj.MIN_SWIPE = options.minSwipe || gesture.MIN_SWIPE obj.MAX_TIME = options.maxTime || gesture.MAX_TIME obj.PINCH_TH = options.pinchThreshold || gesture.PINCH_TH } obj.reset() return obj }