diff --git a/battle_srv/models/room.go b/battle_srv/models/room.go
index 35c9df1..c7b3353 100644
--- a/battle_srv/models/room.go
+++ b/battle_srv/models/room.go
@@ -435,24 +435,6 @@ func (pR *Room) StartBattle() {
return
}
- if 0 == pR.RenderFrameId {
- for _, player := range pR.PlayersArr {
- playerId := player.Id
- thatPlayerBattleState := atomic.LoadInt32(&(player.BattleState)) // Might be changed in "OnPlayerDisconnected/OnPlayerLost" from other threads
- // [WARNING] DON'T try to send any message to an inactive player!
- switch thatPlayerBattleState {
- case PlayerBattleStateIns.DISCONNECTED:
- case PlayerBattleStateIns.LOST:
- case PlayerBattleStateIns.EXPELLED_DURING_GAME:
- case PlayerBattleStateIns.EXPELLED_IN_DISMISSAL:
- continue
- }
- kickoffFrame := pR.RenderFrameBuffer.GetByFrameId(0).(*RoomDownsyncFrame)
- pR.sendSafely(kickoffFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_START, playerId, true)
- }
- Logger.Info(fmt.Sprintf("In `battleMainLoop` for roomId=%v sent out kickoffFrame", pR.Id))
- }
-
/*
[WARNING]
Golang "time.Sleep" is known to be taking longer than specified time to wake up at millisecond granularity, as discussed in https://github.com/golang/go/issues/44343
@@ -462,6 +444,24 @@ func (pR *Room) StartBattle() {
nextRenderFrameId := int32((totalElapsedNanos + pR.dilutedRollbackEstimatedDtNanos - 1) / pR.dilutedRollbackEstimatedDtNanos) // fast ceiling
toSleepNanos := int64(0)
if nextRenderFrameId > pR.RenderFrameId {
+ if 0 == pR.RenderFrameId {
+ // It's important to send kickoff frame iff "0 == pR.RenderFrameId && nextRenderFrameId > pR.RenderFrameId", otherwise it might send duplicate kickoff frames
+ for _, player := range pR.PlayersArr {
+ playerId := player.Id
+ thatPlayerBattleState := atomic.LoadInt32(&(player.BattleState)) // Might be changed in "OnPlayerDisconnected/OnPlayerLost" from other threads
+ // [WARNING] DON'T try to send any message to an inactive player!
+ switch thatPlayerBattleState {
+ case PlayerBattleStateIns.DISCONNECTED:
+ case PlayerBattleStateIns.LOST:
+ case PlayerBattleStateIns.EXPELLED_DURING_GAME:
+ case PlayerBattleStateIns.EXPELLED_IN_DISMISSAL:
+ continue
+ }
+ kickoffFrame := pR.RenderFrameBuffer.GetByFrameId(0).(*RoomDownsyncFrame)
+ pR.sendSafely(kickoffFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_START, playerId, true)
+ }
+ Logger.Info(fmt.Sprintf("In `battleMainLoop` for roomId=%v sent out kickoffFrame", pR.Id))
+ }
prevRenderFrameId := pR.RenderFrameId
pR.RenderFrameId = nextRenderFrameId
@@ -754,7 +754,7 @@ func (pR *Room) OnDismissed() {
pR.RollbackEstimatedDtNanos = 16666666 // A little smaller than the actual per frame time, just for logging FAST FRAME
dilutedServerFps := float64(55.0)
pR.dilutedRollbackEstimatedDtNanos = int64(float64(pR.RollbackEstimatedDtNanos) * float64(pR.ServerFps) / dilutedServerFps)
- pR.BattleDurationFrames = 30 * pR.ServerFps
+ pR.BattleDurationFrames = 60 * pR.ServerFps
pR.BattleDurationNanos = int64(pR.BattleDurationFrames) * (pR.RollbackEstimatedDtNanos + 1)
pR.InputFrameUpsyncDelayTolerance = 2
pR.MaxChasingRenderFramesPerUpdate = 8
@@ -1307,8 +1307,6 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF
}
nextRenderFrameMeleeBullets := make([]*MeleeBullet, 0, len(currRenderFrame.MeleeBullets)) // Is there any better way to reduce malloc/free impact, e.g. smart prediction for fixed memory allocation?
-
- // Guaranteed determinism regardless of traversal order
effPushbacks := make([]Vec2D, pR.Capacity)
hardPushbackNorms := make([][]Vec2D, pR.Capacity)
@@ -1346,7 +1344,9 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF
}
if !characStateAlreadyInAir && characStateIsInterruptWaivable {
thatPlayerInNextFrame.VelY = pR.JumpingInitVelY
- Logger.Info(fmt.Sprintf("playerId=%v, joinIndex=%v triggered a jump at renderFrame.id=%v, delayedInputFrame.id=%v, nextVelY=%v", playerId, joinIndex, currRenderFrame.Id, delayedInputFrame.InputFrameId, thatPlayerInNextFrame.VelY))
+ if 1 == currPlayerDownsync.JoinIndex {
+ Logger.Info(fmt.Sprintf("playerId=%v, joinIndex=%v jumped at {renderFrame.id: %d, virtualX: %d, virtualY: %d, nextVelX: %d, nextVelY: %d}, delayedInputFrame.id=%d", playerId, joinIndex, currRenderFrame.Id, currPlayerDownsync.VirtualGridX, currPlayerDownsync.VirtualGridY, thatPlayerInNextFrame.VelX, thatPlayerInNextFrame.VelY, delayedInputFrame.InputFrameId))
+ }
}
}
@@ -1375,8 +1375,8 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF
if 0 != decodedInput.Dx || 0 != decodedInput.Dy {
thatPlayerInNextFrame.DirX = decodedInput.Dx
thatPlayerInNextFrame.DirY = decodedInput.Dy
- thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_WALKING
thatPlayerInNextFrame.VelX = decodedInput.Dx * currPlayerDownsync.Speed
+ thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_WALKING
} else {
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_IDLE1
thatPlayerInNextFrame.VelX = 0
@@ -1389,6 +1389,7 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF
for _, player := range pR.PlayersArr {
playerId := player.Id
joinIndex := player.JoinIndex
+ effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y = float64(0), float64(0)
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
playerCollider := collisionSysMap[collisionPlayerIndex]
currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
@@ -1448,67 +1449,77 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF
currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
fallStopping := false
possiblyFallStoppedOnAnotherPlayer := false
- if collision := playerCollider.Check(0, 0); collision != nil {
- for _, obj := range collision.Objects {
- isBarrier, isAnotherPlayer, isBullet := false, false, false
- switch obj.Data.(type) {
- case *Barrier:
- isBarrier = true
- case *Player:
- isAnotherPlayer = true
- case *MeleeBullet:
- isBullet = true
- }
- if isBullet {
- // ignore bullets for this step
- continue
- }
- bShape := obj.Shape.(*resolv.ConvexPolygon)
- if overlapped, pushbackX, pushbackY, overlapResult := CalcPushbacks(0, 0, playerShape, bShape); overlapped {
- normAlignmentWithGravity := (overlapResult.OverlapX*float64(0) + overlapResult.OverlapY*float64(-1.0))
- landedOnGravityPushback := (pR.SnapIntoPlatformThreshold < normAlignmentWithGravity) // prevents false snapping on the lateral sides
- if landedOnGravityPushback {
- // kindly note that one player might land on top of another player, and snapping is also required in such case
- pushbackX, pushbackY = (overlapResult.Overlap-pR.SnapIntoPlatformOverlap)*overlapResult.OverlapX, (overlapResult.Overlap-pR.SnapIntoPlatformOverlap)*overlapResult.OverlapY
- thatPlayerInNextFrame.InAir = false
- }
- for _, hardPushbackNorm := range hardPushbackNorms[joinIndex-1] {
- projectedMagnitude := pushbackX*hardPushbackNorm.X + pushbackY*hardPushbackNorm.Y
- if isBarrier || (0 > projectedMagnitude && isAnotherPlayer) {
- pushbackX -= projectedMagnitude * hardPushbackNorm.X
- pushbackY -= projectedMagnitude * hardPushbackNorm.Y
- }
- }
- if currPlayerDownsync.InAir && landedOnGravityPushback {
- fallStopping = true
- if isAnotherPlayer {
- possiblyFallStoppedOnAnotherPlayer = true
- }
- }
- effPushbacks[joinIndex-1].X += pushbackX
- effPushbacks[joinIndex-1].Y += pushbackY
+ collision := playerCollider.Check(0, 0)
+ if nil == collision {
+ continue
+ }
+ for _, obj := range collision.Objects {
+ isBarrier, isAnotherPlayer, isBullet := false, false, false
+ switch obj.Data.(type) {
+ case *Barrier:
+ isBarrier = true
+ case *Player:
+ isAnotherPlayer = true
+ case *MeleeBullet:
+ isBullet = true
+ }
+ if isBullet {
+ // ignore bullets for this step
+ continue
+ }
+ bShape := obj.Shape.(*resolv.ConvexPolygon)
+ overlapped, pushbackX, pushbackY, overlapResult := CalcPushbacks(0, 0, playerShape, bShape)
+ if !overlapped {
+ continue
+ }
+ normAlignmentWithGravity := (overlapResult.OverlapX*float64(0) + overlapResult.OverlapY*float64(-1.0))
+ landedOnGravityPushback := (pR.SnapIntoPlatformThreshold < normAlignmentWithGravity) // prevents false snapping on the lateral sides
+ if landedOnGravityPushback {
+ // kindly note that one player might land on top of another player, and snapping is also required in such case
+ pushbackX, pushbackY = (overlapResult.Overlap-pR.SnapIntoPlatformOverlap)*overlapResult.OverlapX, (overlapResult.Overlap-pR.SnapIntoPlatformOverlap)*overlapResult.OverlapY
+ thatPlayerInNextFrame.InAir = false
+ }
+ for _, hardPushbackNorm := range hardPushbackNorms[joinIndex-1] {
+ projectedMagnitude := pushbackX*hardPushbackNorm.X + pushbackY*hardPushbackNorm.Y
+ if isBarrier || (isAnotherPlayer && 0 > projectedMagnitude) {
+ pushbackX -= projectedMagnitude * hardPushbackNorm.X
+ pushbackY -= projectedMagnitude * hardPushbackNorm.Y
}
}
- if fallStopping {
- thatPlayerInNextFrame.VelX = 0
- thatPlayerInNextFrame.VelY = 0
- thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_IDLE1
- thatPlayerInNextFrame.FramesToRecover = 0
- if possiblyFallStoppedOnAnotherPlayer {
- Logger.Info(fmt.Sprintf("playerId=%d, joinIndex=%d possiblyFallStoppedOnAnotherPlayer with effPushback={%.2f, %.2f} at renderFrame.id=%d", playerId, joinIndex, effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y, currRenderFrame.Id))
+ effPushbacks[joinIndex-1].X += pushbackX
+ effPushbacks[joinIndex-1].Y += pushbackY
+ if currPlayerDownsync.InAir && landedOnGravityPushback {
+ fallStopping = true
+ if isAnotherPlayer {
+ possiblyFallStoppedOnAnotherPlayer = true
+ }
+ if 1 == thatPlayerInNextFrame.JoinIndex {
+ Logger.Info(fmt.Sprintf("playerId=%d, joinIndex=%d fallStopping#1 at {renderFrame.id: %d, virtualX: %d, virtualY: %d, velX: %d, velY: %d} with effPushback={%.3f, %.3f}, overlapMag=%.4f, possiblyFallStoppedOnAnotherPlayer=%v", playerId, joinIndex, currRenderFrame.Id, currPlayerDownsync.VirtualGridX, currPlayerDownsync.VirtualGridY, currPlayerDownsync.VelX, currPlayerDownsync.VelY, effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y, overlapResult.Overlap, possiblyFallStoppedOnAnotherPlayer))
}
}
- if currPlayerDownsync.InAir {
- switch thatPlayerInNextFrame.CharacterState {
- case ATK_CHARACTER_STATE_IDLE1:
- case ATK_CHARACTER_STATE_WALKING:
- thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_IDLE1
- case ATK_CHARACTER_STATE_ATK1:
- thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_ATK1
- case ATK_CHARACTER_STATE_ATKED1:
- thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_ATKED1
- default:
- }
+ if 1 == joinIndex && currPlayerDownsync.InAir && isBarrier && !landedOnGravityPushback {
+ Logger.Warn(fmt.Sprintf("playerId=%d, joinIndex=%d inAir & pushed back by barrier & not landed at {renderFrame.id: %d, virtualX: %d, virtualY: %d, velX: %d, velY: %d} with effPushback={%.3f, %.3f}, playerColliderPos={%.3f, %.3f}, barrierPos={%.3f, %.3f}, overlapMag=%.4f, len(hardPushbackNorms)=%d", playerId, joinIndex, currRenderFrame.Id, currPlayerDownsync.VirtualGridX, currPlayerDownsync.VirtualGridY, currPlayerDownsync.VelX, currPlayerDownsync.VelY, effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y, playerCollider.X-pR.collisionSpaceOffsetX, playerCollider.Y-pR.collisionSpaceOffsetY, bShape.X-pR.collisionSpaceOffsetX, bShape.Y-pR.collisionSpaceOffsetY, overlapResult.Overlap, len(hardPushbackNorms)))
+ }
+ if 1 == joinIndex && currPlayerDownsync.InAir && isAnotherPlayer {
+ Logger.Warn(fmt.Sprintf("playerId=%d, joinIndex=%d inAir & pushed back by another player at {renderFrame.id: %d, virtualX: %d, virtualY: %d, velX: %d, velY: %d} with effPushback={%.3f, %.3f}, landedOnGravityPushback=%v, fallStopping=%v, playerColliderPos={%.3f, %.3f}, anotherPlayerColliderPos={%.3f, %.3f}, overlapMag=%.4f, len(hardPushbackNorms)=%d", playerId, joinIndex, currRenderFrame.Id, currPlayerDownsync.VirtualGridX, currPlayerDownsync.VirtualGridY, currPlayerDownsync.VelX, currPlayerDownsync.VelY, effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y, landedOnGravityPushback, fallStopping, playerCollider.X-pR.collisionSpaceOffsetX, playerCollider.Y-pR.collisionSpaceOffsetY, bShape.X-pR.collisionSpaceOffsetX, bShape.Y-pR.collisionSpaceOffsetY, overlapResult.Overlap, len(hardPushbackNorms)))
+ }
+ }
+ if fallStopping {
+ thatPlayerInNextFrame.VelX = 0
+ thatPlayerInNextFrame.VelY = 0
+ thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_IDLE1
+ thatPlayerInNextFrame.FramesToRecover = 0
+ }
+ if currPlayerDownsync.InAir {
+ switch thatPlayerInNextFrame.CharacterState {
+ case ATK_CHARACTER_STATE_IDLE1:
+ case ATK_CHARACTER_STATE_WALKING:
+ thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_IDLE1
+ case ATK_CHARACTER_STATE_ATK1:
+ thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_ATK1
+ case ATK_CHARACTER_STATE_ATKED1:
+ thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_ATKED1
+ default:
}
}
}
@@ -1537,7 +1548,7 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF
for _, hardPushbackNorm := range hardPushbackNorms[joinIndex-1] {
projectedMagnitude := pushbackX*hardPushbackNorm.X + pushbackY*hardPushbackNorm.Y
if 0 > projectedMagnitude {
- Logger.Info(fmt.Sprintf("defenderPlayerId=%d, joinIndex=%d reducing bullet pushback={%.2f, %.2f} by {%.2f, %.2f} where hardPushbackNorm={%.2f, %.2f}, projectedMagnitude=%.2f at renderFrame.id=%d", t.Id, joinIndex, pushbackX, pushbackY, projectedMagnitude*hardPushbackNorm.X, projectedMagnitude*hardPushbackNorm.Y, hardPushbackNorm.X, hardPushbackNorm.Y, projectedMagnitude, currRenderFrame.Id))
+ Logger.Info(fmt.Sprintf("defenderPlayerId=%d, joinIndex=%d reducing bullet pushback={%.3f, %.3f} by {%.3f, %.3f} where hardPushbackNorm={%.3f, %.3f}, projectedMagnitude=%.3f at renderFrame.id=%d", t.Id, joinIndex, pushbackX, pushbackY, projectedMagnitude*hardPushbackNorm.X, projectedMagnitude*hardPushbackNorm.Y, hardPushbackNorm.X, hardPushbackNorm.Y, projectedMagnitude, currRenderFrame.Id))
pushbackX -= projectedMagnitude * hardPushbackNorm.X
pushbackY -= projectedMagnitude * hardPushbackNorm.Y
}
@@ -1587,16 +1598,29 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF
playerId := player.Id
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
playerCollider := collisionSysMap[collisionPlayerIndex]
+ playerShape := playerCollider.Shape.(*resolv.ConvexPolygon)
// Update "virtual grid position"
- thatPlayerInNextFrame := nextRenderFramePlayers[playerId]
+ currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
thatPlayerInNextFrame.VirtualGridX, thatPlayerInNextFrame.VirtualGridY = PolygonColliderAnchorToVirtualGridPos(playerCollider.X-effPushbacks[joinIndex-1].X, playerCollider.Y-effPushbacks[joinIndex-1].Y, player.ColliderRadius, player.ColliderRadius, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, pR.WorldToVirtualGridRatio)
+
+ if 1 == thatPlayerInNextFrame.JoinIndex {
+ if thatPlayerInNextFrame.InAir && (0 != thatPlayerInNextFrame.VelY) {
+ Logger.Info(fmt.Sprintf("playerId=%d, joinIndex=%d inAir trajectory: {nextRenderFrame.id: %d, nextVirtualX: %d, nextVirtualY: %d, nextVelX: %d, nextVelX: %d}, with playerColliderPos={%.3f, %.3f}, effPushback={%.3f, %.3f}", playerId, joinIndex, currRenderFrame.Id+1, thatPlayerInNextFrame.VirtualGridX, thatPlayerInNextFrame.VirtualGridY, thatPlayerInNextFrame.VelX, thatPlayerInNextFrame.VelY, playerShape.X-pR.collisionSpaceOffsetX, playerShape.Y-pR.collisionSpaceOffsetY, effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y))
+ }
+ if currPlayerDownsync.InAir && !thatPlayerInNextFrame.InAir {
+ Logger.Warn(fmt.Sprintf("playerId=%d, joinIndex=%d fallStopping#2 at {nextRenderFrame.id: %d, nextVirtualX: %d, nextVirtualY: %d, nextVelX: %d, nextVelX: %d}, with playerColliderPos={%.3f, %.3f}, effPushback={%.3f, %.3f}", playerId, joinIndex, currRenderFrame.Id+1, thatPlayerInNextFrame.VirtualGridX, thatPlayerInNextFrame.VirtualGridY, thatPlayerInNextFrame.VelX, thatPlayerInNextFrame.VelY, playerShape.X-pR.collisionSpaceOffsetX, playerShape.Y-pR.collisionSpaceOffsetY, effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y))
+ }
+ if !currPlayerDownsync.InAir && thatPlayerInNextFrame.InAir {
+ Logger.Warn(fmt.Sprintf("playerId=%d, joinIndex=%d took off at {nextRenderFrame.id: %d, nextVirtualX: %d, nextVirtualY: %d, nextVelX: %d, nextVelX: %d}, with playerColliderPos={%.3f, %.3f}, effPushback={%.3f, %.3f}", playerId, joinIndex, currRenderFrame.Id+1, thatPlayerInNextFrame.VirtualGridX, thatPlayerInNextFrame.VirtualGridY, thatPlayerInNextFrame.VelX, thatPlayerInNextFrame.VelY, playerShape.X-pR.collisionSpaceOffsetX, playerShape.Y-pR.collisionSpaceOffsetY, effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y))
+ }
+ }
}
return &RoomDownsyncFrame{
Id: currRenderFrame.Id + 1,
Players: nextRenderFramePlayers,
- CountdownNanos: (pR.BattleDurationNanos - int64(currRenderFrame.Id)*pR.RollbackEstimatedDtNanos),
MeleeBullets: nextRenderFrameMeleeBullets,
+ CountdownNanos: (pR.BattleDurationNanos - int64(currRenderFrame.Id)*pR.RollbackEstimatedDtNanos),
}
}
@@ -1676,7 +1700,7 @@ func (pR *Room) doBattleMainLoopPerTickBackendDynamicsWithProperLocking(prevRend
}
if nil != inputsBufferSnapshot {
- Logger.Warn(fmt.Sprintf("roomId=%v, room.RenderFrameId=%v, room.CurDynamicsRenderFrameId=%v, room.LastAllConfirmedInputFrameId=%v, unconfirmedMask=%v", pR.Id, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, pR.LastAllConfirmedInputFrameId, inputsBufferSnapshot.UnconfirmedMask))
+ // Logger.Warn(fmt.Sprintf("roomId=%v, room.RenderFrameId=%v, room.CurDynamicsRenderFrameId=%v, room.LastAllConfirmedInputFrameId=%v, unconfirmedMask=%v", pR.Id, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, pR.LastAllConfirmedInputFrameId, inputsBufferSnapshot.UnconfirmedMask))
pR.downsyncToAllPlayers(inputsBufferSnapshot)
}
}
@@ -1746,7 +1770,8 @@ func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRender
2. reconnection
*/
- toSendInputFrameIdSt, toSendInputFrameIdEd := toSendInputFrameDownsyncsSnapshot[0].InputFrameId, toSendInputFrameDownsyncsSnapshot[len(toSendInputFrameDownsyncsSnapshot)-1].InputFrameId+1
+ //toSendInputFrameIdSt, toSendInputFrameIdEd := toSendInputFrameDownsyncsSnapshot[0].InputFrameId, toSendInputFrameDownsyncsSnapshot[len(toSendInputFrameDownsyncsSnapshot)-1].InputFrameId+1
+ _, toSendInputFrameIdEd := toSendInputFrameDownsyncsSnapshot[0].InputFrameId, toSendInputFrameDownsyncsSnapshot[len(toSendInputFrameDownsyncsSnapshot)-1].InputFrameId+1
if pR.BackendDynamicsEnabled && shouldResyncOverall {
tmp := pR.RenderFrameBuffer.GetByFrameId(refRenderFrameId)
if nil == tmp {
@@ -1759,7 +1784,7 @@ func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRender
}
refRenderFrame.BackendUnconfirmedMask = unconfirmedMask
pR.sendSafely(refRenderFrame, toSendInputFrameDownsyncsSnapshot, DOWNSYNC_MSG_ACT_FORCED_RESYNC, playerId, false)
- Logger.Warn(fmt.Sprintf("Sent refRenderFrameId=%v & inputFrameIds [%d, %d), for roomId=%v, playerId=%d, playerJoinIndex=%d, renderFrameId=%d, curDynamicsRenderFrameId=%d, playerLastSentInputFrameId=%d: InputsBuffer=%v", refRenderFrameId, toSendInputFrameIdSt, toSendInputFrameIdEd, pR.Id, playerId, player.JoinIndex, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, player.LastSentInputFrameId, pR.InputsBufferString(false)))
+ // Logger.Warn(fmt.Sprintf("Sent refRenderFrameId=%v & inputFrameIds [%d, %d), for roomId=%v, playerId=%d, playerJoinIndex=%d, renderFrameId=%d, curDynamicsRenderFrameId=%d, playerLastSentInputFrameId=%d: InputsBuffer=%v", refRenderFrameId, toSendInputFrameIdSt, toSendInputFrameIdEd, pR.Id, playerId, player.JoinIndex, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, player.LastSentInputFrameId, pR.InputsBufferString(false)))
} else {
pR.sendSafely(nil, toSendInputFrameDownsyncsSnapshot, DOWNSYNC_MSG_ACT_INPUT_BATCH, playerId, false)
}
@@ -1804,21 +1829,25 @@ func (pR *Room) cloneInputsBuffer(stFrameId, edFrameId int32) []*InputFrameDowns
func (pR *Room) calcHardPushbacksNorms(playerCollider *resolv.Object, playerShape *resolv.ConvexPolygon, snapIntoPlatformOverlap float64, pEffPushback *Vec2D) []Vec2D {
ret := make([]Vec2D, 0, 10) // no one would simultaneously have more than 5 hardPushbacks
- if collision := playerCollider.Check(0, 0); collision != nil {
- for _, obj := range collision.Objects {
- switch obj.Data.(type) {
- case *Barrier:
- barrierShape := obj.Shape.(*resolv.ConvexPolygon)
- if overlapped, pushbackX, pushbackY, overlapResult := CalcPushbacks(0, 0, playerShape, barrierShape); overlapped {
- // ALWAY snap into hardPushbacks!
- // [OverlapX, OverlapY] is the unit vector that points into the platform
- pushbackX, pushbackY = (overlapResult.Overlap-snapIntoPlatformOverlap)*overlapResult.OverlapX, (overlapResult.Overlap-snapIntoPlatformOverlap)*overlapResult.OverlapY
- ret = append(ret, Vec2D{X: overlapResult.OverlapX, Y: overlapResult.OverlapY})
- pEffPushback.X += pushbackX
- pEffPushback.Y += pushbackY
- }
+ collision := playerCollider.Check(0, 0)
+ if nil == collision {
+ return ret
+ }
+ for _, obj := range collision.Objects {
+ switch obj.Data.(type) {
+ case *Barrier:
+ barrierShape := obj.Shape.(*resolv.ConvexPolygon)
+ overlapped, pushbackX, pushbackY, overlapResult := CalcPushbacks(0, 0, playerShape, barrierShape)
+ if !overlapped {
+ continue
}
-
+ // ALWAY snap into hardPushbacks!
+ // [OverlapX, OverlapY] is the unit vector that points into the platform
+ pushbackX, pushbackY = (overlapResult.Overlap-snapIntoPlatformOverlap)*overlapResult.OverlapX, (overlapResult.Overlap-snapIntoPlatformOverlap)*overlapResult.OverlapY
+ ret = append(ret, Vec2D{X: overlapResult.OverlapX, Y: overlapResult.OverlapY})
+ pEffPushback.X += pushbackX
+ pEffPushback.Y += pushbackY
+ default:
}
}
return ret
diff --git a/collider_visualizer/worldColliderDisplay.go b/collider_visualizer/worldColliderDisplay.go
index 8a89c11..8a9e566 100644
--- a/collider_visualizer/worldColliderDisplay.go
+++ b/collider_visualizer/worldColliderDisplay.go
@@ -34,14 +34,15 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi
spaceOffsetX := float64(spaceW) * 0.5
spaceOffsetY := float64(spaceH) * 0.5
- virtualGridToWorldRatio := 0.1
- playerDefaultSpeed := 20
+ worldToVirtualGridRatio := float64(1000)
+ virtualGridToWorldRatio := float64(1)/worldToVirtualGridRatio
+ playerDefaultSpeed := 1 * worldToVirtualGridRatio
minStep := (int(float64(playerDefaultSpeed)*virtualGridToWorldRatio) << 2)
- playerColliderRadius := float64(24)
+ playerColliderRadius := float64(12)
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"
+ playerCollider := GenerateRectCollider(playerPos.X, playerPos.Y, playerColliderRadius*2, playerColliderRadius*4, 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: player world pos =(%.2f, %.2f), shape=%v", i, playerPos.X, playerPos.Y, ConvexPolygonStr(playerCollider.Shape.(*resolv.ConvexPolygon))))
playerColliders[i] = playerCollider
space.Add(playerCollider)
@@ -50,33 +51,34 @@ 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", ConvexPolygonStr(barrierCollider.Shape.(*resolv.ConvexPolygon))))
+ Logger.Debug(fmt.Sprintf("Added barrier: shape=%v", ConvexPolygonStr(barrierCollider.Shape.(*resolv.ConvexPolygon))))
space.Add(barrierCollider)
barrierLocalId++
}
world.Space = space
- moveToCollide := false
+ moveToCollide := true
if moveToCollide {
- newVx, newVy := int32(-2959), int32(-2261)
effPushback := Vec2D{X: float64(0), Y: float64(0)}
toTestPlayerCollider := playerColliders[0]
+ newVx, newVy := int32(43900), int32(-451350)
toTestPlayerCollider.X, toTestPlayerCollider.Y = VirtualGridToPolygonColliderAnchorPos(newVx, newVy, playerColliderRadius, playerColliderRadius, spaceOffsetX, spaceOffsetY, virtualGridToWorldRatio)
- Logger.Info(fmt.Sprintf("Checking collision for virtual (%d, %d), now playerShape=%v", newVx, newVy, ConvexPolygonStr(toTestPlayerCollider.Shape.(*resolv.ConvexPolygon))))
+ Logger.Info(fmt.Sprintf("Checking collision for playerShape=%v", ConvexPolygonStr(toTestPlayerCollider.Shape.(*resolv.ConvexPolygon))))
toTestPlayerCollider.Update()
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(0, 0, playerShape, barrierShape); overlapped {
- Logger.Warn(fmt.Sprintf("Overlapped: a=%v, b=%v, pushbackX=%v, pushbackY=%v", ConvexPolygonStr(playerShape), ConvexPolygonStr(barrierShape), pushbackX, pushbackY))
+ bShape := obj.Shape.(*resolv.ConvexPolygon)
+ Logger.Warn(fmt.Sprintf("Checking potential: a=%v, b=%v", ConvexPolygonStr(playerShape), ConvexPolygonStr(bShape)))
+ if overlapped, pushbackX, pushbackY, overlapResult := CalcPushbacks(0, 0, playerShape, bShape); overlapped {
+ Logger.Warn(fmt.Sprintf("Overlapped: a=%v, b=%v, pushbackX=%v, pushbackY=%v", ConvexPolygonStr(playerShape), ConvexPolygonStr(bShape), pushbackX, pushbackY))
effPushback.X += pushbackX
effPushback.Y += pushbackY
} else {
- Logger.Warn(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(bShape), overlapResult))
}
}
toTestPlayerCollider.X -= effPushback.X
@@ -109,7 +111,7 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi
ReleaseTriggerType: int32(1), // 1: rising-edge, 2: falling-edge
Damage: int32(5),
}
- bulletLeftToRight := true
+ bulletLeftToRight := false
if bulletLeftToRight {
xfac := float64(1.0)
offenderWx, offenderWy := playerPosList.Eles[0].X, playerPosList.Eles[0].Y
@@ -132,7 +134,7 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi
}
}
- bulletRightToLeft := true
+ bulletRightToLeft := false
if bulletRightToLeft {
xfac := float64(-1.0)
offenderWx, offenderWy := playerPosList.Eles[1].X, playerPosList.Eles[1].Y
@@ -177,7 +179,7 @@ func (world *WorldColliderDisplay) Draw(screen *ebiten.Image) {
}
}
- world.Game.DebugDraw(screen, world.Space)
+ //world.Game.DebugDraw(screen, world.Space)
if world.Game.ShowHelpText {
diff --git a/dnmshared/resolv_helper.go b/dnmshared/resolv_helper.go
index 480360e..67d2258 100644
--- a/dnmshared/resolv_helper.go
+++ b/dnmshared/resolv_helper.go
@@ -12,7 +12,7 @@ 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("[%.2f, %.2f]", p[0]+body.X, p[1]+body.Y)
+ s[i] = fmt.Sprintf("[%.3f, %.3f]", p[0]+body.X, p[1]+body.Y)
}
return fmt.Sprintf("{\n%s\n}", strings.Join(s, ",\n"))
@@ -66,6 +66,7 @@ func CalcPushbacks(oldDx, oldDy float64, playerShape, barrierShape *resolv.Conve
playerShape.SetPosition(origX, origY)
}()
playerShape.SetPosition(origX+oldDx, origY+oldDy)
+
overlapResult := &SatResult{
Overlap: 0,
OverlapX: 0,
@@ -74,7 +75,7 @@ func CalcPushbacks(oldDx, oldDy float64, playerShape, barrierShape *resolv.Conve
BContainedInA: true,
Axis: vector.Vector{0, 0},
}
- if overlapped := IsPolygonPairOverlapped(playerShape, barrierShape, overlapResult); overlapped {
+ if overlapped := isPolygonPairOverlapped(playerShape, barrierShape, overlapResult); overlapped {
pushbackX, pushbackY := overlapResult.Overlap*overlapResult.OverlapX, overlapResult.Overlap*overlapResult.OverlapY
return true, pushbackX, pushbackY, overlapResult
} else {
@@ -91,16 +92,17 @@ type SatResult struct {
Axis vector.Vector
}
-func IsPolygonPairOverlapped(a, b *resolv.ConvexPolygon, result *SatResult) bool {
+func isPolygonPairOverlapped(a, b *resolv.ConvexPolygon, result *SatResult) bool {
aCnt, bCnt := len(a.Points), len(b.Points)
// Single point case
if 1 == aCnt && 1 == bCnt {
if nil != result {
result.Overlap = 0
}
- return a.Points[0].X() == b.Points[0].X() && a.Points[0].Y() == b.Points[0].Y()
+ return a.Points[0][0] == b.Points[0][0] && a.Points[0][1] == b.Points[0][1]
}
+ //Logger.Info(fmt.Sprintf("Checking collision between a=%v, b=%v", ConvexPolygonStr(a), ConvexPolygonStr(b)))
if 1 < aCnt {
for _, axis := range a.SATAxes() {
if isPolygonPairSeparatedByDir(a, b, axis.Unit(), result) {
@@ -116,6 +118,7 @@ func IsPolygonPairOverlapped(a, b *resolv.ConvexPolygon, result *SatResult) bool
}
}
}
+ //Logger.Info(fmt.Sprintf("a=%v and b=%v are overlapped", ConvexPolygonStr(a), ConvexPolygonStr(b)))
return true
}
@@ -137,9 +140,10 @@ func isPolygonPairSeparatedByDir(a, b *resolv.ConvexPolygon, e vector.Vector, re
e = (-2.98, 1.49).Unit()
*/
+ //Logger.Info(fmt.Sprintf("Checking separation between a=%v, b=%v along axis e={%.3f, %.3f}#1", ConvexPolygonStr(a), ConvexPolygonStr(b), e[0], e[1]))
var aStart, aEnd, bStart, bEnd float64 = math.MaxFloat64, -math.MaxFloat64, math.MaxFloat64, -math.MaxFloat64
for _, p := range a.Points {
- dot := (p.X()+a.X)*e.X() + (p.Y()+a.Y)*e.Y()
+ dot := (p[0]+a.X)*e[0] + (p[1]+a.Y)*e[1]
if aStart > dot {
aStart = dot
@@ -151,7 +155,7 @@ func isPolygonPairSeparatedByDir(a, b *resolv.ConvexPolygon, e vector.Vector, re
}
for _, p := range b.Points {
- dot := (p.X()+b.X)*e.X() + (p.Y()+b.Y)*e.Y()
+ dot := (p[0]+b.X)*e[0] + (p[1]+b.Y)*e[1]
if bStart > dot {
bStart = dot
@@ -168,7 +172,6 @@ func isPolygonPairSeparatedByDir(a, b *resolv.ConvexPolygon, e vector.Vector, re
}
if nil != result {
- result.Axis = e
overlap := float64(0)
if aStart < bStart {
@@ -209,16 +212,19 @@ func isPolygonPairSeparatedByDir(a, b *resolv.ConvexPolygon, e vector.Vector, re
absoluteOverlap = -overlap
}
- if 0 == currentOverlap || currentOverlap > absoluteOverlap {
+ if (0 == result.Axis[0] && 0 == result.Axis[1]) || currentOverlap > absoluteOverlap {
var sign float64 = 1
if overlap < 0 {
sign = -1
}
result.Overlap = absoluteOverlap
- result.OverlapX = e.X() * sign
- result.OverlapY = e.Y() * sign
+ result.OverlapX = e[0] * sign
+ result.OverlapY = e[1] * sign
}
+
+ result.Axis = e
+ //Logger.Info(fmt.Sprintf("Checking separation between a=%v, b=%v along axis e={%.3f, %.3f}#2: aStart=%.3f, aEnd=%.3f, bStart=%.3f, bEnd=%.3f, overlap=%.3f, currentOverlap=%.3f, absoluteOverlap=%.3f, result=%v", ConvexPolygonStr(a), ConvexPolygonStr(b), e[0], e[1], aStart, aEnd, bStart, bEnd, overlap, currentOverlap, absoluteOverlap, result))
}
// the specified unit vector "e" doesn't separate "a" and "b", overlap result is generated
diff --git a/frontend/assets/resources/map/dungeon/map.tmx b/frontend/assets/resources/map/dungeon/map.tmx
index bbda482..94ed106 100644
--- a/frontend/assets/resources/map/dungeon/map.tmx
+++ b/frontend/assets/resources/map/dungeon/map.tmx
@@ -5,14 +5,14 @@
- eJzt3DFv00AYgGErFUuHigqBVGYGJP4ECxLqgDrRjak/BImdkZGJ/k8cNUbBSmLnavu75HuGR5WaDum9Z+fi5HzRNM0FAAAAAAAAAAAAAAAAAAAUuNyIfh4s52FL1/8hoegOkf1XG13/b63bPVZnSP//+++j//nZ7n870P+yglb6z9d/F/3P2/p/f72xa2z654ToVvov2z8D/fWP7hDZ/0WB6Gb666+//vrH9K+B/vrrr7/++ut/Wv1/jvy76w39z6v/n9bvPY+tP39+bH3RP7x/6Zh21xR/PJP++uuv//q53PTof/79b3r9Hf/66x/f/+WAKftv0z+2/1D3Xf1/tb4eqetv/VdP/7Ht7xrr/1Mxtv/Y9iv9T8pQ/12NP7Su9rTv9++7O5L+cf13tb/a0u8+R/83rXf6V9P/0Hl/u//U9K+3f8ka8Vj6L99/zBzoj+WUfYdM2X9VQYsa+081xoeUtNf/fPpH0z/3HNBff/31j24R1T96/KNlf/8XPf7R9M9N/9z0z03/3PTPTf/c9M9N/9z0z03/3PTPTf/c9M9N/9z0z03/cq96olvqf9r9rwfM8R01/evp7/ivu3+/t/6nzfpP/6XHe99re2T/VQUtau5/v/G5ab5/evr573f3ge30X6Z/172vmwfRDfWfr/+hvUFD79ciz+vH9I/uUGv/rvP7Z6h9D5n+86p9H2H2/nPv+ax9L2n2/ksd/53arhPpv2z/bg4cS//l+k+5ni+5t4/+9Rz/z50Hpfd3Wup1Qv9xSufB28L+j83T9SX96+hfqu3/sbR/Z855kL0/8R0AAAAAAAAAAAAAAACA5f0FyTyU0g==
+ eJzt3DFv00AYgOEoFUuHigqBVGYGJP4EI+qAOsHG1H/CzsjIRP8njhRLwUpi52L7O/t7hmdpOiT33tmXtJebzWZzAwAAAAAAAAAAAAAAAAAABW73op8H83k+0PZ/Tii6Q2T/7V7b/0fj8YTtCun/f/9T9F+fw/6PPf1vK2il/3T9j9F/3Xav/e3esbHpXhOiW+k/b/8M9Nc/ukNk/1cFopvpr7/++usf078G+uuvv/7666//svr/Gvh793v6r6v/38afE4/t/v780viqf3j/0jFtP1P8eSX99ddf/91zeejQf/39Hzr9rX/99Y/v/7rHmP0P6R/bv6/7sf6/G98u1Pa3/6un/9D2Txv7/6UY2n9o+63+i9LX/1jjT427E+27/bueLqR/XP9j7e8OdLtP0f9d44P+1fQ/d90/7D82/evtX7JHvJT+8/cfMge6Yzlm3z5j9t9W0KLG/mON8Tkl7fVfT/9o+ueeA/rrr7/+0S2i+kePf7Ts7/+ixz+a/rnpn5v+uemfm/656Z+b/rnpn5v+uemfm/656Z+b/rnpn5v+uelf7k1HdEv9l93/vscU/6Omfz39rf+6+3d7679s9n/6zz3ep+7tkf23FbSouf/3ve71vv159BrWf9r+5+75+i/XkP7nzgb1vV+LvK5f0j+6Q639284fr1D7GTL9p1X7OcLs/ac+81n7WdLs/eda/63aPifSf97+7Ry4lP7z9R9zP1/y3T7617P+r50Hpd/vNNd9Qv9hSufB+8L+L40v+lfTv1TT/3Np/9aU8yB7f+I7AAAAAAAAAAAAAAAAAPP7B3wkkY4=
-
@@ -164,11 +164,6 @@
-
-
-
-
-
@@ -229,35 +224,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/frontend/assets/scenes/login.fire b/frontend/assets/scenes/login.fire
index f2acb21..e5bc0e5 100644
--- a/frontend/assets/scenes/login.fire
+++ b/frontend/assets/scenes/login.fire
@@ -440,7 +440,7 @@
"array": [
0,
0,
- 216.67520680312998,
+ 216.19964242526865,
0,
0,
0,
diff --git a/frontend/assets/scenes/offline_map_1.fire b/frontend/assets/scenes/offline_map_1.fire
index 354c327..840a0db 100644
--- a/frontend/assets/scenes/offline_map_1.fire
+++ b/frontend/assets/scenes/offline_map_1.fire
@@ -454,7 +454,7 @@
"array": [
0,
0,
- 216.67520680312998,
+ 215.64032554232523,
0,
0,
0,
diff --git a/frontend/assets/scripts/Map.js b/frontend/assets/scripts/Map.js
index 29ee2f7..8c50693 100644
--- a/frontend/assets/scripts/Map.js
+++ b/frontend/assets/scripts/Map.js
@@ -331,7 +331,7 @@ cc.Class({
window.mapIns = self;
window.forceBigEndianFloatingNumDecoding = self.forceBigEndianFloatingNumDecoding;
- self.showCriticalCoordinateLabels = false;
+ self.showCriticalCoordinateLabels = true;
console.warn("+++++++ Map onLoad()");
window.handleClientSessionError = function() {
@@ -427,6 +427,16 @@ 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();
@@ -443,12 +453,14 @@ cc.Class({
}
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 newBarrierCollider = self.collisionSys.createPolygon(x0, y0, Array.from(boundaryObj, p => {
+ const refBoundaryObjs = tileCollisionManager.extractBoundaryObjects(self.node).barriers;
+ const boundaryObjs = parsedBattleColliderInfo.strToPolygon2DListMap;
+ for (let k = 0; k < boundaryObjs["Barrier"].eles.length; k++) {
+ let boundaryObj = boundaryObjs["Barrier"].eles[k];
+ const refBoundaryObj = refBoundaryObjs[k];
+ // boundaryObj = refBoundaryObj;
+ const [x0, y0] = [boundaryObj.anchor.x, boundaryObj.anchor.y];
+ const newBarrierCollider = self.collisionSys.createPolygon(x0, y0, Array.from(boundaryObj.points, p => {
return [p.x, p.y];
}));
newBarrierCollider.data = {
@@ -967,13 +979,13 @@ cc.Class({
applyRoomDownsyncFrameDynamics(rdf, prevRdf) {
const self = this;
for (let [playerId, playerRichInfo] of self.playerRichInfoDict.entries()) {
- const immediatePlayerInfo = rdf.players[playerId];
+ const currPlayerDownsync = rdf.players[playerId];
const prevRdfPlayer = (null == prevRdf ? null : prevRdf.players[playerId]);
- const [wx, wy] = self.virtualGridToWorldPos(immediatePlayerInfo.virtualGridX, immediatePlayerInfo.virtualGridY);
+ const [wx, wy] = self.virtualGridToWorldPos(currPlayerDownsync.virtualGridX, currPlayerDownsync.virtualGridY);
//const justJiggling = (self.jigglingEps1D >= Math.abs(wx - playerRichInfo.node.x) && self.jigglingEps1D >= Math.abs(wy - playerRichInfo.node.y));
playerRichInfo.node.setPosition(wx, wy);
- playerRichInfo.scriptIns.updateSpeed(immediatePlayerInfo.speed);
- playerRichInfo.scriptIns.updateCharacterAnim(immediatePlayerInfo, prevRdfPlayer, false);
+ playerRichInfo.scriptIns.updateSpeed(currPlayerDownsync.speed);
+ playerRichInfo.scriptIns.updateCharacterAnim(currPlayerDownsync, prevRdfPlayer, false);
}
// Update countdown
@@ -1125,7 +1137,9 @@ cc.Class({
characStateIsInterruptWaivable
) {
thatPlayerInNextFrame.velY = self.jumpingInitVelY;
- console.log(`playerId=${playerId}, joinIndex=${joinIndex} triggered a rising-edge of btnB at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}, nextVelY=${thatPlayerInNextFrame.velY}, characStateAlreadyInAir=${characStateAlreadyInAir}, characStateIsInterruptWaivable=${characStateIsInterruptWaivable}`);
+ if (1 == joinIndex) {
+ console.log(`playerId=${playerId}, joinIndex=${joinIndex} jumped at {renderFrame.id: ${currRenderFrame.id}, virtualX: ${currPlayerDownsync.virtualGridX}, virtualY: ${currPlayerDownsync.virtualGridY}, nextVelX: ${thatPlayerInNextFrame.velX}, nextVelY: ${thatPlayerInNextFrame.velY}}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}`);
+ }
}
}
@@ -1258,15 +1272,26 @@ cc.Class({
pushback[1] -= projectedMagnitude * hardPushbackNorm[1];
}
}
+
+ effPushbacks[joinIndex - 1][0] += pushback[0];
+ effPushbacks[joinIndex - 1][1] += pushback[1];
if (currPlayerDownsync.inAir && landedOnGravityPushback) {
fallStopping = true;
if (isAnotherPlayer) {
possiblyFallStoppedOnAnotherPlayer = true;
}
+ if (1 == thatPlayerInNextFrame.joinIndex) {
+ console.log(`playerId=${playerId}, joinIndex=${currPlayerDownsync.joinIndex} fallStopping#1 at {renderFrame.id: ${currRenderFrame.id}, virtualX: ${currPlayerDownsync.virtualGridX}, virtualY: ${currPlayerDownsync.virtualGridY}, velX: ${currPlayerDownsync.velX}, velY: ${currPlayerDownsync.velY}} with effPushback={${effPushbacks[joinIndex - 1][0].toFixed(3)}, ${effPushbacks[joinIndex - 1][1].toFixed(3)}}, overlayMag=${result.overlap.toFixed(4)}, possiblyFallStoppedOnAnotherPlayer=${possiblyFallStoppedOnAnotherPlayer}`);
+ }
}
- effPushbacks[joinIndex - 1][0] += pushback[0];
- effPushbacks[joinIndex - 1][1] += pushback[1];
+ if (1 == joinIndex && currPlayerDownsync.inAir && isBarrier && !landedOnGravityPushback) {
+ console.warn(`playerId=${playerId}, joinIndex=${currPlayerDownsync.joinIndex} inAir & pushed back by barrier & not landed at {renderFrame.id: ${currRenderFrame.id}, virtualX: ${currPlayerDownsync.virtualGridX}, virtualY: ${currPlayerDownsync.virtualGridY}, velX: ${currPlayerDownsync.velX}, velY: ${currPlayerDownsync.velY}} with effPushback={${effPushbacks[joinIndex - 1][0].toFixed(3)}, ${effPushbacks[joinIndex - 1][1].toFixed(3)}}, playerColliderPos={${playerCollider.x.toFixed(3)}, ${playerCollider.y.toFixed(3)}}, barrierPos={${potential.x.toFixed(3)}, ${potential.y.toFixed(3)}}, overlayMag=${result.overlap.toFixed(4)}, len(hardPushbackNorms)=${hardPushbackNorms.length}`);
+ }
+
+ if (1 == joinIndex && currPlayerDownsync.inAir && isAnotherPlayer) {
+ console.warn(`playerId=${playerId}, joinIndex=${currPlayerDownsync.joinIndex} inAir and pushed back by another player at {renderFrame.id: ${currRenderFrame.id}, virtualX: ${currPlayerDownsync.virtualGridX}, virtualY: ${currPlayerDownsync.virtualGridY}, velX: ${currPlayerDownsync.velX}, velY: ${currPlayerDownsync.velY}} with effPushback={${effPushbacks[joinIndex - 1][0].toFixed(3)}, ${effPushbacks[joinIndex - 1][1].toFixed(3)}}, landedOnGravityPushback=${landedOnGravityPushback}, fallStopping=${fallStopping}, playerColliderPos={${playerCollider.x.toFixed(3)}, ${playerCollider.y.toFixed(3)}}, anotherPlayerColliderPos={${potential.x.toFixed(3)}, ${potential.y.toFixed(3)}}, overlayMag=${result.overlap.toFixed(4)}, len(hardPushbackNorms)=${hardPushbackNorms.length}`);
+ }
}
if (fallStopping) {
@@ -1274,9 +1299,6 @@ cc.Class({
thatPlayerInNextFrame.velY = 0;
thatPlayerInNextFrame.characterState = window.ATK_CHARACTER_STATE.Idle1[0];
thatPlayerInNextFrame.framesToRecover = 0;
- if (possiblyFallStoppedOnAnotherPlayer) {
- console.log(`playerId=${playerId}, joinIndex=${joinIndex} possiblyFallStoppedOnAnotherPlayer with effPushback=${effPushbacks[joinIndex - 1]} at renderFrame.id=${currRenderFrame.id}`);
- }
}
if (currPlayerDownsync.inAir) {
thatPlayerInNextFrame.characterState = window.toInAirConjugate(thatPlayerInNextFrame.characterState);
@@ -1307,7 +1329,7 @@ cc.Class({
// Otherwise when smashing into a wall the atked player would be pushed into the wall first and only got back in the next renderFrame, not what I want here
bulletPushback[0] -= (projectedMagnitude * hardPushbackNorm[0]);
bulletPushback[1] -= (projectedMagnitude * hardPushbackNorm[1]);
- // console.log(`playerId=${playerId}, joinIndex=${joinIndex} reducing bulletPushback=${JSON.stringify(bulletPushback)} by ${JSON.stringify([projectedMagnitude * hardPushbackNorm[0], projectedMagnitude * hardPushbackNorm[1]])} where hardPushbackNorm=${JSON.stringify(hardPushbackNorm)}, projectedMagnitude=${projectedMagnitude} at renderFrame.id=${currRenderFrame.id}`);
+ // console.log(`playerId=${playerId}, joinIndex=${joinIndex} reducing bulletPushback=${JSON.stringify(bulletPushback)} by ${JSON.stringify([projectedMagnitude * hardPushbackNorm[0], projectedMagnitude * hardPushbackNorm[1]])} where hardPushbackNorm=${JSON.stringify(hardPushbackNorm)}, projectedMagnitude=${projectedMagnitude} at renderFrame.id=${currRenderFrame.id}`);
}
}
// console.log(`playerId=${playerId}, joinIndex=${joinIndex} is actually pushed back by meleeBullet for bulletPushback=${JSON.stringify(bulletPushback)} at renderFrame.id=${currRenderFrame.id}`);
@@ -1348,8 +1370,20 @@ cc.Class({
const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex;
const playerCollider = collisionSysMap.get(collisionPlayerIndex);
// Update "virtual grid position"
- const thatPlayerInNextFrame = nextRenderFramePlayers[playerId];
+ const [currPlayerDownsync, thatPlayerInNextFrame] = [currRenderFrame.players[playerId], nextRenderFramePlayers[playerId]];
[thatPlayerInNextFrame.virtualGridX, thatPlayerInNextFrame.virtualGridY] = self.polygonColliderAnchorToVirtualGridPos(playerCollider.x - effPushbacks[joinIndex - 1][0], playerCollider.y - effPushbacks[joinIndex - 1][1], self.playerRichInfoArr[j].colliderRadius, self.playerRichInfoArr[j].colliderRadius);
+
+ if (1 == thatPlayerInNextFrame.joinIndex) {
+ if (thatPlayerInNextFrame.inAir && 0 != thatPlayerInNextFrame.velY) {
+ console.log(`playerId=${playerId}, joinIndex=${thatPlayerInNextFrame.joinIndex} inAir trajectory: {nextRenderFrame.id: ${currRenderFrame.id + 1}, nextVirtualX: ${thatPlayerInNextFrame.virtualGridX}, nextVirtualY: ${thatPlayerInNextFrame.virtualGridY}, nextVelX: ${thatPlayerInNextFrame.velX}, nextVelY: ${thatPlayerInNextFrame.velY}}, with playerColliderPos={${playerCollider.x.toFixed(3)}, ${playerCollider.y.toFixed(3)}}, effPushback={${effPushbacks[joinIndex - 1][0].toFixed(3)}, ${effPushbacks[joinIndex - 1][1].toFixed(3)}}`);
+ }
+ if (currPlayerDownsync.inAir && !thatPlayerInNextFrame.inAir) {
+ console.warn(`playerId=${playerId}, joinIndex=${thatPlayerInNextFrame.joinIndex} fallStopping#2 at {nextRenderFrame.id: ${currRenderFrame.id + 1}, nextVirtualX: ${thatPlayerInNextFrame.virtualGridX}, nextVirtualY: ${thatPlayerInNextFrame.virtualGridY}, nextVelX: ${thatPlayerInNextFrame.velX}, nextVelY: ${thatPlayerInNextFrame.velY}}, with playerColliderPos={${playerCollider.x.toFixed(3)}, ${playerCollider.y.toFixed(3)}}, effPushback={${effPushbacks[joinIndex - 1][0].toFixed(3)}, ${effPushbacks[joinIndex - 1][1].toFixed(3)}}`);
+ }
+ if (!currPlayerDownsync.inAir && thatPlayerInNextFrame.inAir) {
+ console.warn(`playerId=${playerId}, joinIndex=${thatPlayerInNextFrame.joinIndex} took off at {nextRenderFrame.id: ${currRenderFrame.id + 1}, nextVirtualX: ${thatPlayerInNextFrame.virtualGridX}, nextVirtualY: ${thatPlayerInNextFrame.virtualGridY}, nextVelX: ${thatPlayerInNextFrame.velX}, nextVelY: ${thatPlayerInNextFrame.velY}}, with playerColliderPos={${playerCollider.x.toFixed(3)}, ${playerCollider.y.toFixed(3)}}, effPushback={${effPushbacks[joinIndex - 1][0].toFixed(3)}, ${effPushbacks[joinIndex - 1][1].toFixed(3)}}`);
+ }
+ }
}
return window.pb.protos.RoomDownsyncFrame.create({
@@ -1364,11 +1398,10 @@ cc.Class({
This function eventually calculates a "RoomDownsyncFrame" where "RoomDownsyncFrame.id == renderFrameIdEd" if not interruptted.
*/
const self = this;
- let i = renderFrameIdSt,
- prevLatestRdf = null,
+ let prevLatestRdf = null,
latestRdf = null;
- do {
+ for (let i = renderFrameIdSt; i < renderFrameIdEd; i++) {
latestRdf = self.recentRenderCache.getByFrameId(i); // typed "RoomDownsyncFrame"; [WARNING] When "true == isChasing", this function can be interruptted by "onRoomDownsyncFrame(rdf)" asynchronously anytime, making this line return "null"!
if (null == latestRdf) {
console.warn(`Couldn't find renderFrame for i=${i} to rollback, self.renderFrameId=${self.renderFrameId}, lastAllConfirmedRenderFrameId=${self.lastAllConfirmedRenderFrameId}, lastAllConfirmedInputFrameId=${self.lastAllConfirmedInputFrameId}, might've been interruptted by onRoomDownsyncFrame`);
@@ -1400,8 +1433,7 @@ cc.Class({
self.chaserRenderFrameId = latestRdf.id;
}
self.recentRenderCache.setByFrameId(latestRdf, latestRdf.id);
- ++i;
- } while (i < renderFrameIdEd);
+ }
return [prevLatestRdf, latestRdf];
},
@@ -1496,6 +1528,7 @@ cc.Class({
},
calcHardPushbacksNorms(collider, potentials, result, snapIntoPlatformOverlap, effPushback) {
+ const self = this;
let ret = [];
for (const potential of potentials) {
if (null == potential.data || !(true == potential.data.hardPushback)) continue;
diff --git a/frontend/collision_test_nodejs.js b/frontend/collision_test_nodejs.js
index 3db8003..4aac87d 100644
--- a/frontend/collision_test_nodejs.js
+++ b/frontend/collision_test_nodejs.js
@@ -11,24 +11,28 @@ function polygonStr(body) {
return JSON.stringify(coords);
}
-const playerCollider = collisionSys.createPolygon(1269.665, 1353.335, [[0, 0], [64, 0], [64, 64], [0, 64]]);
+const playerCollider1 = collisionSys.createPolygon(944.000, 676.000, [[0, 0], [24, 0], [24, 48], [0, 48]]);
+playerCollider1.data = {isPlayer: true};
+const playerCollider2 = collisionSys.createPolygon(958.000, 724.000, [[0, 0], [24, 0], [24, 48], [0, 48]]);
+playerCollider2.data = {isPlayer: true};
const barrierCollider1 = collisionSys.createPolygon(1277.7159000000001, 1570.5575, [[642.5696, 319.159], [0, 319.15680000000003], [5.7286, 0], [643.7451, 0.9014999999999986]]);
const barrierCollider2 = collisionSys.createPolygon(1289.039, 1318.0805, [[628.626, 54.254500000000064], [0, 56.03250000000003], [0.42449999999999477, 1.1229999999999905], [625.9715000000001, 0]]);
const barrierCollider3 = collisionSys.createPolygon(1207, 1310, [[69, 581], [0, 579], [8, 3], [79, 0]]);
-playerCollider.x += -2.98;
-playerCollider.y += -50.0;
collisionSys.update();
const effPushback = [0.0, 0.0];
const result = collisionSys.createResult();
-const potentials = playerCollider.potentials();
-
-for (const barrier of potentials) {
- if (!playerCollider.collides(barrier, result)) continue;
+// Check collision for player1
+const potentials = playerCollider1.potentials();
+for (const potential of potentials) {
+ if (null == potential.data || true != potential.data.isPlayer) continue;
+ console.log(`Collided player potential of a=${polygonStr(playerCollider1)}: b=${polygonStr(potential)}`);
+ if (!playerCollider1.collides(potential, result)) continue;
+ console.log(`Collided player of a=${polygonStr(playerCollider1)}: b=${polygonStr(potential)}`);
const pushbackX = result.overlap * result.overlap_x;
const pushbackY = result.overlap * result.overlap_y;
console.log(`Overlapped: a=${polygonStr(result.a)}, b=${polygonStr(result.b)}, pushbackX=${pushbackX}, pushbackY=${pushbackY}`);