Skip to content

Instantly share code, notes, and snippets.

@fleon
Created August 23, 2018 12:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fleon/f9abc82f1f873cb3b30f8d9628cfeb98 to your computer and use it in GitHub Desktop.
Save fleon/f9abc82f1f873cb3b30f8d9628cfeb98 to your computer and use it in GitHub Desktop.
cocos2dx-TouchHelper
export function noop() {}
export default class Deferred<T = void> {
resolve: (value?: T) => void
reject: (value?: any) => void
promise: Promise<T>
constructor() {
this.promise = new Promise<T>((resolve, reject) => {
this.resolve = resolve
this.reject = reject
})
}
}
import { noop } from 'utils/Common'
import Deferred from 'utils/Deferred'
export default class Timeout<Data = null> extends Deferred {
constructor(private fn: (data?: Data) => any = noop, time: number, private data?: Data) {
super()
// delay cannot be zero. Minimum delay has to be 1ms.
if (!time) time = 1
cc.director.getScheduler()
.scheduleCallbackForTarget(this, this.callback, 1e10, 0, time / 1000, false)
}
callback = () => {
this.fn(this.data)
this.resolve()
this.cancel()
}
cancel() {
cc.director.getScheduler()
.unscheduleCallbackForTarget(this, this.callback)
}
}
export function timeout<Data = null>(fn: (data?: Data) => any = noop, time = 1, data?: Data): Timeout<Data> {
return new Timeout(fn, time, data)
}
import Timeout, { timeout } from 'utils/Timeout'
interface ITouchableNode extends cc.Node {
touchBegan?(touch: cc.Touch)
touchMoved?(touch: cc.Touch)
touchEnded?(touch: cc.Touch)
touchCancelled?(touch: cc.Touch)
shortPress?(touch: ITouchInfo)
mediumPress?(touch: ITouchInfo)
longPress?(touch: ITouchInfo)
}
function getTouchInfo(touch: cc.Touch): ITouchInfo {
return {
location: touch.getLocation(),
startLocation: touch.getStartLocation ? touch.getStartLocation() : cc.p(0, 0),
delta: touch.getDelta()
}
}
const touchListeners = new Map<ITouchableNode, cc.EventListener>()
const touchListenerObjs = new Map<ITouchableNode, object>()
const shortPressTimeouts = []
const mediumPressTimeouts = []
const longPressTimeouts = []
function cancelAllTimeouts() {
shortPressTimeouts.forEach(t => t.cancel())
shortPressTimeouts.length = 0
mediumPressTimeouts.forEach(t => t.cancel())
mediumPressTimeouts.length = 0
longPressTimeouts.forEach(t => t.cancel())
longPressTimeouts.length = 0
}
export function enableTouch(node: ITouchableNode, swallowTouches = true) {
let shortPressTimeout: Timeout
let shortPressCalled = false
let mediumPressTimeout: Timeout
let longPressTimeout: Timeout
const listenerObj = {
event: cc.EventListener.TOUCH_ONE_BY_ONE,
swallowTouches,
onTouchBegan: (touch: cc.Touch) => {
const touchInfo = getTouchInfo(touch)
shortPressCalled = false
if (shortPressTimeout) shortPressTimeout.cancel()
shortPressTimeout = timeout(() => {
if (node.shortPress && !shortPressCalled)
node.shortPress(touchInfo)
shortPressCalled = true
})
if (mediumPressTimeout) mediumPressTimeout.cancel()
mediumPressTimeout = timeout(() => {
if (node.mediumPress)
node.mediumPress(touchInfo)
}, 10)
mediumPressTimeouts.push(mediumPressTimeout)
if (longPressTimeout) longPressTimeout.cancel()
longPressTimeout = timeout(() => {
if (node.longPress)
node.longPress(touchInfo)
}, 800)
longPressTimeouts.push(longPressTimeout)
if (node.touchBegan)
return node.touchBegan(touch)
},
onTouchMoved: (touch: cc.Touch) => {
if (!touch || !touch.getLocation) return
const startLocation = touch.getStartLocation ? touch.getStartLocation() : cc.p(0, 0)
const location = touch.getLocation()
if (!cc.pointEqualToPoint(startLocation, location)) {
cancelAllTimeouts()
}
if (node.touchMoved)
return node.touchMoved(touch)
},
onTouchEnded: (touch: cc.Touch) => {
cancelAllTimeouts()
if (!touch || !touch.getLocation) return
const startLocation = touch.getStartLocation ? touch.getStartLocation() : cc.p(0, 0)
const location = touch.getLocation()
if (cc.pointEqualToPoint(startLocation, location) && node.shortPress && !shortPressCalled)
node.shortPress(getTouchInfo(touch))
if (node.touchEnded)
return node.touchEnded(touch)
},
onTouchCancelled: (touch: cc.Touch) => {
cancelAllTimeouts()
if (!touch || !touch.getLocation) return
if (node.touchCancelled)
return node.touchCancelled(touch)
},
}
const listener = cc.EventListener.create(listenerObj)
listener.retain()
node.retain()
cc.eventManager.addListener(listener, node)
// need separate maps for listener and the obj so that the listener obj doesn't get
// garbage collected unneccessarily
touchListeners.set(node, listener)
touchListenerObjs.set(node, listenerObj)
}
export function disableTouch(node: ITouchableNode) {
if (!touchListeners.has(node)) return
const listener = touchListeners.get(node)
cc.eventManager.removeListener(listener)
cancelAllTimeouts()
touchListeners.delete(node)
touchListenerObjs.delete(node)
listener.release()
node.release()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment