2022-09-20 15:50:01 +00:00
window . DIRECTION _DECODER = [
2022-11-10 10:18:00 +00:00
// The 3rd value matches low-precision constants in backend.
[ 0 , 0 ] ,
[ 0 , + 2 ] ,
[ 0 , - 2 ] ,
[ + 2 , 0 ] ,
[ - 2 , 0 ] ,
[ + 1 , + 1 ] ,
[ - 1 , - 1 ] ,
[ + 1 , - 1 ] ,
[ - 1 , + 1 ] ,
2022-09-20 15:50:01 +00:00
] ;
cc . Class ( {
extends : cc . Component ,
properties : {
// For joystick begins.
translationListenerNode : {
default : null ,
type : cc . Node
} ,
zoomingListenerNode : {
default : null ,
type : cc . Node
} ,
stickhead : {
default : null ,
type : cc . Node
} ,
base : {
default : null ,
type : cc . Node
} ,
joyStickEps : {
default : 0.10 ,
type : cc . Float
} ,
magicLeanLowerBound : {
2022-11-10 13:28:46 +00:00
default : 0.1 ,
2022-09-20 15:50:01 +00:00
type : cc . Float
} ,
magicLeanUpperBound : {
2022-11-10 13:28:46 +00:00
default : 0.9 ,
2022-09-20 15:50:01 +00:00
type : cc . Float
} ,
// For joystick ends.
linearScaleFacBase : {
default : 1.00 ,
type : cc . Float
} ,
minScale : {
default : 1.00 ,
type : cc . Float
} ,
maxScale : {
default : 2.50 ,
type : cc . Float
} ,
maxMovingBufferLength : {
default : 1 ,
type : cc . Integer
} ,
zoomingScaleFacBase : {
default : 0.10 ,
type : cc . Float
} ,
zoomingSpeedBase : {
default : 4.0 ,
type : cc . Float
} ,
linearSpeedBase : {
default : 320.0 ,
type : cc . Float
} ,
canvasNode : {
default : null ,
type : cc . Node
} ,
mapNode : {
default : null ,
type : cc . Node
} ,
linearMovingEps : {
default : 0.10 ,
type : cc . Float
} ,
scaleByEps : {
default : 0.0375 ,
type : cc . Float
} ,
} ,
start ( ) { } ,
onLoad ( ) {
this . cachedStickHeadPosition = cc . v2 ( 0.0 , 0.0 ) ;
2022-11-20 10:53:33 +00:00
this . cachedBtnUpLevel = 0 ;
this . cachedBtnDownLevel = 0 ;
this . cachedBtnLeftLevel = 0 ;
this . cachedBtnRightLevel = 0 ;
this . cachedBtnALevel = 0 ;
2022-12-09 16:07:03 +00:00
this . cachedBtnBLevel = 0 ;
2022-11-20 10:53:33 +00:00
2022-09-20 15:50:01 +00:00
this . canvasNode = this . mapNode . parent ;
this . mainCameraNode = this . canvasNode . getChildByName ( "Main Camera" ) ; // Cannot drag and assign the `mainCameraNode` from CocosCreator EDITOR directly, otherwise it'll cause an infinite loading time, till v2.1.0.
this . mainCamera = this . mainCameraNode . getComponent ( cc . Camera ) ;
this . activeDirection = {
dx : 0.0 ,
dy : 0.0
} ;
this . maxHeadDistance = ( 0.5 * this . base . width ) ;
this . _initTouchEvent ( ) ;
this . _cachedMapNodePosTarget = [ ] ;
this . _cachedZoomRawTarget = null ;
this . mapScriptIns = this . mapNode . getComponent ( "Map" ) ;
this . initialized = true ;
} ,
_initTouchEvent ( ) {
const self = this ;
2022-11-10 10:18:00 +00:00
const translationListenerNode = ( self . translationListenerNode ? self . translationListenerNode : self . mapNode ) ;
const zoomingListenerNode = ( self . zoomingListenerNode ? self . zoomingListenerNode : self . mapNode ) ;
2022-09-20 15:50:01 +00:00
translationListenerNode . on ( cc . Node . EventType . TOUCH _START , function ( event ) {
self . _touchStartEvent ( event ) ;
} ) ;
translationListenerNode . on ( cc . Node . EventType . TOUCH _MOVE , function ( event ) {
self . _translationEvent ( event ) ;
} ) ;
translationListenerNode . on ( cc . Node . EventType . TOUCH _END , function ( event ) {
self . _touchEndEvent ( event ) ;
} ) ;
translationListenerNode . on ( cc . Node . EventType . TOUCH _CANCEL , function ( event ) {
self . _touchEndEvent ( event ) ;
} ) ;
2022-11-10 10:18:00 +00:00
translationListenerNode . inTouchPoints = new Map ( ) ;
2022-09-20 15:50:01 +00:00
zoomingListenerNode . on ( cc . Node . EventType . TOUCH _START , function ( event ) {
self . _touchStartEvent ( event ) ;
} ) ;
zoomingListenerNode . on ( cc . Node . EventType . TOUCH _MOVE , function ( event ) {
self . _zoomingEvent ( event ) ;
} ) ;
zoomingListenerNode . on ( cc . Node . EventType . TOUCH _END , function ( event ) {
self . _touchEndEvent ( event ) ;
} ) ;
zoomingListenerNode . on ( cc . Node . EventType . TOUCH _CANCEL , function ( event ) {
self . _touchEndEvent ( event ) ;
} ) ;
2022-11-10 10:18:00 +00:00
zoomingListenerNode . inTouchPoints = new Map ( ) ;
2022-11-20 10:53:33 +00:00
// Setup keyboard controls for the ease of attach debugging
cc . systemEvent . on ( cc . SystemEvent . EventType . KEY _DOWN , function ( evt ) {
switch ( evt . keyCode ) {
case cc . macro . KEY . w :
self . cachedBtnUpLevel = 1 ;
break ;
case cc . macro . KEY . s :
self . cachedBtnDownLevel = 1 ;
break ;
case cc . macro . KEY . a :
self . cachedBtnLeftLevel = 1 ;
break ;
case cc . macro . KEY . d :
self . cachedBtnRightLevel = 1 ;
break ;
case cc . macro . KEY . h :
self . cachedBtnALevel = 1 ;
break ;
2022-12-09 16:07:03 +00:00
case cc . macro . KEY . j :
self . cachedBtnBLevel = 1 ;
break ;
2022-11-20 10:53:33 +00:00
default :
break ;
}
} , this ) ;
cc . systemEvent . on ( cc . SystemEvent . EventType . KEY _UP , function ( evt ) {
switch ( evt . keyCode ) {
case cc . macro . KEY . w :
self . cachedBtnUpLevel = 0 ;
break ;
case cc . macro . KEY . s :
self . cachedBtnDownLevel = 0 ;
break ;
case cc . macro . KEY . a :
self . cachedBtnLeftLevel = 0 ;
break ;
case cc . macro . KEY . d :
self . cachedBtnRightLevel = 0 ;
break ;
case cc . macro . KEY . h :
self . cachedBtnALevel = 0 ;
break ;
2022-12-09 16:07:03 +00:00
case cc . macro . KEY . j :
self . cachedBtnBLevel = 0 ;
break ;
2022-11-20 10:53:33 +00:00
default :
break ;
}
} , this ) ;
2022-09-20 15:50:01 +00:00
} ,
_isMapOverMoved ( mapTargetPos ) {
const virtualPlayerPos = cc . v2 ( - mapTargetPos . x , - mapTargetPos . y ) ;
return tileCollisionManager . isOutOfMapNode ( this . mapNode , virtualPlayerPos ) ;
} ,
_touchStartEvent ( event ) {
2022-11-10 10:18:00 +00:00
const theListenerNode = event . target ;
2022-09-20 15:50:01 +00:00
for ( let touch of event . _touches ) {
theListenerNode . inTouchPoints . set ( touch . _id , touch ) ;
}
} ,
_translationEvent ( event ) {
if ( ALL _MAP _STATES . VISUAL != this . mapScriptIns . state ) {
return ;
}
2022-11-10 10:18:00 +00:00
const theListenerNode = event . target ;
2022-09-20 15:50:01 +00:00
const linearScaleFacBase = this . linearScaleFacBase ; // Not used yet.
if ( 1 != theListenerNode . inTouchPoints . size ) {
return ;
}
2022-11-10 10:18:00 +00:00
if ( ! theListenerNode . inTouchPoints . has ( event . currentTouch . _id ) ) {
2022-09-20 15:50:01 +00:00
return ;
}
const diffVec = event . currentTouch . _point . sub ( event . currentTouch . _startPoint ) ;
const distance = diffVec . mag ( ) ;
const overMoved = ( distance > this . maxHeadDistance ) ;
if ( overMoved ) {
const ratio = ( this . maxHeadDistance / distance ) ;
this . cachedStickHeadPosition = diffVec . mul ( ratio ) ;
} else {
const ratio = ( distance / this . maxHeadDistance ) ;
this . cachedStickHeadPosition = diffVec . mul ( ratio ) ;
}
} ,
_zoomingEvent ( event ) {
if ( ALL _MAP _STATES . VISUAL != this . mapScriptIns . state ) {
return ;
}
2022-11-10 10:18:00 +00:00
const theListenerNode = event . target ;
2022-09-20 15:50:01 +00:00
if ( 2 != theListenerNode . inTouchPoints . size ) {
2022-11-10 10:18:00 +00:00
return ;
2022-09-20 15:50:01 +00:00
}
if ( 2 == event . _touches . length ) {
const firstTouch = event . _touches [ 0 ] ;
const secondTouch = event . _touches [ 1 ] ;
const startMagnitude = firstTouch . _startPoint . sub ( secondTouch . _startPoint ) . mag ( ) ;
const currentMagnitude = firstTouch . _point . sub ( secondTouch . _point ) . mag ( ) ;
let scaleBy = ( currentMagnitude / startMagnitude ) ;
scaleBy = 1 + ( scaleBy - 1 ) * this . zoomingScaleFacBase ;
if ( 1 < scaleBy && Math . abs ( scaleBy - 1 ) < this . scaleByEps ) {
// Jitterring.
cc . log ( ` ScaleBy == ${ scaleBy } is just jittering. ` ) ;
return ;
}
if ( 1 > scaleBy && Math . abs ( scaleBy - 1 ) < 0.5 * this . scaleByEps ) {
// Jitterring.
cc . log ( ` ScaleBy == ${ scaleBy } is just jittering. ` ) ;
return ;
}
if ( ! this . mainCamera ) return ;
const targetScale = this . mainCamera . zoomRatio * scaleBy ;
if ( this . minScale > targetScale || targetScale > this . maxScale ) {
return ;
}
this . mainCamera . zoomRatio = targetScale ;
for ( let child of this . mainCameraNode . children ) {
2022-11-10 10:18:00 +00:00
child . setScale ( 1 / targetScale ) ;
2022-09-20 15:50:01 +00:00
}
}
} ,
_touchEndEvent ( event ) {
2022-11-10 10:18:00 +00:00
const theListenerNode = event . target ;
2022-09-20 15:50:01 +00:00
do {
if ( ! theListenerNode . inTouchPoints . has ( event . currentTouch . _id ) ) {
break ;
}
const diffVec = event . currentTouch . _point . sub ( event . currentTouch . _startPoint ) ;
const diffVecMag = diffVec . mag ( ) ;
if ( this . linearMovingEps <= diffVecMag ) {
break ;
}
// Only triggers map-state-switch when `diffVecMag` is sufficiently small.
if ( ALL _MAP _STATES . VISUAL != this . mapScriptIns . state ) {
break ;
}
2022-11-10 10:18:00 +00:00
// TODO: Handle single-finger-click event.
2022-09-20 15:50:01 +00:00
} while ( false ) ;
for ( let touch of event . _touches ) {
if ( touch ) {
theListenerNode . inTouchPoints . delete ( touch . _id ) ;
}
}
} ,
_touchCancelEvent ( event ) { } ,
update ( dt ) {
if ( this . inMultiTouch ) return ;
if ( true != this . initialized ) return ;
2022-11-20 10:53:33 +00:00
const self = this ;
// Keyboard takes top priority
let keyboardDiffVec = cc . v2 ( 0 , 0 ) ;
if ( 1 == this . cachedBtnUpLevel ) {
if ( 1 == this . cachedBtnLeftLevel ) {
keyboardDiffVec = cc . v2 ( - 1.0 , + 1.0 ) ;
} else if ( 1 == this . cachedBtnRightLevel ) {
keyboardDiffVec = cc . v2 ( + 1.0 , + 1.0 ) ;
} else {
keyboardDiffVec = cc . v2 ( 0.0 , + 1.0 ) ;
}
} else if ( 1 == this . cachedBtnDownLevel ) {
if ( 1 == this . cachedBtnLeftLevel ) {
keyboardDiffVec = cc . v2 ( - 1.0 , - 1.0 ) ;
} else if ( 1 == this . cachedBtnRightLevel ) {
keyboardDiffVec = cc . v2 ( + 1.0 , - 1.0 ) ;
} else {
keyboardDiffVec = cc . v2 ( 0.0 , - 1.0 ) ;
}
} else if ( 1 == this . cachedBtnLeftLevel ) {
keyboardDiffVec = cc . v2 ( - 1.0 , 0.0 ) ;
} else if ( 1 == this . cachedBtnRightLevel ) {
keyboardDiffVec = cc . v2 ( + 1.0 , 0.0 ) ;
}
if ( 0 != keyboardDiffVec . x || 0 != keyboardDiffVec . y ) {
this . cachedStickHeadPosition = keyboardDiffVec . mul ( this . maxHeadDistance / keyboardDiffVec . mag ( ) ) ;
}
2022-09-20 15:50:01 +00:00
this . stickhead . setPosition ( this . cachedStickHeadPosition ) ;
2022-11-20 10:53:33 +00:00
const translationListenerNode = ( self . translationListenerNode ? self . translationListenerNode : self . mapNode ) ;
if ( 0 == translationListenerNode . inTouchPoints . size
&&
( 0 == keyboardDiffVec . x && 0 == keyboardDiffVec . y )
) {
this . cachedStickHeadPosition = cc . v2 ( 0 , 0 ) ; // Important reset!
}
2022-09-20 15:50:01 +00:00
} ,
discretizeDirection ( continuousDx , continuousDy , eps ) {
let ret = {
dx : 0 ,
dy : 0 ,
encodedIdx : 0
} ;
if ( Math . abs ( continuousDx ) < eps && Math . abs ( continuousDy ) < eps ) {
2022-11-10 10:18:00 +00:00
return ret ;
2022-09-20 15:50:01 +00:00
}
2022-11-10 13:28:46 +00:00
const criticalRatio = continuousDy / continuousDx ;
if ( Math . abs ( criticalRatio ) < this . magicLeanLowerBound ) {
2022-09-20 15:50:01 +00:00
ret . dy = 0 ;
if ( 0 < continuousDx ) {
ret . dx = + 2 ; // right
ret . encodedIdx = 3 ;
} else {
ret . dx = - 2 ; // left
ret . encodedIdx = 4 ;
}
2022-11-10 13:28:46 +00:00
} else if ( Math . abs ( criticalRatio ) > this . magicLeanUpperBound ) {
ret . dx = 0 ;
if ( 0 < continuousDy ) {
ret . dy = + 2 ; // up
ret . encodedIdx = 1 ;
} else {
ret . dy = - 2 ; // down
ret . encodedIdx = 2 ;
}
2022-09-20 15:50:01 +00:00
} else {
2022-11-10 13:28:46 +00:00
if ( 0 < continuousDx ) {
if ( 0 < continuousDy ) {
2022-11-10 10:18:00 +00:00
ret . dx = + 1 ;
2022-09-20 15:50:01 +00:00
ret . dy = + 1 ;
ret . encodedIdx = 5 ;
} else {
2022-11-10 10:18:00 +00:00
ret . dx = + 1 ;
2022-09-20 15:50:01 +00:00
ret . dy = - 1 ;
ret . encodedIdx = 7 ;
2022-11-10 13:28:46 +00:00
}
} else {
// 0 >= continuousDx
if ( 0 < continuousDy ) {
2022-11-10 10:18:00 +00:00
ret . dx = - 1 ;
2022-09-20 15:50:01 +00:00
ret . dy = + 1 ;
ret . encodedIdx = 8 ;
2022-11-10 13:28:46 +00:00
} else {
ret . dx = - 1 ;
ret . dy = - 1 ;
ret . encodedIdx = 6 ;
2022-09-20 15:50:01 +00:00
}
}
}
2022-11-10 13:28:46 +00:00
2022-09-20 15:50:01 +00:00
return ret ;
} ,
2022-11-20 10:53:33 +00:00
getEncodedInput ( ) {
const discretizedDir = this . discretizeDirection ( this . stickhead . x , this . stickhead . y , this . joyStickEps ) . encodedIdx ; // There're only 9 dirs, thus using only the lower 4-bits
const btnALevel = ( this . cachedBtnALevel << 4 ) ;
2022-12-09 16:07:03 +00:00
const btnBLevel = ( this . cachedBtnBLevel << 5 ) ;
return ( btnBLevel + btnALevel + discretizedDir ) ;
2022-11-20 10:53:33 +00:00
} ,
decodeInput ( encodedInput ) {
2022-11-20 16:23:01 +00:00
const encodedDirection = ( encodedInput & 15 ) ;
2022-11-20 10:53:33 +00:00
const mappedDirection = window . DIRECTION _DECODER [ encodedDirection ] ;
if ( null == mappedDirection ) {
2022-11-10 10:18:00 +00:00
console . error ( "Unexpected encodedDirection = " , encodedDirection ) ;
2022-09-20 15:50:01 +00:00
}
2022-11-20 10:53:33 +00:00
const btnALevel = ( ( encodedInput >> 4 ) & 1 ) ;
2022-12-09 16:07:03 +00:00
const btnBLevel = ( ( encodedInput >> 5 ) & 1 ) ;
2022-11-21 09:27:32 +00:00
return window . pb . protos . InputFrameDecoded . create ( {
2022-11-20 10:53:33 +00:00
dx : mappedDirection [ 0 ] ,
dy : mappedDirection [ 1 ] ,
2022-11-21 09:27:32 +00:00
btnALevel : btnALevel ,
2022-12-09 16:07:03 +00:00
btnBLevel : btnBLevel ,
2022-11-21 09:27:32 +00:00
} ) ;
2022-09-20 15:50:01 +00:00
} ,
} ) ;