@@ -24,6 +24,13 @@ export default class Project {
24
24
public answer : string | null ;
25
25
private timerStart ! : Date ;
26
26
27
+ public draggingSprite : Sprite | null ;
28
+ public dragThreshold : number ;
29
+ private _consideringDraggingSprite : Sprite | null ;
30
+ private _dragOffsetX : number ;
31
+ private _dragOffsetY : number ;
32
+ private _idleDragTimeout : number | null ;
33
+
27
34
/**
28
35
* Used to keep track of what edge-activated trigger predicates evaluted to
29
36
* on the previous step.
@@ -56,6 +63,14 @@ export default class Project {
56
63
this . restartTimer ( ) ;
57
64
58
65
this . answer = null ;
66
+ this . draggingSprite = null ;
67
+ this . _consideringDraggingSprite = null ;
68
+ this . _dragOffsetX = 0 ;
69
+ this . _dragOffsetY = 0 ;
70
+ this . _idleDragTimeout = null ;
71
+
72
+ // TODO: Enable customizing, like frameRate
73
+ this . dragThreshold = 3 ;
59
74
60
75
// Run project code at specified framerate
61
76
setInterval ( ( ) => {
@@ -68,6 +83,7 @@ export default class Project {
68
83
69
84
public attach ( renderTarget : string | HTMLElement ) : void {
70
85
this . renderer . setRenderTarget ( renderTarget ) ;
86
+
71
87
this . renderer . stage . addEventListener ( "click" , ( ) => {
72
88
// Chrome requires a user gesture on the page before we can start the
73
89
// audio context.
@@ -76,24 +92,56 @@ export default class Project {
76
92
if ( Sound . audioContext . state === "suspended" ) {
77
93
void Sound . audioContext . resume ( ) ;
78
94
}
95
+ } ) ;
79
96
80
- let clickedSprite = this . renderer . pick ( this . spritesAndClones , {
81
- x : this . input . mouse . x ,
82
- y : this . input . mouse . y ,
83
- } ) ;
84
- if ( ! clickedSprite ) {
85
- clickedSprite = this . stage ;
97
+ this . renderer . stage . addEventListener ( "mousedown" , ( ) => {
98
+ const spriteUnderMouse = this . _spriteUnderMouse ;
99
+ const targetUnderMouse = this . _targetUnderMouse ;
100
+ if ( spriteUnderMouse && spriteUnderMouse . draggable ) {
101
+ this . _consideringDraggingSprite = spriteUnderMouse ;
102
+ this . _startIdleDragTimeout ( ) ;
103
+ } else {
104
+ this . _startClickTriggersFor ( targetUnderMouse ) ;
86
105
}
106
+ } ) ;
107
+
108
+ this . renderer . stage . addEventListener ( "mousemove" , ( ) => {
109
+ // TODO: Effects - goto() and moveAhead() - are applied immediately.
110
+ // Do we want to buffer them to apply at the start of the next tick?
111
+ if ( this . input . mouse . down ) {
112
+ if ( this . _consideringDraggingSprite && this . input . mouse . downAt ) {
113
+ const distanceX = this . input . mouse . x - this . input . mouse . downAt . x ;
114
+ const distanceY = this . input . mouse . y - this . input . mouse . downAt . y ;
115
+ const distanceFromMouseDown = Math . sqrt (
116
+ distanceX ** 2 + distanceY ** 2
117
+ ) ;
118
+ if ( distanceFromMouseDown > this . dragThreshold ) {
119
+ this . _startDragging ( ) ;
120
+ }
121
+ }
87
122
88
- const matchingTriggers : TriggerWithTarget [ ] = [ ] ;
89
- for ( const trigger of clickedSprite . triggers ) {
90
- if ( trigger . matches ( Trigger . CLICKED , { } , clickedSprite ) ) {
91
- matchingTriggers . push ( { trigger , target : clickedSprite } ) ;
123
+ if ( this . draggingSprite ) {
124
+ const gotoX = this . input . mouse . x + this . _dragOffsetX ;
125
+ const gotoY = this . input . mouse . y + this . _dragOffsetY ;
126
+ this . draggingSprite . goto ( gotoX , gotoY , true ) ;
92
127
}
93
128
}
129
+ } ) ;
94
130
95
- void this . _startTriggers ( matchingTriggers ) ;
131
+ this . renderer . stage . addEventListener ( "mouseup" , ( ) => {
132
+ if ( ! this . _clearDragging ( ) ) {
133
+ const spriteUnderMouse = this . _spriteUnderMouse ;
134
+ if ( spriteUnderMouse && spriteUnderMouse . draggable ) {
135
+ this . _startClickTriggersFor ( spriteUnderMouse ) ;
136
+ }
137
+ }
96
138
} ) ;
139
+
140
+ if ( this . renderer . stage . ownerDocument ) {
141
+ this . renderer . stage . ownerDocument . addEventListener ( "mouseup" , ( ) => {
142
+ void this . _clearDragging ( ) ;
143
+ } ) ;
144
+ }
97
145
}
98
146
99
147
public greenFlag ( ) : void {
@@ -155,6 +203,65 @@ export default class Project {
155
203
void this . _startTriggers ( triggersToStart ) ;
156
204
}
157
205
206
+ private _startClickTriggersFor ( target : Sprite | Stage ) : void {
207
+ const matchingTriggers : TriggerWithTarget [ ] = [ ] ;
208
+ for ( const trigger of target . triggers ) {
209
+ if ( trigger . matches ( Trigger . CLICKED , { } , target ) ) {
210
+ matchingTriggers . push ( { trigger, target } ) ;
211
+ }
212
+ }
213
+
214
+ void this . _startTriggers ( matchingTriggers ) ;
215
+ }
216
+
217
+ private get _spriteUnderMouse ( ) : Sprite | null {
218
+ return this . renderer . pick ( this . spritesAndClones , {
219
+ x : this . input . mouse . x ,
220
+ y : this . input . mouse . y ,
221
+ } ) ;
222
+ }
223
+
224
+ private get _targetUnderMouse ( ) : Sprite | Stage {
225
+ return this . _spriteUnderMouse || this . stage ;
226
+ }
227
+
228
+ private _startDragging ( ) : void {
229
+ if ( this . _consideringDraggingSprite ) {
230
+ this . draggingSprite = this . _consideringDraggingSprite ;
231
+ this . _consideringDraggingSprite = null ;
232
+ this . _clearIdleDragTimeout ( ) ;
233
+
234
+ this . _dragOffsetX = this . draggingSprite . x - this . input . mouse . x ;
235
+ this . _dragOffsetY = this . draggingSprite . y - this . input . mouse . y ;
236
+
237
+ this . draggingSprite . moveAhead ( ) ;
238
+ }
239
+ }
240
+
241
+ private _clearDragging ( ) : boolean {
242
+ const wasDragging = ! ! this . draggingSprite ;
243
+ this . draggingSprite = null ;
244
+ this . _consideringDraggingSprite = null ;
245
+ this . _dragOffsetX = 0 ;
246
+ this . _dragOffsetY = 0 ;
247
+ this . _clearIdleDragTimeout ( ) ;
248
+ return wasDragging ;
249
+ }
250
+
251
+ private _startIdleDragTimeout ( ) : void {
252
+ this . _idleDragTimeout = window . setTimeout (
253
+ this . _startDragging . bind ( this ) ,
254
+ 400
255
+ ) ;
256
+ }
257
+
258
+ private _clearIdleDragTimeout ( ) : void {
259
+ if ( typeof this . _idleDragTimeout === "number" ) {
260
+ clearTimeout ( this . _idleDragTimeout ) ;
261
+ this . _idleDragTimeout = null ;
262
+ }
263
+ }
264
+
158
265
private step ( ) : void {
159
266
this . _cachedLoudness = null ;
160
267
this . _stepEdgeActivatedTriggers ( ) ;
0 commit comments