diff --git a/battle_srv/models/room.go b/battle_srv/models/room.go index a947116..40a3ed4 100644 --- a/battle_srv/models/room.go +++ b/battle_srv/models/room.go @@ -201,7 +201,7 @@ func (pR *Room) AddPlayerIfPossible(pPlayerFromDbInit *Player, session *websocke pPlayerFromDbInit.LastSentInputFrameId = MAGIC_LAST_SENT_INPUT_FRAME_ID_NORMAL_ADDED pPlayerFromDbInit.BattleState = PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK pPlayerFromDbInit.Speed = pR.PlayerDefaultSpeed // Hardcoded - pPlayerFromDbInit.ColliderRadius = float64(12) // Hardcoded + pPlayerFromDbInit.ColliderRadius = float64(24) // Hardcoded pR.Players[playerId] = pPlayerFromDbInit pR.PlayerDownsyncSessionDict[playerId] = session @@ -234,7 +234,7 @@ func (pR *Room) ReAddPlayerIfPossible(pTmpPlayerInstance *Player, session *webso pEffectiveInRoomPlayerInstance.LastSentInputFrameId = MAGIC_LAST_SENT_INPUT_FRAME_ID_READDED pEffectiveInRoomPlayerInstance.BattleState = PlayerBattleStateIns.READDED_PENDING_BATTLE_COLLIDER_ACK pEffectiveInRoomPlayerInstance.Speed = pR.PlayerDefaultSpeed // Hardcoded - pEffectiveInRoomPlayerInstance.ColliderRadius = float64(12) // Hardcoded + pEffectiveInRoomPlayerInstance.ColliderRadius = float64(16) // Hardcoded Logger.Warn("ReAddPlayerIfPossible finished.", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("joinIndex", pEffectiveInRoomPlayerInstance.JoinIndex), zap.Any("playerBattleState", pEffectiveInRoomPlayerInstance.BattleState), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount), zap.Any("AckingFrameId", pEffectiveInRoomPlayerInstance.AckingFrameId), zap.Any("AckingInputFrameId", pEffectiveInRoomPlayerInstance.AckingInputFrameId), zap.Any("LastSentInputFrameId", pEffectiveInRoomPlayerInstance.LastSentInputFrameId)) return true @@ -252,7 +252,7 @@ func (pR *Room) ChooseStage() error { } rand.Seed(time.Now().Unix()) - stageNameList := []string{ /*"simple" ,*/ "richsoil"} + stageNameList := []string{"simple" /* "richsoil" */} chosenStageIndex := rand.Int() % len(stageNameList) // Hardcoded temporarily. -- YFLu pR.StageName = stageNameList[chosenStageIndex] @@ -792,7 +792,7 @@ func (pR *Room) OnDismissed() { // Always instantiates new HeapRAM blocks and let the old blocks die out due to not being retained by any root reference. pR.WorldToVirtualGridRatio = float64(10) pR.VirtualGridToWorldRatio = float64(1.0) / pR.WorldToVirtualGridRatio // this is a one-off computation, should avoid division in iterations - pR.PlayerDefaultSpeed = 10 // Hardcoded in virtual grids per frame + pR.PlayerDefaultSpeed = 20 // Hardcoded in virtual grids per frame pR.Players = make(map[int32]*Player) pR.PlayersArr = make([]*Player, pR.Capacity) pR.CollisionSysMap = make(map[int32]*resolv.Object) @@ -940,7 +940,7 @@ func (pR *Room) onPlayerAdded(playerId int32) { if nil == playerPos { panic(fmt.Sprintf("onPlayerAdded error, nil == playerPos, roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount)) } - pR.Players[playerId].VirtualGridX, pR.Players[playerId].VirtualGridY = pR.worldToVirtualGridPos(playerPos.X, playerPos.Y) + pR.Players[playerId].VirtualGridX, pR.Players[playerId].VirtualGridY = WorldToVirtualGridPos(playerPos.X, playerPos.Y, pR.WorldToVirtualGridRatio) break } @@ -1240,15 +1240,19 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF currPlayerDownsync := currRenderFrame.Players[playerId] encodedInput := inputList[joinIndex-1] decodedInput := DIRECTION_DECODER[encodedInput] - newVx := (currPlayerDownsync.VirtualGridX + (decodedInput[0] + decodedInput[0]*currPlayerDownsync.Speed)) - newVy := (currPlayerDownsync.VirtualGridY + (decodedInput[1] + decodedInput[1]*currPlayerDownsync.Speed)) + proposedVirtualGridDx, proposedVirtualGridDy := (decodedInput[0] + decodedInput[0]*currPlayerDownsync.Speed), (decodedInput[1] + decodedInput[1]*currPlayerDownsync.Speed) + newVx, newVy := (currPlayerDownsync.VirtualGridX + proposedVirtualGridDx), (currPlayerDownsync.VirtualGridY + proposedVirtualGridDy) // Reset playerCollider position from the "virtual grid position" collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex playerCollider := collisionSysMap[collisionPlayerIndex] - playerCollider.X, playerCollider.Y = pR.virtualGridToPlayerColliderPos(newVx, newVy, player) + playerCollider.X, playerCollider.Y = VirtualGridToPolygonColliderAnchorPos(newVx, newVy, player.ColliderRadius, player.ColliderRadius, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, pR.VirtualGridToWorldRatio) // Update in the collision system playerCollider.Update() + + if 0 < encodedInput { + Logger.Debug(fmt.Sprintf("Moved playerId=%v: virtual (%d, %d) -> (%d, %d), now playerCollider at (%.2f, %.2f)", playerId, currPlayerDownsync.VirtualGridX, currPlayerDownsync.VirtualGridY, newVx, newVy, playerCollider.X, playerCollider.Y)) + } } // handle pushbacks upon collision after all movements treated as simultaneous @@ -1256,17 +1260,17 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF joinIndex := player.JoinIndex collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex playerCollider := collisionSysMap[collisionPlayerIndex] - oldDx, oldDy := float64(0), float64(0) - if collision := playerCollider.Check(oldDx, oldDy); collision != nil { + if collision := playerCollider.Check(0, 0); collision != nil { playerShape := playerCollider.Shape.(*resolv.ConvexPolygon) + Logger.Warn(fmt.Sprintf("Collided: a=%v", ConvexPolygonStr(playerShape))) for _, obj := range collision.Objects { barrierShape := obj.Shape.(*resolv.ConvexPolygon) - if overlapped, pushbackX, pushbackY, _ := CalcPushbacks(oldDx, oldDy, playerShape, barrierShape); overlapped { - Logger.Debug(fmt.Sprintf("Collided & overlapped: player.X=%v, player.Y=%v, oldDx=%v, oldDy=%v, playerShape=%v, toCheckBarrier=%v, pushbackX=%v, pushbackY=%v", playerCollider.X, playerCollider.Y, oldDx, oldDy, ConvexPolygonStr(playerShape), ConvexPolygonStr(barrierShape), pushbackX, pushbackY)) + if overlapped, pushbackX, pushbackY, overlapResult := CalcPushbacks(0, 0, playerShape, barrierShape); overlapped { + Logger.Warn(fmt.Sprintf("Overlapped: a=%v, b=%v, pushbackX=%v, pushbackY=%v", ConvexPolygonStr(playerShape), ConvexPolygonStr(barrierShape), pushbackX, pushbackY)) effPushbacks[joinIndex-1].X += pushbackX effPushbacks[joinIndex-1].Y += pushbackY } else { - Logger.Debug(fmt.Sprintf("Collided BUT not overlapped: player.X=%v, player.Y=%v, oldDx=%v, oldDy=%v, playerShape=%v, toCheckBarrier=%v", playerCollider.X, playerCollider.Y, oldDx, oldDy, ConvexPolygonStr(playerShape), ConvexPolygonStr(barrierShape))) + Logger.Warn(fmt.Sprintf("Collided BUT not overlapped: a=%v, b=%v, overlapResult=%v", ConvexPolygonStr(playerShape), ConvexPolygonStr(barrierShape), overlapResult)) } } } @@ -1278,7 +1282,7 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF playerCollider := collisionSysMap[collisionPlayerIndex] // Update "virtual grid position" - newVx, newVy := pR.playerColliderAnchorToVirtualGridPos(playerCollider.X-effPushbacks[joinIndex-1].X, playerCollider.Y-effPushbacks[joinIndex-1].Y, player) + newVx, newVy := PolygonColliderAnchorToVirtualGridPos(playerCollider.X-effPushbacks[joinIndex-1].X, playerCollider.Y-effPushbacks[joinIndex-1].Y, player.ColliderRadius, player.ColliderRadius, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, pR.WorldToVirtualGridRatio) nextRenderFramePlayers[playerId].VirtualGridX = newVx nextRenderFramePlayers[playerId].VirtualGridY = newVy } @@ -1296,10 +1300,10 @@ func (pR *Room) inputFrameIdDebuggable(inputFrameId int32) bool { func (pR *Room) refreshColliders(spaceW, spaceH int32) { // Kindly note that by now, we've already got all the shapes in the tmx file into "pR.(Players | Barriers)" from "ParseTmxLayersAndGroups" - minStep := int(pR.PlayerDefaultSpeed) // the approx minimum distance a player can move per frame in world coordinate - space := resolv.NewSpace(int(spaceW), int(spaceH), minStep, minStep) // allocate a new collision space everytime after a battle is settled + minStep := (int(float64(pR.PlayerDefaultSpeed)*pR.VirtualGridToWorldRatio) << 2) // the approx minimum distance a player can move per frame in world coordinate + space := resolv.NewSpace(int(spaceW), int(spaceH), minStep, minStep) // allocate a new collision space everytime after a battle is settled for _, player := range pR.Players { - wx, wy := pR.virtualGridToWorldPos(player.VirtualGridX, player.VirtualGridY) + wx, wy := VirtualGridToWorldPos(player.VirtualGridX, player.VirtualGridY, pR.VirtualGridToWorldRatio) playerCollider := GenerateRectCollider(wx, wy, player.ColliderRadius*2, player.ColliderRadius*2, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, "Player") space.Add(playerCollider) // Keep track of the collider in "pR.CollisionSysMap" @@ -1319,37 +1323,3 @@ func (pR *Room) refreshColliders(spaceW, spaceH int32) { func (pR *Room) printBarrier(barrierCollider *resolv.Object) { Logger.Info(fmt.Sprintf("Barrier in roomId=%v: w=%v, h=%v, shape=%v", pR.Id, barrierCollider.W, barrierCollider.H, barrierCollider.Shape)) } - -func (pR *Room) worldToVirtualGridPos(wx, wy float64) (int32, int32) { - // [WARNING] Introduces loss of precision! - // In JavaScript floating numbers suffer from seemingly non-deterministic arithmetics, and even if certain libs solved this issue by approaches such as fixed-point-number, they might not be used in other libs -- e.g. the "collision libs" we're interested in -- thus couldn't kill all pains. - var virtualGridX int32 = int32(math.Round(wx * pR.WorldToVirtualGridRatio)) - var virtualGridY int32 = int32(math.Round(wy * pR.WorldToVirtualGridRatio)) - return virtualGridX, virtualGridY -} - -func (pR *Room) virtualGridToWorldPos(vx, vy int32) (float64, float64) { - // No loss of precision - var wx float64 = float64(vx) * pR.VirtualGridToWorldRatio - var wy float64 = float64(vy) * pR.VirtualGridToWorldRatio - return wx, wy -} - -func (pR *Room) playerWorldToCollisionPos(wx, wy float64, player *Player) (float64, float64) { - // TODO: remove this duplicate code w.r.t. "dnmshared/resolv_helper.go" - return wx - player.ColliderRadius + pR.collisionSpaceOffsetX, wy - player.ColliderRadius + pR.collisionSpaceOffsetY -} - -func (pR *Room) playerColliderAnchorToWorldPos(cx, cy float64, player *Player) (float64, float64) { - return cx + player.ColliderRadius - pR.collisionSpaceOffsetX, cy + player.ColliderRadius - pR.collisionSpaceOffsetY -} - -func (pR *Room) playerColliderAnchorToVirtualGridPos(cx, cy float64, player *Player) (int32, int32) { - wx, wy := pR.playerColliderAnchorToWorldPos(cx, cy, player) - return pR.worldToVirtualGridPos(wx, wy) -} - -func (pR *Room) virtualGridToPlayerColliderPos(vx, vy int32, player *Player) (float64, float64) { - wx, wy := pR.virtualGridToWorldPos(vx, vy) - return pR.playerWorldToCollisionPos(wx, wy, player) -} diff --git a/collider_visualizer/worldColliderDisplay.go b/collider_visualizer/worldColliderDisplay.go index 9064e91..a89a150 100644 --- a/collider_visualizer/worldColliderDisplay.go +++ b/collider_visualizer/worldColliderDisplay.go @@ -33,14 +33,15 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi spaceOffsetX := float64(spaceW) * 0.5 spaceOffsetY := float64(spaceH) * 0.5 - playerDefaultSpeed := int32(10) - minStep := int(playerDefaultSpeed) - playerColliderRadius := float64(12) + virtualGridToWorldRatio := 0.1 + playerDefaultSpeed := 20 + minStep := (int(float64(playerDefaultSpeed)*virtualGridToWorldRatio) << 2) + playerColliderRadius := float64(24) playerColliders := make([]*resolv.Object, len(playerPosList.Eles)) space := resolv.NewSpace(int(spaceW), int(spaceH), minStep, minStep) for i, playerPos := range playerPosList.Eles { playerCollider := GenerateRectCollider(playerPos.X, playerPos.Y, playerColliderRadius*2, playerColliderRadius*2, spaceOffsetX, spaceOffsetY, "Player") // [WARNING] Deliberately not using a circle because "resolv v0.5.1" doesn't yet align circle center with space cell center, regardless of the "specified within-object offset" - Logger.Info(fmt.Sprintf("Player Collider#%d: playerPos.X=%v, playerPos.Y=%v, radius=%v, spaceOffsetX=%v, spaceOffsetY=%v, shape=%v", i, playerPos.X, playerPos.Y, playerColliderRadius, spaceOffsetX, spaceOffsetY, playerCollider.Shape)) + Logger.Info(fmt.Sprintf("Player Collider#%d: player world pos =(%.2f, %.2f), shape=%v", i, playerPos.X, playerPos.Y, ConvexPolygonStr(playerCollider.Shape.(*resolv.ConvexPolygon)))) playerColliders[i] = playerCollider space.Add(playerCollider) } @@ -48,7 +49,7 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi barrierLocalId := 0 for _, barrierUnaligned := range barrierList.Eles { barrierCollider := GenerateConvexPolygonCollider(barrierUnaligned, spaceOffsetX, spaceOffsetY, "Barrier") - Logger.Info(fmt.Sprintf("Added barrier: shape=%v", barrierCollider.Shape)) + Logger.Info(fmt.Sprintf("Added barrier: shape=%v", ConvexPolygonStr(barrierCollider.Shape.(*resolv.ConvexPolygon)))) space.Add(barrierCollider) barrierLocalId++ } @@ -57,22 +58,22 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi moveToCollide := true if moveToCollide { + proposedDx, proposedDy := -50.0, -60.0 effPushback := Vec2D{X: float64(0), Y: float64(0)} toTestPlayerCollider := playerColliders[0] - toTestPlayerCollider.X += -50.0 - toTestPlayerCollider.Y += -60.0 + toTestPlayerCollider.X += proposedDx + toTestPlayerCollider.Y += proposedDy toTestPlayerCollider.Update() - oldDx, oldDy := float64(0), float64(0) - if collision := toTestPlayerCollider.Check(oldDx, oldDy); collision != nil { + if collision := toTestPlayerCollider.Check(0, 0); collision != nil { playerShape := toTestPlayerCollider.Shape.(*resolv.ConvexPolygon) for _, obj := range collision.Objects { barrierShape := obj.Shape.(*resolv.ConvexPolygon) - if overlapped, pushbackX, pushbackY, overlapResult := CalcPushbacks(oldDx, oldDy, playerShape, barrierShape); overlapped { - Logger.Info(fmt.Sprintf("Overlapped: a=%v, b=%v, pushbackX=%v, pushbackY=%v", ConvexPolygonStr(playerShape), ConvexPolygonStr(barrierShape), pushbackX, pushbackY)) + if overlapped, pushbackX, pushbackY, overlapResult := CalcPushbacks(0, 0, playerShape, barrierShape); overlapped { + Logger.Warn(fmt.Sprintf("Overlapped: a=%v, b=%v, pushbackX=%v, pushbackY=%v", ConvexPolygonStr(playerShape), ConvexPolygonStr(barrierShape), pushbackX, pushbackY)) effPushback.X += pushbackX effPushback.Y += pushbackY } else { - Logger.Info(fmt.Sprintf("Collided BUT not overlapped: a=%v, b=%v, overlapResult=%v", ConvexPolygonStr(playerShape), ConvexPolygonStr(barrierShape), overlapResult)) + Logger.Warn(fmt.Sprintf("Collided BUT not overlapped: a=%v, b=%v, overlapResult=%v", ConvexPolygonStr(playerShape), ConvexPolygonStr(barrierShape), overlapResult)) } } toTestPlayerCollider.X -= effPushback.X diff --git a/dnmshared/resolv_helper.go b/dnmshared/resolv_helper.go index afe38c5..306d654 100644 --- a/dnmshared/resolv_helper.go +++ b/dnmshared/resolv_helper.go @@ -12,14 +12,15 @@ import ( func ConvexPolygonStr(body *resolv.ConvexPolygon) string { var s []string = make([]string, len(body.Points)) for i, p := range body.Points { - s[i] = fmt.Sprintf("[%v, %v]", p[0]+body.X, p[1]+body.Y) + s[i] = fmt.Sprintf("[%.2f, %.2f]", p[0]+body.X, p[1]+body.Y) } - return fmt.Sprintf("[%s]", strings.Join(s, ", ")) + return fmt.Sprintf("{\n%s\n}", strings.Join(s, ",\n")) } func GenerateRectCollider(origX, origY, w, h, spaceOffsetX, spaceOffsetY float64, tag string) *resolv.Object { - collider := resolv.NewObject(origX-w*0.5+spaceOffsetX, origY-h*0.5+spaceOffsetY, w, h, tag) + cx, cy := WorldToPolygonColliderAnchorPos(origX, origY, w*0.5, h*0.5, spaceOffsetX, spaceOffsetY) + collider := resolv.NewObject(cx, cy, w, h, tag) shape := resolv.NewRectangle(0, 0, w, h) collider.SetShape(shape) return collider @@ -219,3 +220,36 @@ func isPolygonPairSeparatedByDir(a, b *resolv.ConvexPolygon, e vector.Vector, re // the specified unit vector "e" doesn't separate "a" and "b", overlap result is generated return false } + +func WorldToVirtualGridPos(wx, wy, worldToVirtualGridRatio float64) (int32, int32) { + // [WARNING] Introduces loss of precision! + // In JavaScript floating numbers suffer from seemingly non-deterministic arithmetics, and even if certain libs solved this issue by approaches such as fixed-point-number, they might not be used in other libs -- e.g. the "collision libs" we're interested in -- thus couldn't kill all pains. + var virtualGridX int32 = int32(math.Round(wx * worldToVirtualGridRatio)) + var virtualGridY int32 = int32(math.Round(wy * worldToVirtualGridRatio)) + return virtualGridX, virtualGridY +} + +func VirtualGridToWorldPos(vx, vy int32, virtualGridToWorldRatio float64) (float64, float64) { + // No loss of precision + var wx float64 = float64(vx) * virtualGridToWorldRatio + var wy float64 = float64(vy) * virtualGridToWorldRatio + return wx, wy +} + +func WorldToPolygonColliderAnchorPos(wx, wy, halfBoundingW, halfBoundingH, collisionSpaceOffsetX, collisionSpaceOffsetY float64) (float64, float64) { + return wx - halfBoundingW + collisionSpaceOffsetX, wy - halfBoundingH + collisionSpaceOffsetY +} + +func PolygonColliderAnchorToWorldPos(cx, cy, halfBoundingW, halfBoundingH, collisionSpaceOffsetX, collisionSpaceOffsetY float64) (float64, float64) { + return cx + halfBoundingW - collisionSpaceOffsetX, cy + halfBoundingH - collisionSpaceOffsetY +} + +func PolygonColliderAnchorToVirtualGridPos(cx, cy, halfBoundingW, halfBoundingH, collisionSpaceOffsetX, collisionSpaceOffsetY float64, worldToVirtualGridRatio float64) (int32, int32) { + wx, wy := PolygonColliderAnchorToWorldPos(cx, cy, halfBoundingW, halfBoundingH, collisionSpaceOffsetX, collisionSpaceOffsetY) + return WorldToVirtualGridPos(wx, wy, worldToVirtualGridRatio) +} + +func VirtualGridToPolygonColliderAnchorPos(vx, vy int32, halfBoundingW, halfBoundingH, collisionSpaceOffsetX, collisionSpaceOffsetY float64, virtualGridToWorldRatio float64) (float64, float64) { + wx, wy := VirtualGridToWorldPos(vx, vy, virtualGridToWorldRatio) + return WorldToPolygonColliderAnchorPos(wx, wy, halfBoundingW, halfBoundingH, collisionSpaceOffsetX, collisionSpaceOffsetY) +} diff --git a/frontend/assets/resources/map/simple/map.tmx b/frontend/assets/resources/map/simple/map.tmx index 16b49c2..7f28144 100644 --- a/frontend/assets/resources/map/simple/map.tmx +++ b/frontend/assets/resources/map/simple/map.tmx @@ -17,7 +17,7 @@ - eJztwQENAAAAwqD3T20ON6AAAAAAAAAAAADg3wAnEAAB + eJzt1jEKgDAQRNE0GtD739fGaQIhqJHdCf81aSz2oyspBQAAAADWcUYPMIEaaugU37TvwbGl9y05tYz2wWFfaMiBhhyNKzRs99n7lzo0SG1OcWqQtsWxQdSwD57L3CCjO4dDg7zd+Yye7nxmajlCp5jD6Y4OAAAA4H8XE6wBrA== diff --git a/frontend/assets/resources/prefabs/Pacman1.prefab b/frontend/assets/resources/prefabs/Pacman1.prefab index 7d5723c..bf52f5a 100644 --- a/frontend/assets/resources/prefabs/Pacman1.prefab +++ b/frontend/assets/resources/prefabs/Pacman1.prefab @@ -100,7 +100,7 @@ "__id__": 1 }, "_children": [], - "_active": false, + "_active": true, "_components": [ { "__id__": 3 @@ -119,8 +119,8 @@ }, "_contentSize": { "__type__": "cc.Size", - "width": 93.36, - "height": 40 + "width": 46.68, + "height": 27.72 }, "_anchorPoint": { "__type__": "cc.Vec2", @@ -132,7 +132,7 @@ "ctor": "Float64Array", "array": [ -5, - 101, + 50, 0, 0, 0, @@ -164,12 +164,16 @@ "__id__": 2 }, "_enabled": true, - "_materials": [], + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], "_useOriginalSize": false, "_string": "(0, 0)", "_N$string": "(0, 0)", - "_fontSize": 40, - "_lineHeight": 40, + "_fontSize": 20, + "_lineHeight": 22, "_enableWrapText": true, "_N$file": null, "_isSystemFontUsed": true, @@ -557,15 +561,13 @@ }, "_enabled": true, "animComp": null, - "baseSpeed": 50, - "speed": 50, "lastMovedAt": 0, - "eps": 0.1, - "magicLeanLowerBound": 0.414, - "magicLeanUpperBound": 2.414, "arrowTipNode": { "__id__": 8 }, + "coordLabel": { + "__id__": 3 + }, "_id": "" }, { diff --git a/frontend/assets/resources/prefabs/Pacman2.prefab b/frontend/assets/resources/prefabs/Pacman2.prefab index cc5b6c8..b6d4472 100644 --- a/frontend/assets/resources/prefabs/Pacman2.prefab +++ b/frontend/assets/resources/prefabs/Pacman2.prefab @@ -100,7 +100,7 @@ "__id__": 1 }, "_children": [], - "_active": false, + "_active": true, "_components": [ { "__id__": 3 @@ -119,8 +119,8 @@ }, "_contentSize": { "__type__": "cc.Size", - "width": 93.36, - "height": 40 + "width": 46.68, + "height": 27.72 }, "_anchorPoint": { "__type__": "cc.Vec2", @@ -132,7 +132,7 @@ "ctor": "Float64Array", "array": [ -5, - 101, + 50, 0, 0, 0, @@ -164,12 +164,16 @@ "__id__": 2 }, "_enabled": true, - "_materials": [], + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], "_useOriginalSize": false, "_string": "(0, 0)", "_N$string": "(0, 0)", - "_fontSize": 40, - "_lineHeight": 40, + "_fontSize": 20, + "_lineHeight": 22, "_enableWrapText": true, "_N$file": null, "_isSystemFontUsed": true, @@ -557,15 +561,13 @@ }, "_enabled": true, "animComp": null, - "baseSpeed": 50, - "speed": 50, "lastMovedAt": 0, - "eps": 0.1, - "magicLeanLowerBound": 0.414, - "magicLeanUpperBound": 2.414, "arrowTipNode": { "__id__": 8 }, + "coordLabel": { + "__id__": 3 + }, "_id": "" }, { diff --git a/frontend/assets/scripts/BasePlayer.js b/frontend/assets/scripts/BasePlayer.js index 8f1b5ea..bded266 100644 --- a/frontend/assets/scripts/BasePlayer.js +++ b/frontend/assets/scripts/BasePlayer.js @@ -6,30 +6,10 @@ module.export = cc.Class({ type: cc.Animation, default: null, }, - baseSpeed: { - type: cc.Float, - default: 50, - }, - speed: { - type: cc.Float, - default: 50 - }, lastMovedAt: { type: cc.Float, default: 0 // In "GMT milliseconds" - }, - eps: { - default: 0.10, - type: cc.Float - }, - magicLeanLowerBound: { - default: 0.414, // Tangent of (PI/8). - type: cc.Float - }, - magicLeanUpperBound: { - default: 2.414, // Tangent of (3*PI/8). - type: cc.Float - }, + } }, // LIFE-CYCLE CALLBACKS: @@ -70,7 +50,7 @@ module.export = cc.Class({ this.activeDirection = newScheduledDirection; this.activeDirection = newScheduledDirection; const clipKey = newScheduledDirection.dx.toString() + newScheduledDirection.dy.toString(); - const clips = (this.attacked ? this.attackedClips : this.clips); + const clips = (this.attacked ? this.attackedClips : this.clips); let clip = clips[clipKey]; if (!clip) { // Keep playing the current anim. @@ -86,11 +66,9 @@ module.export = cc.Class({ } }, - update(dt) { - }, + update(dt) {}, - lateUpdate(dt) { - }, + lateUpdate(dt) {}, _generateRandomDirection() { return ALL_DISCRETE_DIRECTIONS_CLOCKWISE[Math.floor(Math.random() * ALL_DISCRETE_DIRECTIONS_CLOCKWISE.length)]; @@ -117,16 +95,16 @@ module.export = cc.Class({ updateSpeed(proposedSpeed) { if (0 == proposedSpeed && 0 < this.speed) { - this.startFrozenDisplay(); - } + this.startFrozenDisplay(); + } if (0 < proposedSpeed && 0 == this.speed) { - this.stopFrozenDisplay(); - } - this.speed = proposedSpeed; + this.stopFrozenDisplay(); + } + this.speed = proposedSpeed; }, startFrozenDisplay() { - const self = this; + const self = this; self.attacked = true; }, diff --git a/frontend/assets/scripts/Map.js b/frontend/assets/scripts/Map.js index 65e15de..f195b07 100644 --- a/frontend/assets/scripts/Map.js +++ b/frontend/assets/scripts/Map.js @@ -352,6 +352,8 @@ cc.Class({ window.mapIns = self; window.forceBigEndianFloatingNumDecoding = self.forceBigEndianFloatingNumDecoding; + self.showCriticalCoordinateLabels = true; + console.warn("+++++++ Map onLoad()"); window.handleClientSessionError = function() { console.warn('+++++++ Common handleClientSessionError()'); @@ -473,9 +475,36 @@ cc.Class({ const x0 = boundaryObj[0].x, y0 = boundaryObj[0].y; let pts = []; - // TODO: Simplify this redundant coordinate conversion within "extractBoundaryObjects", but since this routine is only called once per battle, not urgent. for (let i = 0; i < boundaryObj.length; ++i) { - pts.push([boundaryObj[i].x - x0, boundaryObj[i].y - y0]); + const dx = boundaryObj[i].x - x0; + const dy = boundaryObj[i].y - y0; + pts.push([dx, dy]); + if (self.showCriticalCoordinateLabels) { + 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; + } + barrierVertLabelNode.setPosition(cc.v2(x0+0.95*dx, y0+0.5*dy)); + const barrierVertLabel = barrierVertLabelNode.addComponent(cc.Label); + barrierVertLabel.fontSize = 20; + barrierVertLabel.lineHeight = 22; + barrierVertLabel.string = `(${boundaryObj[i].x.toFixed(1)}, ${boundaryObj[i].y.toFixed(1)})`; + safelyAddChild(self.node, barrierVertLabelNode); + setLocalZOrder(barrierVertLabelNode, 5); + + barrierVertLabelNode.active = true; + } } const newBarrier = self.collisionSys.createPolygon(x0, y0, pts); // console.log("Created barrier: ", newBarrier); diff --git a/frontend/assets/scripts/SelfPlayer.js b/frontend/assets/scripts/SelfPlayer.js index 9025a24..33ab8cf 100644 --- a/frontend/assets/scripts/SelfPlayer.js +++ b/frontend/assets/scripts/SelfPlayer.js @@ -1,4 +1,4 @@ -const BasePlayer = require("./BasePlayer"); +const BasePlayer = require("./BasePlayer"); cc.Class({ extends: BasePlayer, @@ -7,6 +7,10 @@ cc.Class({ arrowTipNode: { type: cc.Node, default: null + }, + coordLabel: { + type: cc.Label, + default: null } }, start() { @@ -34,7 +38,7 @@ cc.Class({ return; } self.arrowTipNode.active = true; - window.setTimeout(function(){ + window.setTimeout(function() { if (null == self.arrowTipNode) { return; } @@ -44,6 +48,9 @@ cc.Class({ update(dt) { BasePlayer.prototype.update.call(this, dt); + if (this.mapIns.showCriticalCoordinateLabels) { + this.coordLabel.string = `(${this.node.x.toFixed(2)}, ${this.node.y.toFixed(2)})`; + } }, }); diff --git a/frontend/assets/scripts/TileCollisionManagerSingleton.js b/frontend/assets/scripts/TileCollisionManagerSingleton.js index 560f38a..e8181a0 100644 --- a/frontend/assets/scripts/TileCollisionManagerSingleton.js +++ b/frontend/assets/scripts/TileCollisionManagerSingleton.js @@ -371,8 +371,8 @@ TileCollisionManager.prototype.extractBoundaryObjects = function (withTiledMapNo const tilesElListUnderTilesets = {}; for (let tsxFilenameIdx = 0; tsxFilenameIdx < tsxFileNames.length; ++tsxFilenameIdx) { const tsxOrientation = tileSets[tsxFilenameIdx].orientation; - if (cc.TiledMap.Orientation.ORTHO != tsxOrientation) { - cc.error("Error at tileset %s: We proceed with ONLY tilesets in ORTHO orientation for all map orientations by now.", tsxFileNames[tsxFilenameIdx]); + if (cc.TiledMap.Orientation.ORTHO == tsxOrientation) { + cc.error("Error at tileset %s: We don't proceed with tilesets in ORTHO orientation by now.", tsxFileNames[tsxFilenameIdx]); continue; };