t1k:cocos:playable:input-service
| Field | Value |
|---|---|
| Module | playable |
| Version | 0.15.0 |
| Effort | high |
| Tools | — |
Keywords: ads, cocos, gesture, input, InputService, playable, raycasting, touch
How to invoke
Section titled “How to invoke”/t1k:cocos:playable:input-serviceInputService
Section titled “InputService”Cocos Component attached to a scene node. Listens to global input events and fires typed signals via SignalBus. See t1k-cocos-playable-signalbus for subscription patterns.
Architecture
Section titled “Architecture”InputService— CocosComponent(attach to scene node), registers TOUCH_START/MOVE/END handlers inonLoadInputSignals— Plain TS classes emitted via SignalBus; no constructor needed forFirstInteractionSignalInputServiceConfig— Optional config overrides passed toconfigure()
Default thresholds: swipeThreshold=50px, swipeVelocityThreshold=300px/s, tapMaxDuration=300ms, tapMaxDistance=10px
Signal Types
Section titled “Signal Types”| Signal | Payload | Fires when |
|---|---|---|
TouchStartSignal | worldPosition, uiPosition | finger touches screen |
TouchEndSignal | worldPosition, uiPosition | finger lifts |
TapSignal | worldPosition, uiPosition | duration < 300ms AND distance < 10px |
SwipeSignal | `direction (‘up' | 'down' |
DragSignal | worldPosition, uiPosition, delta | every TOUCH_MOVE |
FirstInteractionSignal | — | first ever touch (once per session) |
RaycastHitSignal | hitNode, hitPoint | 3D ray hits on TOUCH_START |
RaycastMoveSignal | hitNode, hitPoint | 3D ray hits on TOUCH_MOVE |
RaycastEndSignal | hitNode, hitPoint | 3D ray hits on TOUCH_END |
Key APIs
Section titled “Key APIs”// Runtime configuration (merge over defaults)inputService.configure({ swipeThreshold: 80, tapMaxDuration: 200 });
// Provide explicit 2D camera for screen→world conversioninputService.setMainCamera(camera2D);
// Enable 3D raycasting (auto-enables when set)inputService.set3DCamera(camera3D);// OR assign via @property in editor: inputService.camera3D = camera;
// Toggle all input processinginputService.setEnabled(false);
// Raycast mask for filtering physics layers (default = all layers)inputService.configure({ raycastMask: 1 << 3 }); // layer 3 onlyWorkflow: Common Tasks
Section titled “Workflow: Common Tasks”Subscribe to tap anywhere:
SignalBus.instance.subscribe(TapSignal, (s) => { console.log('tap at UI', s.uiPosition);});Detect first touch (BGM unlock):
// PlayableHelper already handles this — autoPlayMusicOnFirstTouch = true// For custom logic:SignalBus.instance.subscribe(FirstInteractionSignal, () => { AudioService.instance.playMusic(Constant.AUDIO_NAME.BGM);});4-directional swipe:
SignalBus.instance.subscribe(SwipeSignal, (s) => { if (s.direction === 'up') movePlayerUp();});3D object picking (drag):
// 1. Assign camera3D in editor @property or via set3DCamera()// 2. Subscribe to raycast signals:SignalBus.instance.subscribe(RaycastHitSignal, (s) => { s.hitNode.getComponent(MyObject)?.onSelect();});SignalBus.instance.subscribe(RaycastMoveSignal, (s) => { s.hitNode.setWorldPosition(s.hitPoint);});Screen-to-world conversion (internal):
Uses camera.screenToWorld() auto-detected from Canvas if mainCamera not explicitly set.
Integration with PlayableHelper
Section titled “Integration with PlayableHelper”PlayableHelper subscribes FirstInteractionSignal → plays BGM, and optionally subscribes TapSignal for redirect-after-N-clicks. Do not duplicate these subscriptions.
Common Mistakes
Section titled “Common Mistakes”- Attaching
InputServiceto a node that gets destroyed early — use a persistent scene root node - Setting
camera3Dwithout enabling the PhysicsSystem in project settings (raycasts silently skip) - Forgetting to call
setEnabled(false)during loading/cutscenes — tap/swipe signals still fire otherwise - Subscribing
TapSignalwhenPlayableHelper.autoPlayMusicOnFirstTouchis true creates duplicate BGM play calls if you also subscribeFirstInteractionSignal
Gotchas
Section titled “Gotchas”- Touch events on Cocos Web target document, not Canvas — adding a div over the canvas blocks input silently.
- Gamepad polling is per-frame, not per-event — debounce in user code if you need event semantics.
- Multi-touch pinches deliver two unsynchronised TouchMove events per frame — buffer before reacting.
EventTouch.getTouches()is UNRELIABLE for the still-active touch set on TOUCH_END (Cocos 3.8.x) — calling it on TOUCH_END to remove the ended touch from a multi-touch map can wipe a finger that is still down, corrupting a pinch or single-drag state machine. Correct pattern: on TOUCH_END remove only the single ended touch viaevent.touch.getID(); useevent.getTouches()only to refresh positions during TOUCH_MOVE; clear the full tracked set on TOUCH_CANCEL. Evidence: TapInOut CameraInputController.ts; mirrors PLAGameFoundation CameraController.ts pattern.- Pinch-to-single-drag transition: re-seed drag origin from the SURVIVING touch — when one finger of a pinch lifts, do NOT use
event.getLocation()(which is the ended finger’s position) to seed the single-drag start. Instead, read the surviving touch’s last known position from your own tracked map to avoid a spurious drag jump on the first TOUCH_MOVE after the lift.