diff --git a/frontend/assets/resources/prefabs/ControlledCharacter.prefab b/frontend/assets/resources/prefabs/ControlledCharacter.prefab index c797cc4..0bee135 100644 --- a/frontend/assets/resources/prefabs/ControlledCharacter.prefab +++ b/frontend/assets/resources/prefabs/ControlledCharacter.prefab @@ -33,14 +33,14 @@ "_active": true, "_components": [ { - "__id__": 20 + "__id__": 23 }, { - "__id__": 21 + "__id__": 24 } ], "_prefab": { - "__id__": 22 + "__id__": 25 }, "_opacity": 255, "_color": { @@ -128,8 +128,8 @@ "__type__": "TypedArray", "ctor": "Float64Array", "array": [ - -5, - 50, + 0, + 0, 0, 0, 0, @@ -490,12 +490,15 @@ }, { "__id__": 15 + }, + { + "__id__": 18 } ], "_active": true, "_components": [], "_prefab": { - "__id__": 19 + "__id__": 22 }, "_opacity": 255, "_color": { @@ -584,7 +587,7 @@ "ctor": "Float64Array", "array": [ 0, - 0, + -10, 0, 0, 0, @@ -671,13 +674,128 @@ "_components": [ { "__id__": 16 - }, - { - "__id__": 17 } ], "_prefab": { - "__id__": 18 + "__id__": 17 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 0, + "height": 0 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + -10, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "dragonBones.ArmatureDisplay", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 15 + }, + "_enabled": true, + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], + "_armatureName": "SoldierFireGhost", + "_animationName": "Idle1", + "_preCacheMode": 0, + "_cacheMode": 0, + "playTimes": -1, + "premultipliedAlpha": false, + "_armatureKey": "36230012-8df3-4e85-afad-76ec47d0e4d7#4a9187d5-a9ad-4464-a03c-d2f3cc277051", + "_accTime": 0, + "_playCount": 0, + "_frameCache": null, + "_curFrame": null, + "_playing": false, + "_armatureCache": null, + "_N$dragonAsset": { + "__uuid__": "36230012-8df3-4e85-afad-76ec47d0e4d7" + }, + "_N$dragonAtlasAsset": { + "__uuid__": "4a9187d5-a9ad-4464-a03c-d2f3cc277051" + }, + "_N$_defaultArmatureIndex": 0, + "_N$_animationIndex": 8, + "_N$_defaultCacheMode": 0, + "_N$timeScale": 1, + "_N$debugBones": false, + "_N$enableBatch": false, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__uuid__": "59bff7a2-23e1-4d69-bce7-afb37eae196a" + }, + "fileId": "3b2LJFABVL7ozO2U81FC4U", + "sync": false + }, + { + "__type__": "cc.Node", + "_name": "SoldierFireGhostFrameAnim", + "_objFlags": 0, + "_parent": { + "__id__": 11 + }, + "_children": [], + "_active": false, + "_components": [ + { + "__id__": 19 + }, + { + "__id__": 20 + } + ], + "_prefab": { + "__id__": 21 }, "_opacity": 255, "_color": { @@ -702,7 +820,7 @@ "ctor": "Float64Array", "array": [ 0, - 0, + -12, 0, 0, 0, @@ -731,7 +849,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 15 + "__id__": 18 }, "_enabled": true, "_defaultClip": null, @@ -748,15 +866,14 @@ { "__uuid__": "c69bcceb-d7d1-4e33-9623-e2a374a0a6b6" }, - null, + { + "__uuid__": "43dbf141-be76-48c3-bdef-29233ccbe30d" + }, { "__uuid__": "c738236a-0702-45f8-aa38-99457b051997" }, { "__uuid__": "c69bcceb-d7d1-4e33-9623-e2a374a0a6b6" - }, - { - "__uuid__": "43dbf141-be76-48c3-bdef-29233ccbe30d" } ], "playOnLoad": false, @@ -767,7 +884,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 15 + "__id__": 18 }, "_enabled": true, "_materials": [ diff --git a/frontend/assets/scripts/AttackingCharacter.js b/frontend/assets/scripts/AttackingCharacter.js index a933cc5..b4db4e6 100644 --- a/frontend/assets/scripts/AttackingCharacter.js +++ b/frontend/assets/scripts/AttackingCharacter.js @@ -81,8 +81,8 @@ cc.Class({ this.animComp = this.effAnimNode.getComponent(dragonBones.ArmatureDisplay); if (!this.animComp) { this.animComp = this.effAnimNode.getComponent(cc.Animation); - this.effAnimNode.anchorY = 0.0; // Otherwise the frame anim will show with an incorrect y-offset even if the collider boundaries are all correct! - } + this.effAnimNode.anchorY = 0.0; // Otherwise the anim will show with an incorrect y-offset even if the collider boundaries are all correct! + } this.effAnimNode.active = true; }, diff --git a/frontend/assets/scripts/Map.js b/frontend/assets/scripts/Map.js index c543061..b748d62 100644 --- a/frontend/assets/scripts/Map.js +++ b/frontend/assets/scripts/Map.js @@ -273,8 +273,7 @@ cc.Class({ const self = this; const mapNode = self.node; const canvasNode = mapNode.parent; - - [self.gravityX, self.gravityY] = self.worldToVirtualGridPos(0/self.serverFps, -9.8/self.serverFps); + [self.gravityX, self.gravityY] = self.worldToVirtualGridPos(0 / self.serverFps, -9.8 / self.serverFps); // Clearing previous info of all players. [BEGINS] self.collisionPlayerIndexPrefix = (1 << 17); // For tracking the movements of players @@ -775,6 +774,7 @@ cc.Class({ const [x0, y0] = self.virtualGridToPolygonColliderAnchorPos(vx, vy, colliderWidth, colliderHeight), pts = [[0, 0], [colliderWidth, 0], [colliderWidth, colliderHeight], [0, colliderHeight]]; + // [WARNING] The animNode "anchor & offset" are tuned to fit in this collider by "ControlledCharacter prefab & AttackingCharacter.js"! const newPlayerCollider = self.collisionSys.createPolygon(x0, y0, pts); const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex; newPlayerCollider.data = playerDownsyncInfo; @@ -1059,7 +1059,7 @@ cc.Class({ } const [offenderWx, offenderWy] = self.virtualGridToWorldPos(offender.virtualGridX, offender.virtualGridY); const bulletWx = offenderWx + xfac * meleeBullet.hitboxOffset; - const bulletWy = offenderWy; + const bulletWy = offenderWy + 0.5 * meleeBullet.hitboxSize.y; const [bulletCx, bulletCy] = self.worldToPolygonColliderAnchorPos(bulletWx, bulletWy, meleeBullet.hitboxSize.x * 0.5, meleeBullet.hitboxSize.y * 0.5), pts = [[0, 0], [meleeBullet.hitboxSize.x, 0], [meleeBullet.hitboxSize.x, meleeBullet.hitboxSize.y], [0, meleeBullet.hitboxSize.y]]; const newBulletCollider = collisionSys.createPolygon(bulletCx, bulletCy, pts); diff --git a/frontend/assets/scripts/OfflineMap.js b/frontend/assets/scripts/OfflineMap.js index 87ab1d3..e85745b 100644 --- a/frontend/assets/scripts/OfflineMap.js +++ b/frontend/assets/scripts/OfflineMap.js @@ -19,6 +19,7 @@ cc.Class({ onLoad() { const self = this; window.mapIns = self; + self.showCriticalCoordinateLabels = true; cc.director.getCollisionManager().enabled = false; @@ -87,6 +88,17 @@ cc.Class({ mapNode.removeAllChildren(); self._resetCurrentMatch(); + 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; + } + + tiledMapIns.tmxAsset = tmxAsset; const newMapSize = tiledMapIns.getMapSize(); const newTileSize = tiledMapIns.getTileSize(); @@ -186,40 +198,6 @@ cc.Class({ }, - spawnPlayerNode(joinIndex, vx, vy, playerDownsyncInfo) { - const self = this; - const newPlayerNode = cc.instantiate(self.controlledCharacterPrefab) - const playerScriptIns = newPlayerNode.getComponent("ControlledCharacter"); - if (1 == joinIndex) { - playerScriptIns.setSpecies("SoldierWaterGhost"); - } else if (2 == joinIndex) { - playerScriptIns.setSpecies("SoldierFireGhost"); - } - - const [wx, wy] = self.virtualGridToWorldPos(vx, vy); - newPlayerNode.setPosition(wx, wy); - playerScriptIns.mapNode = self.node; - const colliderWidth = playerDownsyncInfo.colliderRadius * 2, - colliderHeight = playerDownsyncInfo.colliderRadius * 2.5; - const [x0, y0] = self.virtualGridToPolygonColliderAnchorPos(vx, vy, colliderWidth, colliderHeight), - pts = [[0, 0], [colliderWidth, 0], [colliderWidth, colliderHeight], [0, colliderHeight]]; - - const newPlayerCollider = self.collisionSys.createPolygon(x0, y0, pts); - const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex; - newPlayerCollider.data = playerDownsyncInfo; - self.collisionSysMap.set(collisionPlayerIndex, newPlayerCollider); - - console.log(`Created new player collider: joinIndex=${joinIndex}, colliderRadius=${playerDownsyncInfo.colliderRadius}`); - - safelyAddChild(self.node, newPlayerNode); - setLocalZOrder(newPlayerNode, 5); - - newPlayerNode.active = true; - playerScriptIns.updateCharacterAnim(playerDownsyncInfo, null, true); - - return [newPlayerNode, playerScriptIns]; - }, - update(dt) { const self = this; if (ALL_BATTLE_STATES.IN_BATTLE == self.battleState) { @@ -333,7 +311,7 @@ cc.Class({ } const [offenderWx, offenderWy] = self.virtualGridToWorldPos(offender.virtualGridX, offender.virtualGridY); const bulletWx = offenderWx + xfac * meleeBullet.hitboxOffset; - const bulletWy = offenderWy; + const bulletWy = offenderWy + 0.5 * meleeBullet.hitboxSize.y; const [bulletCx, bulletCy] = self.worldToPolygonColliderAnchorPos(bulletWx, bulletWy, meleeBullet.hitboxSize.x * 0.5, meleeBullet.hitboxSize.y * 0.5), pts = [[0, 0], [meleeBullet.hitboxSize.x, 0], [meleeBullet.hitboxSize.x, meleeBullet.hitboxSize.y], [0, meleeBullet.hitboxSize.y]]; const newBulletCollider = collisionSys.createPolygon(bulletCx, bulletCy, pts); @@ -539,4 +517,106 @@ cc.Class({ meleeBullets: nextRenderFrameMeleeBullets, }); }, + + applyRoomDownsyncFrameDynamics(rdf, prevRdf) { + const self = this; + OnlineMap.prototype.applyRoomDownsyncFrameDynamics.call(self, rdf, prevRdf); + if (self.showCriticalCoordinateLabels) { + let g = self.g; + g.clear(); + + for (let k in self.collisionSys._bvh._bodies) { + const body = self.collisionSys._bvh._bodies[k]; + if (!body._polygon) continue; + if (null != body.data && null != body.data.joinIndex) { + // character + if (1 == body.data.joinIndex) { + g.strokeColor = cc.Color.BLUE; + } else { + g.strokeColor = cc.Color.RED; + } + } else { + // barrier + g.strokeColor = cc.Color.WHITE; + } + g.moveTo(body.x, body.y); + const cnt = body._coords.length; + for (let j = 0; j < cnt; j += 2) { + const x = body._coords[j], + y = body._coords[j + 1]; + g.lineTo(x, y); + } + g.lineTo(body.x, body.y); + g.stroke(); + } + // For convenience of recovery upon reconnection, active bullets are always created & immediately removed from "collisionSys" within "applyInputFrameDownsyncDynamicsOnSingleRenderFrame" + + for (let k in rdf.meleeBullets) { + const meleeBullet = rdf.meleeBullets[k]; + if ( + meleeBullet.originatedRenderFrameId + meleeBullet.startupFrames <= rdf.id + && + meleeBullet.originatedRenderFrameId + meleeBullet.startupFrames + meleeBullet.activeFrames > rdf.id + ) { + const offender = rdf.players[meleeBullet.offenderPlayerId]; + if (1 == offender.joinIndex) { + g.strokeColor = cc.Color.BLUE; + } else { + g.strokeColor = cc.Color.RED; + } + + let xfac = 1; // By now, straight Punch offset doesn't respect "y-axis" + if (0 > offender.dirX) { + xfac = -1; + } + const [offenderWx, offenderWy] = self.virtualGridToWorldPos(offender.virtualGridX, offender.virtualGridY); + const bulletWx = offenderWx + xfac * meleeBullet.hitboxOffset; + const bulletWy = offenderWy + 0.5 * meleeBullet.hitboxSize.y; + const [bulletCx, bulletCy] = self.worldToPolygonColliderAnchorPos(bulletWx, bulletWy, meleeBullet.hitboxSize.x * 0.5, meleeBullet.hitboxSize.y * 0.5), + pts = [[0, 0], [meleeBullet.hitboxSize.x, 0], [meleeBullet.hitboxSize.x, meleeBullet.hitboxSize.y], [0, meleeBullet.hitboxSize.y]]; + + g.moveTo(bulletCx, bulletCy); + for (let j = 0; j < pts.length; j += 1) { + g.lineTo(pts[j][0] + bulletCx, pts[j][1] + bulletCy); + } + g.lineTo(bulletCx, bulletCy); + g.stroke(); + } + } + } + }, + + spawnPlayerNode(joinIndex, vx, vy, playerDownsyncInfo) { + const self = this; + const newPlayerNode = cc.instantiate(self.controlledCharacterPrefab) + const playerScriptIns = newPlayerNode.getComponent("ControlledCharacter"); + if (1 == joinIndex) { + playerScriptIns.setSpecies("SoldierWaterGhost"); + } else if (2 == joinIndex) { + playerScriptIns.setSpecies("SoldierFireGhost"); + } + + const [wx, wy] = self.virtualGridToWorldPos(vx, vy); + newPlayerNode.setPosition(wx, wy); + playerScriptIns.mapNode = self.node; + const colliderWidth = playerDownsyncInfo.colliderRadius * 2, + colliderHeight = playerDownsyncInfo.colliderRadius * 4; + const [x0, y0] = self.virtualGridToPolygonColliderAnchorPos(vx, vy, colliderWidth, colliderHeight), + pts = [[0, 0], [colliderWidth, 0], [colliderWidth, colliderHeight], [0, colliderHeight]]; + + const newPlayerCollider = self.collisionSys.createPolygon(x0, y0, pts); + const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex; + newPlayerCollider.data = playerDownsyncInfo; + self.collisionSysMap.set(collisionPlayerIndex, newPlayerCollider); + + console.log(`Created new player collider: joinIndex=${joinIndex}, colliderRadius=${playerDownsyncInfo.colliderRadius}`); + + safelyAddChild(self.node, newPlayerNode); + setLocalZOrder(newPlayerNode, 5); + + newPlayerNode.active = true; + playerScriptIns.updateCharacterAnim(playerDownsyncInfo, null, true); + + return [newPlayerNode, playerScriptIns]; + }, });