2022-11-17 15:39:32 +00:00
const i18n = require ( 'LanguageData' ) ;
i18n . init ( window . language ) ; // languageID should be equal to the one we input in New Language ID input field
const OnlineMap = require ( './Map' ) ;
cc . Class ( {
extends : OnlineMap ,
onDestroy ( ) {
console . warn ( "+++++++ Map onDestroy()" ) ;
} ,
onLoad ( ) {
const self = this ;
window . mapIns = self ;
2022-12-12 15:17:54 +00:00
self . showCriticalCoordinateLabels = true ;
2022-11-17 15:39:32 +00:00
2022-11-19 12:58:07 +00:00
cc . director . getCollisionManager ( ) . enabled = false ;
const mapNode = self . node ;
const canvasNode = mapNode . parent ;
self . mainCameraNode = self . canvasNode . getChildByName ( "Main Camera" ) ;
2022-11-17 15:39:32 +00:00
self . mainCamera = self . mainCameraNode . getComponent ( cc . Camera ) ;
for ( let child of self . mainCameraNode . children ) {
child . setScale ( 1 / self . mainCamera . zoomRatio ) ;
}
self . widgetsAboveAllNode = self . mainCameraNode . getChildByName ( "WidgetsAboveAll" ) ;
self . mainCameraNode . setPosition ( cc . v2 ( ) ) ;
/** Init required prefab ended. */
2022-11-19 12:58:07 +00:00
self . inputDelayFrames = 8 ;
self . inputScaleFrames = 2 ;
self . inputFrameUpsyncDelayTolerance = 2 ;
2022-11-17 15:39:32 +00:00
2022-12-01 03:35:56 +00:00
self . renderCacheSize = 1024 ;
2022-12-09 09:22:04 +00:00
self . serverFps = 60 ;
2022-11-19 12:58:07 +00:00
self . rollbackEstimatedDt = 0.016667 ;
self . rollbackEstimatedDtMillis = 16.667 ;
self . rollbackEstimatedDtNanos = 16666666 ;
2022-12-12 11:11:59 +00:00
self . tooFastDtIntervalMillis = 0.5 * self . rollbackEstimatedDtMillis ;
2022-11-17 15:39:32 +00:00
2022-11-19 12:58:07 +00:00
self . worldToVirtualGridRatio = 1000 ;
self . virtualGridToWorldRatio = 1.0 / self . worldToVirtualGridRatio ;
2022-11-24 11:45:48 +00:00
self . meleeSkillConfig = {
1 : {
// for offender
2022-11-27 11:38:26 +00:00
startupFrames : 10 ,
2022-11-25 00:21:03 +00:00
activeFrames : 3 ,
2022-11-27 11:38:26 +00:00
recoveryFrames : 34 , // usually but not always "startupFrames+activeFrames", I hereby set it to be 1 frame more than the actual animation to avoid critical transition, i.e. when the animation is 1 frame from ending but "rdfPlayer.framesToRecover" is already counted 0 and the player triggers an other same attack, making an effective bullet trigger but no animation is played due to same animName is still playing
recoveryFramesOnBlock : 34 ,
recoveryFramesOnHit : 34 ,
2022-11-24 11:45:48 +00:00
moveforward : {
x : 0 ,
y : 0 ,
} ,
hitboxOffset : 12.0 , // should be about the radius of the PlayerCollider
hitboxSize : {
2022-11-27 11:38:26 +00:00
x : 23.0 ,
2022-11-27 13:33:34 +00:00
y : 32.0 ,
2022-11-24 11:45:48 +00:00
} ,
// for defender
hitStunFrames : 18 ,
blockStunFrames : 9 ,
2022-11-27 11:38:26 +00:00
pushback : 8.0 ,
2022-11-24 11:45:48 +00:00
releaseTriggerType : 1 , // 1: rising-edge, 2: falling-edge
damage : 5
}
} ;
2022-11-17 15:39:32 +00:00
2022-12-11 09:26:55 +00:00
/ *
[ WARNING ] As when a character is standing on a barrier , if not carefully curated there MIGHT BE a bouncing sequence of "[(inAir -> dropIntoBarrier ->), (notInAir -> pushedOutOfBarrier ->)], [(inAir -> ..."
2022-12-12 15:17:54 +00:00
Moreover , "snapIntoPlatformOverlap" should be small enough such that the walking "velX" or jumping initial "velY" can escape from it by 1 renderFrame ( when jumping is triggered , the character is waived from snappig for 1 renderFrame ) .
2022-12-11 09:26:55 +00:00
* /
2022-12-13 10:10:30 +00:00
self . snapIntoPlatformOverlap = 0.01 ;
2022-12-11 09:26:55 +00:00
self . snapIntoPlatformThreshold = 0.5 ; // a platform must be "horizontal enough" for a character to "stand on"
2022-12-12 08:42:11 +00:00
self . jumpingInitVelY = 6 * self . worldToVirtualGridRatio ; // unit: (virtual grid length/renderFrame)
[ self . gravityX , self . gravityY ] = [ 0 , - Math . ceil ( 4 * self . jumpingInitVelY / self . serverFps ) ] ; // unit: (virtual grid length/renderFrame^2)
2022-12-11 09:26:55 +00:00
2022-11-17 15:39:32 +00:00
const tiledMapIns = self . node . getComponent ( cc . TiledMap ) ;
2022-11-19 12:58:07 +00:00
const fullPathOfTmxFile = cc . js . formatStr ( "map/%s/map" , "dungeon" ) ;
2022-11-17 15:39:32 +00:00
cc . loader . loadRes ( fullPathOfTmxFile , cc . TiledMapAsset , ( err , tmxAsset ) => {
if ( null != err ) {
console . error ( err ) ;
return ;
}
tiledMapIns . tmxAsset = null ;
mapNode . removeAllChildren ( ) ;
self . _resetCurrentMatch ( ) ;
2022-12-11 04:20:42 +00:00
if ( self . showCriticalCoordinateLabels ) {
const drawer = new cc . Node ( ) ;
drawer . setPosition ( cc . v2 ( 0 , 0 ) )
safelyAddChild ( self . node , drawer ) ;
setLocalZOrder ( drawer , 999 ) ;
const g = drawer . addComponent ( cc . Graphics ) ;
g . lineWidth = 2 ;
self . g = g ;
}
2022-11-17 15:39:32 +00:00
tiledMapIns . tmxAsset = tmxAsset ;
const newMapSize = tiledMapIns . getMapSize ( ) ;
const newTileSize = tiledMapIns . getTileSize ( ) ;
self . node . setContentSize ( newMapSize . width * newTileSize . width , newMapSize . height * newTileSize . height ) ;
self . node . setPosition ( cc . v2 ( 0 , 0 ) ) ;
let barrierIdCounter = 0 ;
const boundaryObjs = tileCollisionManager . extractBoundaryObjects ( self . node ) ;
for ( let boundaryObj of boundaryObjs . barriers ) {
const x0 = boundaryObj . anchor . x ,
y0 = boundaryObj . anchor . y ;
const newBarrier = self . collisionSys . createPolygon ( x0 , y0 , Array . from ( boundaryObj , p => {
return [ p . x , p . y ] ;
} ) ) ;
2022-12-12 15:17:54 +00:00
newBarrier . data = {
hardPushback : true
} ;
2022-11-17 15:39:32 +00:00
2022-12-11 09:26:55 +00:00
if ( false && self . showCriticalCoordinateLabels ) {
2022-11-17 15:39:32 +00:00
for ( let i = 0 ; i < boundaryObj . length ; ++ i ) {
const barrierVertLabelNode = new cc . Node ( ) ;
switch ( i % 4 ) {
case 0 :
barrierVertLabelNode . color = cc . Color . RED ;
break ;
case 1 :
barrierVertLabelNode . color = cc . Color . GRAY ;
break ;
case 2 :
barrierVertLabelNode . color = cc . Color . BLACK ;
break ;
default :
barrierVertLabelNode . color = cc . Color . MAGENTA ;
break ;
}
const wx = boundaryObj . anchor . x + boundaryObj [ i ] . x ,
wy = boundaryObj . anchor . y + boundaryObj [ i ] . y ;
barrierVertLabelNode . setPosition ( cc . v2 ( wx , wy ) ) ;
const barrierVertLabel = barrierVertLabelNode . addComponent ( cc . Label ) ;
barrierVertLabel . fontSize = 12 ;
barrierVertLabel . lineHeight = barrierVertLabel . fontSize + 1 ;
barrierVertLabel . string = ` ( ${ wx . toFixed ( 1 ) } , ${ wy . toFixed ( 1 ) } ) ` ;
safelyAddChild ( self . node , barrierVertLabelNode ) ;
setLocalZOrder ( barrierVertLabelNode , 5 ) ;
barrierVertLabelNode . active = true ;
}
}
// console.log("Created barrier: ", newBarrier);
++ barrierIdCounter ;
const collisionBarrierIndex = ( self . collisionBarrierIndexPrefix + barrierIdCounter ) ;
self . collisionSysMap . set ( collisionBarrierIndex , newBarrier ) ;
}
2022-11-19 12:58:07 +00:00
2022-11-25 05:24:03 +00:00
const startRdf = window . pb . protos . RoomDownsyncFrame . create ( {
2022-11-19 12:58:07 +00:00
id : window . MAGIC _ROOM _DOWNSYNC _FRAME _ID . BATTLE _START ,
players : {
2022-12-09 09:22:04 +00:00
10 : window . pb . protos . PlayerDownsync . create ( {
2022-11-19 12:58:07 +00:00
id : 10 ,
2022-11-20 13:07:45 +00:00
joinIndex : 1 ,
2022-12-12 08:42:11 +00:00
virtualGridX : self . worldToVirtualGridPos ( boundaryObjs . playerStartingPositions [ 0 ] . x , boundaryObjs . playerStartingPositions [ 0 ] . y ) [ 0 ] ,
virtualGridY : self . worldToVirtualGridPos ( boundaryObjs . playerStartingPositions [ 0 ] . x , boundaryObjs . playerStartingPositions [ 0 ] . y ) [ 1 ] ,
2022-11-25 00:21:03 +00:00
speed : 1 * self . worldToVirtualGridRatio ,
2022-11-22 08:19:04 +00:00
colliderRadius : 12 ,
2022-12-09 09:22:04 +00:00
characterState : window . ATK _CHARACTER _STATE . InAirIdle1 [ 0 ] ,
2022-11-23 07:04:32 +00:00
framesToRecover : 0 ,
2022-11-23 14:11:28 +00:00
dirX : 0 ,
dirY : 0 ,
2022-12-09 09:22:04 +00:00
velX : 0 ,
velY : 0 ,
inAir : true ,
} ) ,
11 : window . pb . protos . PlayerDownsync . create ( {
2022-11-22 08:19:04 +00:00
id : 11 ,
joinIndex : 2 ,
2022-12-12 08:42:11 +00:00
virtualGridX : self . worldToVirtualGridPos ( boundaryObjs . playerStartingPositions [ 1 ] . x , boundaryObjs . playerStartingPositions [ 1 ] . y ) [ 0 ] ,
virtualGridY : self . worldToVirtualGridPos ( boundaryObjs . playerStartingPositions [ 1 ] . x , boundaryObjs . playerStartingPositions [ 1 ] . y ) [ 1 ] ,
2022-11-25 00:21:03 +00:00
speed : 1 * self . worldToVirtualGridRatio ,
2022-11-19 12:58:07 +00:00
colliderRadius : 12 ,
2022-12-09 09:22:04 +00:00
characterState : window . ATK _CHARACTER _STATE . InAirIdle1 [ 0 ] ,
2022-11-23 07:04:32 +00:00
framesToRecover : 0 ,
2022-11-23 14:11:28 +00:00
dirX : 0 ,
dirY : 0 ,
2022-12-09 09:22:04 +00:00
velX : 0 ,
velY : 0 ,
inAir : true ,
} ) ,
2022-11-19 12:58:07 +00:00
}
2022-11-25 05:24:03 +00:00
} ) ;
2022-11-19 12:58:07 +00:00
self . selfPlayerInfo = {
2022-11-27 13:33:34 +00:00
id : 11
2022-11-19 12:58:07 +00:00
} ;
2022-11-22 08:19:04 +00:00
self . _initPlayerRichInfoDict ( startRdf . players ) ;
2022-11-19 12:58:07 +00:00
self . onRoomDownsyncFrame ( startRdf ) ;
self . battleState = ALL _BATTLE _STATES . IN _BATTLE ;
2022-11-17 15:39:32 +00:00
} ) ;
} ,
update ( dt ) {
const self = this ;
if ( ALL _BATTLE _STATES . IN _BATTLE == self . battleState ) {
const elapsedMillisSinceLastFrameIdTriggered = performance . now ( ) - self . lastRenderFrameIdTriggeredAt ;
2022-12-12 11:11:59 +00:00
if ( elapsedMillisSinceLastFrameIdTriggered < self . tooFastDtIntervalMillis ) {
// [WARNING] We should avoid a frontend ticking too fast to prevent cheating, as well as ticking too slow to cause a "resync avalanche" that impacts user experience!
2022-11-17 15:39:32 +00:00
// console.debug("Avoiding too fast frame@renderFrameId=", self.renderFrameId, ": elapsedMillisSinceLastFrameIdTriggered=", elapsedMillisSinceLastFrameIdTriggered);
return ;
}
try {
let st = performance . now ( ) ;
let prevSelfInput = null ,
currSelfInput = null ;
const noDelayInputFrameId = self . _convertToInputFrameId ( self . renderFrameId , 0 ) ; // It's important that "inputDelayFrames == 0" here
if ( self . shouldGenerateInputFrameUpsync ( self . renderFrameId ) ) {
const prevAndCurrInputs = self . _generateInputFrameUpsync ( noDelayInputFrameId ) ;
prevSelfInput = prevAndCurrInputs [ 0 ] ;
currSelfInput = prevAndCurrInputs [ 1 ] ;
}
2022-11-25 03:20:05 +00:00
const [ prevRdf , rdf ] = self . rollbackAndChase ( self . renderFrameId , self . renderFrameId + 1 , self . collisionSys , self . collisionSysMap , false ) ;
self . applyRoomDownsyncFrameDynamics ( rdf , prevRdf ) ;
2022-12-12 15:17:54 +00:00
self . showDebugBoundaries ( rdf ) ;
2022-12-12 11:11:59 +00:00
++ self . renderFrameId ;
self . lastRenderFrameIdTriggeredAt = performance . now ( ) ;
2022-11-17 15:39:32 +00:00
let t3 = performance . now ( ) ;
} catch ( err ) {
console . error ( "Error during Map.update" , err ) ;
2022-12-11 04:20:42 +00:00
}
}
} ,
2022-11-17 15:39:32 +00:00
} ) ;