mirror of
https://github.com/genxium/DelayNoMore
synced 2024-12-26 11:48:56 +00:00
Applied snapping on all-sides to avoid random zero-overlap detection uncertainty.
This commit is contained in:
parent
c5b26d716e
commit
a41c68fb13
@ -401,11 +401,11 @@ func (pR *Room) StartBattle() {
|
|||||||
pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY = float64(spaceW)*0.5, float64(spaceH)*0.5
|
pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY = float64(spaceW)*0.5, float64(spaceH)*0.5
|
||||||
pR.refreshColliders(spaceW, spaceH)
|
pR.refreshColliders(spaceW, spaceH)
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Will be triggered from a goroutine which executes the critical `Room.AddPlayerIfPossible`, thus the `battleMainLoop` should be detached.
|
Will be triggered from a goroutine which executes the critical `Room.AddPlayerIfPossible`, thus the `battleMainLoop` should be detached.
|
||||||
* All of the consecutive stages, e.g. settlement, dismissal, should share the same goroutine with `battleMainLoop`.
|
All of the consecutive stages, e.g. settlement, dismissal, should share the same goroutine with `battleMainLoop`.
|
||||||
*
|
|
||||||
* As "defer" is only applicable to function scope, the use of "pR.InputsBufferLock" within "battleMainLoop" is embedded into each subroutine call.
|
As "defer" is only applicable to function scope, the use of "pR.InputsBufferLock" within "battleMainLoop" is embedded into each subroutine call.
|
||||||
*/
|
*/
|
||||||
battleMainLoop := func() {
|
battleMainLoop := func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -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
|
pR.RollbackEstimatedDtNanos = 16666666 // A little smaller than the actual per frame time, just for logging FAST FRAME
|
||||||
dilutedServerFps := float64(55.0)
|
dilutedServerFps := float64(55.0)
|
||||||
pR.dilutedRollbackEstimatedDtNanos = int64(float64(pR.RollbackEstimatedDtNanos) * float64(pR.ServerFps) / dilutedServerFps)
|
pR.dilutedRollbackEstimatedDtNanos = int64(float64(pR.RollbackEstimatedDtNanos) * float64(pR.ServerFps) / dilutedServerFps)
|
||||||
pR.BattleDurationFrames = 60 * pR.ServerFps
|
pR.BattleDurationFrames = 120 * pR.ServerFps
|
||||||
pR.BattleDurationNanos = int64(pR.BattleDurationFrames) * (pR.RollbackEstimatedDtNanos + 1)
|
pR.BattleDurationNanos = int64(pR.BattleDurationFrames) * (pR.RollbackEstimatedDtNanos + 1)
|
||||||
pR.InputFrameUpsyncDelayTolerance = 2
|
pR.InputFrameUpsyncDelayTolerance = 2
|
||||||
pR.MaxChasingRenderFramesPerUpdate = 8
|
pR.MaxChasingRenderFramesPerUpdate = 8
|
||||||
@ -1278,6 +1278,7 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende
|
|||||||
|
|
||||||
// TODO: Write unit-test for this function to compare with its frontend counter part
|
// TODO: Write unit-test for this function to compare with its frontend counter part
|
||||||
func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame *InputFrameDownsync, currRenderFrame *RoomDownsyncFrame, collisionSysMap map[int32]*resolv.Object) *RoomDownsyncFrame {
|
func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame *InputFrameDownsync, currRenderFrame *RoomDownsyncFrame, collisionSysMap map[int32]*resolv.Object) *RoomDownsyncFrame {
|
||||||
|
topPadding, bottomPadding, leftPadding, rightPadding := pR.SnapIntoPlatformOverlap, pR.SnapIntoPlatformOverlap, pR.SnapIntoPlatformOverlap, pR.SnapIntoPlatformOverlap
|
||||||
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
|
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
|
||||||
nextRenderFramePlayers := make(map[int32]*PlayerDownsync, pR.Capacity)
|
nextRenderFramePlayers := make(map[int32]*PlayerDownsync, pR.Capacity)
|
||||||
// Make a copy first
|
// Make a copy first
|
||||||
@ -1395,9 +1396,12 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF
|
|||||||
currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
|
currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
|
||||||
// Reset playerCollider position from the "virtual grid position"
|
// Reset playerCollider position from the "virtual grid position"
|
||||||
newVx, newVy := currPlayerDownsync.VirtualGridX+currPlayerDownsync.VelX, currPlayerDownsync.VirtualGridY+currPlayerDownsync.VelY
|
newVx, newVy := currPlayerDownsync.VirtualGridX+currPlayerDownsync.VelX, currPlayerDownsync.VirtualGridY+currPlayerDownsync.VelY
|
||||||
|
if thatPlayerInNextFrame.VelY == pR.JumpingInitVelY {
|
||||||
|
newVy += thatPlayerInNextFrame.VelY
|
||||||
|
}
|
||||||
|
|
||||||
colliderWidth, colliderHeight := player.ColliderRadius*2, player.ColliderRadius*4
|
halfColliderWidth, halfColliderHeight := player.ColliderRadius, player.ColliderRadius+player.ColliderRadius // avoid multiplying
|
||||||
playerCollider.X, playerCollider.Y = VirtualGridToPolygonColliderBLPos(newVx, newVy, colliderWidth*0.5, colliderHeight*0.5, pR.SnapIntoPlatformOverlap, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, pR.VirtualGridToWorldRatio)
|
playerCollider.X, playerCollider.Y = VirtualGridToPolygonColliderBLPos(newVx, newVy, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, pR.VirtualGridToWorldRatio)
|
||||||
// Update in the collision system
|
// Update in the collision system
|
||||||
playerCollider.Update()
|
playerCollider.Update()
|
||||||
|
|
||||||
@ -1423,8 +1427,7 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF
|
|||||||
}
|
}
|
||||||
offenderWx, offenderWy := VirtualGridToWorldPos(offender.VirtualGridX, offender.VirtualGridY, pR.VirtualGridToWorldRatio)
|
offenderWx, offenderWy := VirtualGridToWorldPos(offender.VirtualGridX, offender.VirtualGridY, pR.VirtualGridToWorldRatio)
|
||||||
bulletWx, bulletWy := offenderWx+xfac*meleeBullet.HitboxOffset, offenderWy
|
bulletWx, bulletWy := offenderWx+xfac*meleeBullet.HitboxOffset, offenderWy
|
||||||
|
newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, meleeBullet.HitboxSize.X, meleeBullet.HitboxSize.Y, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, "MeleeBullet")
|
||||||
newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, meleeBullet.HitboxSize.X, meleeBullet.HitboxSize.Y, 0, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, "MeleeBullet")
|
|
||||||
newBulletCollider.Data = meleeBullet
|
newBulletCollider.Data = meleeBullet
|
||||||
pR.Space.Add(newBulletCollider)
|
pR.Space.Add(newBulletCollider)
|
||||||
collisionSysMap[collisionBulletIndex] = newBulletCollider
|
collisionSysMap[collisionBulletIndex] = newBulletCollider
|
||||||
@ -1444,9 +1447,6 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF
|
|||||||
playerCollider := collisionSysMap[collisionPlayerIndex]
|
playerCollider := collisionSysMap[collisionPlayerIndex]
|
||||||
playerShape := playerCollider.Shape.(*resolv.ConvexPolygon)
|
playerShape := playerCollider.Shape.(*resolv.ConvexPolygon)
|
||||||
hardPushbackNorms[joinIndex-1] = pR.calcHardPushbacksNorms(playerCollider, playerShape, pR.SnapIntoPlatformOverlap, &(effPushbacks[joinIndex-1]))
|
hardPushbackNorms[joinIndex-1] = pR.calcHardPushbacksNorms(playerCollider, playerShape, pR.SnapIntoPlatformOverlap, &(effPushbacks[joinIndex-1]))
|
||||||
if 0 < len(hardPushbackNorms[joinIndex-1]) {
|
|
||||||
Logger.Debug(fmt.Sprintf("playerId=%d, joinIndex=%d got %d non-empty hardPushbacks at renderFrame.id=%d", playerId, joinIndex, len(hardPushbackNorms), currRenderFrame.Id))
|
|
||||||
}
|
|
||||||
currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
|
currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
|
||||||
fallStopping := false
|
fallStopping := false
|
||||||
possiblyFallStoppedOnAnotherPlayer := false
|
possiblyFallStoppedOnAnotherPlayer := false
|
||||||
@ -1480,6 +1480,10 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF
|
|||||||
pushbackX, pushbackY = (overlapResult.Overlap-pR.SnapIntoPlatformOverlap)*overlapResult.OverlapX, (overlapResult.Overlap-pR.SnapIntoPlatformOverlap)*overlapResult.OverlapY
|
pushbackX, pushbackY = (overlapResult.Overlap-pR.SnapIntoPlatformOverlap)*overlapResult.OverlapX, (overlapResult.Overlap-pR.SnapIntoPlatformOverlap)*overlapResult.OverlapY
|
||||||
thatPlayerInNextFrame.InAir = false
|
thatPlayerInNextFrame.InAir = false
|
||||||
}
|
}
|
||||||
|
if isAnotherPlayer {
|
||||||
|
// [WARNING] See comments of this substep in frontend.
|
||||||
|
pushbackX, pushbackY = (overlapResult.Overlap-pR.SnapIntoPlatformOverlap*2)*overlapResult.OverlapX, (overlapResult.Overlap-pR.SnapIntoPlatformOverlap*2)*overlapResult.OverlapY
|
||||||
|
}
|
||||||
for _, hardPushbackNorm := range hardPushbackNorms[joinIndex-1] {
|
for _, hardPushbackNorm := range hardPushbackNorms[joinIndex-1] {
|
||||||
projectedMagnitude := pushbackX*hardPushbackNorm.X + pushbackY*hardPushbackNorm.Y
|
projectedMagnitude := pushbackX*hardPushbackNorm.X + pushbackY*hardPushbackNorm.Y
|
||||||
if isBarrier || (isAnotherPlayer && 0 > projectedMagnitude) {
|
if isBarrier || (isAnotherPlayer && 0 > projectedMagnitude) {
|
||||||
@ -1494,15 +1498,16 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF
|
|||||||
if isAnotherPlayer {
|
if isAnotherPlayer {
|
||||||
possiblyFallStoppedOnAnotherPlayer = true
|
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 1 == joinIndex {
|
||||||
|
halfColliderWidth, halfColliderHeight := player.ColliderRadius, player.ColliderRadius+player.ColliderRadius // avoid multiplying
|
||||||
|
if fallStopping {
|
||||||
|
Logger.Info(fmt.Sprintf("playerId=%d, joinIndex=%d fallStopping#1\n{renderFrame.id: %d, possiblyFallStoppedOnAnotherPlayer: %v}\nplayerColliderPos=%v, effPushback={%.3f, %.3f}, overlapMag=%.4f", playerId, joinIndex, currRenderFrame.Id, possiblyFallStoppedOnAnotherPlayer, RectCenterStr(playerCollider, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY), effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y, overlapResult.Overlap))
|
||||||
|
} else if currPlayerDownsync.InAir && isBarrier && !landedOnGravityPushback {
|
||||||
|
Logger.Warn(fmt.Sprintf("playerId=%d, joinIndex=%d inAir & pushed back by barrier & not landed at {renderFrame.id: %d}\nplayerColliderPos=%v, effPushback={%.3f, %.3f}, overlapMag=%.4f, len(hardPushbackNorms)=%d", playerId, joinIndex, currRenderFrame.Id, RectCenterStr(playerCollider, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY), effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y, overlapResult.Overlap, len(hardPushbackNorms)))
|
||||||
|
} else if currPlayerDownsync.InAir && isAnotherPlayer {
|
||||||
|
Logger.Warn(fmt.Sprintf("playerId=%d, joinIndex=%d inAir & pushed back by another player\n{renderFrame.id: %d}\nplayerColliderPos=%v, anotherPlayerColliderPos=%v, effPushback={%.3f, %.3f}, landedOnGravityPushback=%v, fallStopping=%v, overlapMag=%.4f, len(hardPushbackNorms)=%d", playerId, joinIndex, currRenderFrame.Id, RectCenterStr(playerCollider, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY), RectCenterStr(obj, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY), effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y, landedOnGravityPushback, fallStopping, overlapResult.Overlap, len(hardPushbackNorms)))
|
||||||
}
|
}
|
||||||
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 {
|
if fallStopping {
|
||||||
@ -1599,21 +1604,18 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF
|
|||||||
playerId := player.Id
|
playerId := player.Id
|
||||||
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
|
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
|
||||||
playerCollider := collisionSysMap[collisionPlayerIndex]
|
playerCollider := collisionSysMap[collisionPlayerIndex]
|
||||||
playerShape := playerCollider.Shape.(*resolv.ConvexPolygon)
|
|
||||||
// Update "virtual grid position"
|
// Update "virtual grid position"
|
||||||
currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
|
currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
|
||||||
colliderWidth, colliderHeight := player.ColliderRadius*2, player.ColliderRadius*4
|
halfColliderWidth, halfColliderHeight := player.ColliderRadius, player.ColliderRadius+player.ColliderRadius // avoid multiplying
|
||||||
thatPlayerInNextFrame.VirtualGridX, thatPlayerInNextFrame.VirtualGridY = PolygonColliderBLToVirtualGridPos(playerCollider.X-effPushbacks[joinIndex-1].X, playerCollider.Y-effPushbacks[joinIndex-1].Y, colliderWidth*0.5, colliderHeight*0.5, pR.SnapIntoPlatformOverlap, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, pR.WorldToVirtualGridRatio)
|
thatPlayerInNextFrame.VirtualGridX, thatPlayerInNextFrame.VirtualGridY = PolygonColliderBLToVirtualGridPos(playerCollider.X-effPushbacks[joinIndex-1].X, playerCollider.Y-effPushbacks[joinIndex-1].Y, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, pR.WorldToVirtualGridRatio)
|
||||||
|
|
||||||
if 1 == thatPlayerInNextFrame.JoinIndex {
|
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, nextVelY: %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 {
|
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, nextVelY: %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))
|
Logger.Warn(fmt.Sprintf("playerId=%d, joinIndex=%d fallStopping#2:\n{nextRenderFrame.id: %d, nextVirtualX: %d, nextVirtualY: %d, nextVelX: %d, nextVelY: %d}\n\tcalculated from <- playerColliderPos=%v, effPushback={%.3f, %.3f}", playerId, joinIndex, currRenderFrame.Id+1, thatPlayerInNextFrame.VirtualGridX, thatPlayerInNextFrame.VirtualGridY, thatPlayerInNextFrame.VelX, thatPlayerInNextFrame.VelY, RectCenterStr(playerCollider, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY), effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y))
|
||||||
}
|
} else if !currPlayerDownsync.InAir && thatPlayerInNextFrame.InAir {
|
||||||
if !currPlayerDownsync.InAir && thatPlayerInNextFrame.InAir {
|
Logger.Warn(fmt.Sprintf("playerId=%d, joinIndex=%d took off:\n{nextRenderFrame.id: %d, nextVirtualX: %d, nextVirtualY: %d, nextVelX: %d, nextVelY: %d}\n\tcalculated from <- playerColliderPos=%v, effPushback={%.3f, %.3f}", playerId, joinIndex, currRenderFrame.Id+1, thatPlayerInNextFrame.VirtualGridX, thatPlayerInNextFrame.VirtualGridY, thatPlayerInNextFrame.VelX, thatPlayerInNextFrame.VelY, RectCenterStr(playerCollider, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY), effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y))
|
||||||
Logger.Warn(fmt.Sprintf("playerId=%d, joinIndex=%d took off at {nextRenderFrame.id: %d, nextVirtualX: %d, nextVirtualY: %d, nextVelX: %d, nextVelY: %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))
|
} else if thatPlayerInNextFrame.InAir && (0 != thatPlayerInNextFrame.VelY) {
|
||||||
|
//Logger.Info(fmt.Sprintf("playerId=%d, joinIndex=%d inAir trajectory:\n{nextRenderFrame.id: %d, nextVirtualX: %d, nextVirtualY: %d, nextVelX: %d, nextVelY: %d}\n\tcalculated from <- playerColliderPos=%v, effPushback={%.3f, %.3f}", playerId, joinIndex, currRenderFrame.Id+1, thatPlayerInNextFrame.VirtualGridX, thatPlayerInNextFrame.VirtualGridY, thatPlayerInNextFrame.VelX, thatPlayerInNextFrame.VelY, RectCenterStr(playerCollider, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY), effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1645,12 +1647,14 @@ func (pR *Room) inputFrameIdDebuggable(inputFrameId int32) bool {
|
|||||||
func (pR *Room) refreshColliders(spaceW, spaceH int32) {
|
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"
|
// Kindly note that by now, we've already got all the shapes in the tmx file into "pR.(Players | Barriers)" from "ParseTmxLayersAndGroups"
|
||||||
|
|
||||||
minStep := (int(float64(pR.PlayerDefaultSpeed)*pR.VirtualGridToWorldRatio) << 1) // the approx minimum distance a player can move per frame in world coordinate
|
topPadding, bottomPadding, leftPadding, rightPadding := pR.SnapIntoPlatformOverlap, pR.SnapIntoPlatformOverlap, pR.SnapIntoPlatformOverlap, pR.SnapIntoPlatformOverlap
|
||||||
|
|
||||||
|
minStep := (int(float64(pR.PlayerDefaultSpeed)*pR.VirtualGridToWorldRatio) << 2) // the approx minimum distance a player can move per frame in world coordinate
|
||||||
pR.Space = resolv.NewSpace(int(spaceW), int(spaceH), minStep, minStep) // allocate a new collision space everytime after a battle is settled
|
pR.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 {
|
for _, player := range pR.Players {
|
||||||
wx, wy := VirtualGridToWorldPos(player.VirtualGridX, player.VirtualGridY, pR.VirtualGridToWorldRatio)
|
wx, wy := VirtualGridToWorldPos(player.VirtualGridX, player.VirtualGridY, pR.VirtualGridToWorldRatio)
|
||||||
colliderWidth, colliderHeight := player.ColliderRadius*2, player.ColliderRadius*4
|
colliderWidth, colliderHeight := player.ColliderRadius*2, player.ColliderRadius*4
|
||||||
playerCollider := GenerateRectCollider(wx, wy, colliderWidth, colliderHeight, pR.SnapIntoPlatformOverlap, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, "Player") // the coords of all barrier boundaries are multiples of tileWidth(i.e. 16), by adding snapping y-padding when "landedOnGravityPushback" all "playerCollider.Y" would be a multiple of 1.0
|
playerCollider := GenerateRectCollider(wx, wy, colliderWidth, colliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, "Player") // the coords of all barrier boundaries are multiples of tileWidth(i.e. 16), by adding snapping y-padding when "landedOnGravityPushback" all "playerCollider.Y" would be a multiple of 1.0
|
||||||
playerCollider.Data = player
|
playerCollider.Data = player
|
||||||
pR.Space.Add(playerCollider)
|
pR.Space.Add(playerCollider)
|
||||||
// Keep track of the collider in "pR.CollisionSysMap"
|
// Keep track of the collider in "pR.CollisionSysMap"
|
||||||
|
@ -37,14 +37,15 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi
|
|||||||
worldToVirtualGridRatio := float64(1000)
|
worldToVirtualGridRatio := float64(1000)
|
||||||
virtualGridToWorldRatio := float64(1) / worldToVirtualGridRatio
|
virtualGridToWorldRatio := float64(1) / worldToVirtualGridRatio
|
||||||
playerDefaultSpeed := 1 * worldToVirtualGridRatio
|
playerDefaultSpeed := 1 * worldToVirtualGridRatio
|
||||||
minStep := (int(float64(playerDefaultSpeed)*virtualGridToWorldRatio) << 2)
|
minStep := (int(float64(playerDefaultSpeed)*virtualGridToWorldRatio) << 3)
|
||||||
playerColliderRadius := float64(12)
|
playerColliderRadius := float64(12)
|
||||||
playerColliders := make([]*resolv.Object, len(playerPosList.Eles))
|
playerColliders := make([]*resolv.Object, len(playerPosList.Eles))
|
||||||
snapIntoPlatformOverlap := float64(0.1)
|
snapIntoPlatformOverlap := float64(0.1)
|
||||||
space := resolv.NewSpace(int(spaceW), int(spaceH), minStep, minStep)
|
space := resolv.NewSpace(int(spaceW), int(spaceH), minStep, minStep)
|
||||||
|
topPadding, bottomPadding, leftPadding, rightPadding := snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap
|
||||||
for i, playerPos := range playerPosList.Eles {
|
for i, playerPos := range playerPosList.Eles {
|
||||||
colliderWidth, colliderHeight := playerColliderRadius*2, playerColliderRadius*4
|
colliderWidth, colliderHeight := playerColliderRadius*2, playerColliderRadius*4
|
||||||
playerCollider := GenerateRectCollider(playerPos.X, playerPos.Y, colliderWidth, colliderHeight, snapIntoPlatformOverlap, 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, colliderWidth, colliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, 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))))
|
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
|
playerColliders[i] = playerCollider
|
||||||
space.Add(playerCollider)
|
space.Add(playerCollider)
|
||||||
@ -60,13 +61,13 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi
|
|||||||
|
|
||||||
world.Space = space
|
world.Space = space
|
||||||
|
|
||||||
moveToCollide := false
|
moveToCollide := true
|
||||||
if moveToCollide {
|
if moveToCollide {
|
||||||
effPushback := Vec2D{X: float64(0), Y: float64(0)}
|
effPushback := Vec2D{X: float64(0), Y: float64(0)}
|
||||||
toTestPlayerCollider := playerColliders[0]
|
toTestPlayerCollider := playerColliders[0]
|
||||||
newVx, newVy := int32(27999), int32(-420270)
|
//colliderWidth, colliderHeight := playerColliderRadius*2, playerColliderRadius*4
|
||||||
colliderWidth, colliderHeight := playerColliderRadius*2, playerColliderRadius*4
|
//newVx, newVy := int32(27999), int32(-420270)
|
||||||
toTestPlayerCollider.X, toTestPlayerCollider.Y = VirtualGridToPolygonColliderTLPos(newVx, newVy, colliderWidth, colliderHeight, spaceOffsetX, spaceOffsetY, virtualGridToWorldRatio)
|
//toTestPlayerCollider.X, toTestPlayerCollider.Y = VirtualGridToPolygonColliderBLPos(newVx, newVy, colliderWidth, colliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, virtualGridToWorldRatio)
|
||||||
|
|
||||||
Logger.Info(fmt.Sprintf("Checking collision for playerShape=%v", ConvexPolygonStr(toTestPlayerCollider.Shape.(*resolv.ConvexPolygon))))
|
Logger.Info(fmt.Sprintf("Checking collision for playerShape=%v", ConvexPolygonStr(toTestPlayerCollider.Shape.(*resolv.ConvexPolygon))))
|
||||||
|
|
||||||
@ -114,13 +115,12 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi
|
|||||||
ReleaseTriggerType: int32(1), // 1: rising-edge, 2: falling-edge
|
ReleaseTriggerType: int32(1), // 1: rising-edge, 2: falling-edge
|
||||||
Damage: int32(5),
|
Damage: int32(5),
|
||||||
}
|
}
|
||||||
bulletLeftToRight := true
|
bulletLeftToRight := false
|
||||||
if bulletLeftToRight {
|
if bulletLeftToRight {
|
||||||
xfac := float64(1.0)
|
xfac := float64(1.0)
|
||||||
offenderWx, offenderWy := playerPosList.Eles[0].X, playerPosList.Eles[0].Y
|
offenderWx, offenderWy := playerPosList.Eles[0].X, playerPosList.Eles[0].Y
|
||||||
bulletWx, bulletWy := offenderWx+xfac*meleeBullet.HitboxOffset, offenderWy
|
bulletWx, bulletWy := offenderWx+xfac*meleeBullet.HitboxOffset, offenderWy
|
||||||
|
newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, meleeBullet.HitboxSize.X, meleeBullet.HitboxSize.Y, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, "MeleeBullet")
|
||||||
newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, meleeBullet.HitboxSize.X, meleeBullet.HitboxSize.Y, 0, spaceOffsetX, spaceOffsetY, "MeleeBullet")
|
|
||||||
space.Add(newBulletCollider)
|
space.Add(newBulletCollider)
|
||||||
bulletShape := newBulletCollider.Shape.(*resolv.ConvexPolygon)
|
bulletShape := newBulletCollider.Shape.(*resolv.ConvexPolygon)
|
||||||
Logger.Warn(fmt.Sprintf("bullet ->: Added bullet collider to space: a=%v", ConvexPolygonStr(bulletShape)))
|
Logger.Warn(fmt.Sprintf("bullet ->: Added bullet collider to space: a=%v", ConvexPolygonStr(bulletShape)))
|
||||||
@ -137,13 +137,13 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bulletRightToLeft := true
|
bulletRightToLeft := false
|
||||||
if bulletRightToLeft {
|
if bulletRightToLeft {
|
||||||
xfac := float64(-1.0)
|
xfac := float64(-1.0)
|
||||||
offenderWx, offenderWy := playerPosList.Eles[1].X, playerPosList.Eles[1].Y
|
offenderWx, offenderWy := playerPosList.Eles[1].X, playerPosList.Eles[1].Y
|
||||||
bulletWx, bulletWy := offenderWx+xfac*meleeBullet.HitboxOffset, offenderWy
|
bulletWx, bulletWy := offenderWx+xfac*meleeBullet.HitboxOffset, offenderWy
|
||||||
|
|
||||||
newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, meleeBullet.HitboxSize.X, meleeBullet.HitboxSize.Y, 0, spaceOffsetX, spaceOffsetY, "MeleeBullet")
|
newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, meleeBullet.HitboxSize.X, meleeBullet.HitboxSize.Y, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, "MeleeBullet")
|
||||||
space.Add(newBulletCollider)
|
space.Add(newBulletCollider)
|
||||||
bulletShape := newBulletCollider.Shape.(*resolv.ConvexPolygon)
|
bulletShape := newBulletCollider.Shape.(*resolv.ConvexPolygon)
|
||||||
Logger.Warn(fmt.Sprintf("bullet <-: Added bullet collider to space: a=%v", ConvexPolygonStr(bulletShape)))
|
Logger.Warn(fmt.Sprintf("bullet <-: Added bullet collider to space: a=%v", ConvexPolygonStr(bulletShape)))
|
||||||
|
@ -18,9 +18,13 @@ func ConvexPolygonStr(body *resolv.ConvexPolygon) string {
|
|||||||
return fmt.Sprintf("{\n%s\n}", strings.Join(s, ",\n"))
|
return fmt.Sprintf("{\n%s\n}", strings.Join(s, ",\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateRectCollider(wx, wy, w, h, bottomPadding, spaceOffsetX, spaceOffsetY float64, tag string) *resolv.Object {
|
func RectCenterStr(body *resolv.Object, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY float64) string {
|
||||||
blX, blY := WorldToPolygonColliderBLPos(wx, wy, w*0.5, h*0.5, bottomPadding, spaceOffsetX, spaceOffsetY)
|
return fmt.Sprintf("{%.2f, %.2f}", body.X + leftPadding + halfBoundingW - spaceOffsetX, body.Y + bottomPadding + halfBoundingH - spaceOffsetY)
|
||||||
return generateRectColliderInCollisionSpace(blX, blY, w, h+bottomPadding, tag)
|
}
|
||||||
|
|
||||||
|
func GenerateRectCollider(wx, wy, w, h, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY float64, tag string) *resolv.Object {
|
||||||
|
blX, blY := WorldToPolygonColliderBLPos(wx, wy, w*0.5, h*0.5, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY)
|
||||||
|
return generateRectColliderInCollisionSpace(blX, blY, leftPadding+w+rightPadding, bottomPadding+h+topPadding, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateRectColliderInCollisionSpace(blX, blY, w, h float64, tag string) *resolv.Object {
|
func generateRectColliderInCollisionSpace(blX, blY, w, h float64, tag string) *resolv.Object {
|
||||||
@ -246,38 +250,20 @@ func VirtualGridToWorldPos(vx, vy int32, virtualGridToWorldRatio float64) (float
|
|||||||
return wx, wy
|
return wx, wy
|
||||||
}
|
}
|
||||||
|
|
||||||
func WorldToPolygonColliderBLPos(wx, wy, halfBoundingW, halfBoundingH, bottomPadding, collisionSpaceOffsetX, collisionSpaceOffsetY float64) (float64, float64) {
|
func WorldToPolygonColliderBLPos(wx, wy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY float64) (float64, float64) {
|
||||||
return wx - halfBoundingW + collisionSpaceOffsetX, wy - halfBoundingH - bottomPadding + collisionSpaceOffsetY
|
return wx - halfBoundingW - leftPadding + collisionSpaceOffsetX, wy - halfBoundingH - bottomPadding + collisionSpaceOffsetY
|
||||||
}
|
}
|
||||||
|
|
||||||
func WorldToPolygonColliderTLPos(wx, wy, halfBoundingW, halfBoundingH, collisionSpaceOffsetX, collisionSpaceOffsetY float64) (float64, float64) {
|
func PolygonColliderBLToWorldPos(cx, cy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY float64) (float64, float64) {
|
||||||
return wx - halfBoundingW + collisionSpaceOffsetX, wy + halfBoundingH + collisionSpaceOffsetY
|
return cx + halfBoundingW + leftPadding - collisionSpaceOffsetX, cy + halfBoundingH + bottomPadding - collisionSpaceOffsetY
|
||||||
}
|
}
|
||||||
|
|
||||||
func PolygonColliderBLToWorldPos(cx, cy, halfBoundingW, halfBoundingH, bottomPadding, collisionSpaceOffsetX, collisionSpaceOffsetY float64) (float64, float64) {
|
func PolygonColliderBLToVirtualGridPos(cx, cy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY float64, worldToVirtualGridRatio float64) (int32, int32) {
|
||||||
return cx + halfBoundingW - collisionSpaceOffsetX, cy + halfBoundingH + bottomPadding - collisionSpaceOffsetY
|
wx, wy := PolygonColliderBLToWorldPos(cx, cy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY)
|
||||||
}
|
|
||||||
|
|
||||||
func PolygonColliderTLToWorldPos(cx, cy, halfBoundingW, halfBoundingH, collisionSpaceOffsetX, collisionSpaceOffsetY float64) (float64, float64) {
|
|
||||||
return cx + halfBoundingW - collisionSpaceOffsetX, cy - halfBoundingH - collisionSpaceOffsetY
|
|
||||||
}
|
|
||||||
|
|
||||||
func PolygonColliderBLToVirtualGridPos(cx, cy, halfBoundingW, halfBoundingH, bottomPadding, collisionSpaceOffsetX, collisionSpaceOffsetY float64, worldToVirtualGridRatio float64) (int32, int32) {
|
|
||||||
wx, wy := PolygonColliderBLToWorldPos(cx, cy, halfBoundingW, halfBoundingH, bottomPadding, collisionSpaceOffsetX, collisionSpaceOffsetY)
|
|
||||||
return WorldToVirtualGridPos(wx, wy, worldToVirtualGridRatio)
|
return WorldToVirtualGridPos(wx, wy, worldToVirtualGridRatio)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PolygonColliderTLToVirtualGridPos(cx, cy, halfBoundingW, halfBoundingH, collisionSpaceOffsetX, collisionSpaceOffsetY float64, worldToVirtualGridRatio float64) (int32, int32) {
|
func VirtualGridToPolygonColliderBLPos(vx, vy int32, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY float64, virtualGridToWorldRatio float64) (float64, float64) {
|
||||||
wx, wy := PolygonColliderTLToWorldPos(cx, cy, halfBoundingW, halfBoundingH, collisionSpaceOffsetX, collisionSpaceOffsetY)
|
|
||||||
return WorldToVirtualGridPos(wx, wy, worldToVirtualGridRatio)
|
|
||||||
}
|
|
||||||
|
|
||||||
func VirtualGridToPolygonColliderBLPos(vx, vy int32, halfBoundingW, halfBoundingH, bottomPadding, collisionSpaceOffsetX, collisionSpaceOffsetY float64, virtualGridToWorldRatio float64) (float64, float64) {
|
|
||||||
wx, wy := VirtualGridToWorldPos(vx, vy, virtualGridToWorldRatio)
|
wx, wy := VirtualGridToWorldPos(vx, vy, virtualGridToWorldRatio)
|
||||||
return WorldToPolygonColliderBLPos(wx, wy, halfBoundingW, halfBoundingH, bottomPadding, collisionSpaceOffsetX, collisionSpaceOffsetY)
|
return WorldToPolygonColliderBLPos(wx, wy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY)
|
||||||
}
|
|
||||||
|
|
||||||
func VirtualGridToPolygonColliderTLPos(vx, vy int32, halfBoundingW, halfBoundingH, collisionSpaceOffsetX, collisionSpaceOffsetY float64, virtualGridToWorldRatio float64) (float64, float64) {
|
|
||||||
wx, wy := VirtualGridToWorldPos(vx, vy, virtualGridToWorldRatio)
|
|
||||||
return WorldToPolygonColliderTLPos(wx, wy, halfBoundingW, halfBoundingH, collisionSpaceOffsetX, collisionSpaceOffsetY)
|
|
||||||
}
|
}
|
||||||
|
@ -440,7 +440,7 @@
|
|||||||
"array": [
|
"array": [
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
216.19964242526865,
|
216.50635094610968,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
@ -454,7 +454,7 @@
|
|||||||
"array": [
|
"array": [
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
216.67520680312998,
|
216.50635094610968,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
@ -784,10 +784,16 @@ cc.Class({
|
|||||||
const [wx, wy] = self.virtualGridToWorldPos(vx, vy);
|
const [wx, wy] = self.virtualGridToWorldPos(vx, vy);
|
||||||
newPlayerNode.setPosition(wx, wy);
|
newPlayerNode.setPosition(wx, wy);
|
||||||
playerScriptIns.mapNode = self.node;
|
playerScriptIns.mapNode = self.node;
|
||||||
const colliderWidth = playerDownsyncInfo.colliderRadius * 2,
|
const halfColliderWidth = playerDownsyncInfo.colliderRadius,
|
||||||
colliderHeight = playerDownsyncInfo.colliderRadius * 4;
|
halfColliderHeight = playerDownsyncInfo.colliderRadius + playerDownsyncInfo.colliderRadius; // avoid multiplying
|
||||||
const cpos = self.virtualGridToPolygonColliderTLPos(vx, vy, colliderWidth * 0.5, colliderHeight * 0.5); // the top-left corner is kept having integer coords
|
const colliderWidth = halfColliderWidth + halfColliderWidth,
|
||||||
const pts = [[0, 0], [colliderWidth, 0], [colliderWidth, -colliderHeight - self.snapIntoPlatformOverlap], [0, -colliderHeight - self.snapIntoPlatformOverlap]];
|
colliderHeight = halfColliderHeight + halfColliderHeight; // avoid multiplying
|
||||||
|
const leftPadding = self.snapIntoPlatformOverlap,
|
||||||
|
rightPadding = self.snapIntoPlatformOverlap,
|
||||||
|
topPadding = self.snapIntoPlatformOverlap,
|
||||||
|
bottomPadding = self.snapIntoPlatformOverlap;
|
||||||
|
const cpos = self.virtualGridToPolygonColliderBLPos(vx, vy, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding); // the collider center is kept having integer coords
|
||||||
|
const pts = [[0, 0], [leftPadding + colliderWidth + rightPadding, 0], [leftPadding + colliderWidth + rightPadding, bottomPadding + colliderHeight + topPadding], [0, bottomPadding + colliderHeight + topPadding]];
|
||||||
|
|
||||||
// [WARNING] The animNode "anchor & offset" are tuned to fit in this collider by "ControlledCharacter prefab & AttackingCharacter.js"!
|
// [WARNING] The animNode "anchor & offset" are tuned to fit in this collider by "ControlledCharacter prefab & AttackingCharacter.js"!
|
||||||
const newPlayerCollider = self.collisionSys.createPolygon(cpos[0], cpos[1], pts);
|
const newPlayerCollider = self.collisionSys.createPolygon(cpos[0], cpos[1], pts);
|
||||||
@ -997,6 +1003,10 @@ cc.Class({
|
|||||||
|
|
||||||
showDebugBoundaries(rdf) {
|
showDebugBoundaries(rdf) {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
const leftPadding = self.snapIntoPlatformOverlap,
|
||||||
|
rightPadding = self.snapIntoPlatformOverlap,
|
||||||
|
topPadding = self.snapIntoPlatformOverlap,
|
||||||
|
bottomPadding = self.snapIntoPlatformOverlap;
|
||||||
if (self.showCriticalCoordinateLabels) {
|
if (self.showCriticalCoordinateLabels) {
|
||||||
let g = self.g;
|
let g = self.g;
|
||||||
g.clear();
|
g.clear();
|
||||||
@ -1048,8 +1058,10 @@ cc.Class({
|
|||||||
const [offenderWx, offenderWy] = self.virtualGridToWorldPos(offender.virtualGridX, offender.virtualGridY);
|
const [offenderWx, offenderWy] = self.virtualGridToWorldPos(offender.virtualGridX, offender.virtualGridY);
|
||||||
const bulletWx = offenderWx + xfac * meleeBullet.hitboxOffset;
|
const bulletWx = offenderWx + xfac * meleeBullet.hitboxOffset;
|
||||||
const bulletWy = offenderWy;
|
const bulletWy = offenderWy;
|
||||||
const bulletCpos = self.worldToPolygonColliderTLPos(bulletWx, bulletWy, meleeBullet.hitboxSize.x * 0.5, meleeBullet.hitboxSize.y * 0.5);
|
const halfColliderWidth = meleeBullet.hitboxSize.x * 0.5,
|
||||||
const pts = [[0, 0], [meleeBullet.hitboxSize.x, 0], [meleeBullet.hitboxSize.x, -meleeBullet.hitboxSize.y], [0, -meleeBullet.hitboxSize.y]];
|
halfColliderHeight = meleeBullet.hitboxSize.y * 0.5; // avoid multiplying
|
||||||
|
const bulletCpos = self.worldToPolygonColliderBLPos(bulletWx, bulletWy, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding);
|
||||||
|
const pts = [[0, 0], [leftPadding + meleeBullet.hitboxSize.x + rightPadding, 0], [leftPadding + meleeBullet.hitboxSize.x + rightPadding, bottomPadding + meleeBullet.hitboxSize.y + topPadding], [0, bottomPadding + meleeBullet.hitboxSize.y + topPadding]];
|
||||||
|
|
||||||
g.moveTo(bulletCpos[0], bulletCpos[1]);
|
g.moveTo(bulletCpos[0], bulletCpos[1]);
|
||||||
for (let j = 0; j < pts.length; j += 1) {
|
for (let j = 0; j < pts.length; j += 1) {
|
||||||
@ -1079,6 +1091,10 @@ cc.Class({
|
|||||||
// TODO: Write unit-test for this function to compare with its backend counter part
|
// TODO: Write unit-test for this function to compare with its backend counter part
|
||||||
applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame, currRenderFrame, collisionSys, collisionSysMap) {
|
applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame, currRenderFrame, collisionSys, collisionSysMap) {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
const leftPadding = self.snapIntoPlatformOverlap,
|
||||||
|
rightPadding = self.snapIntoPlatformOverlap,
|
||||||
|
topPadding = self.snapIntoPlatformOverlap,
|
||||||
|
bottomPadding = self.snapIntoPlatformOverlap;
|
||||||
const nextRenderFramePlayers = {};
|
const nextRenderFramePlayers = {};
|
||||||
for (let playerId in currRenderFrame.players) {
|
for (let playerId in currRenderFrame.players) {
|
||||||
const currPlayerDownsync = currRenderFrame.players[playerId];
|
const currPlayerDownsync = currRenderFrame.players[playerId];
|
||||||
@ -1188,10 +1204,14 @@ cc.Class({
|
|||||||
const currPlayerDownsync = currRenderFrame.players[playerId];
|
const currPlayerDownsync = currRenderFrame.players[playerId];
|
||||||
const thatPlayerInNextFrame = nextRenderFramePlayers[playerId];
|
const thatPlayerInNextFrame = nextRenderFramePlayers[playerId];
|
||||||
// Reset playerCollider position from the "virtual grid position"
|
// Reset playerCollider position from the "virtual grid position"
|
||||||
const [newVx, newVy] = [currPlayerDownsync.virtualGridX + currPlayerDownsync.velX, currPlayerDownsync.virtualGridY + currPlayerDownsync.velY];
|
const newVpos = [currPlayerDownsync.virtualGridX + currPlayerDownsync.velX, currPlayerDownsync.virtualGridY + currPlayerDownsync.velY];
|
||||||
const colliderWidth = self.playerRichInfoArr[joinIndex - 1].colliderRadius * 2,
|
if (thatPlayerInNextFrame.velY == self.jumpingInitVelY) {
|
||||||
colliderHeight = self.playerRichInfoArr[joinIndex - 1].colliderRadius * 4;
|
// This step can be waived, but putting the jumping inclination here makes it easier to read logs.
|
||||||
const newCpos = self.virtualGridToPolygonColliderTLPos(newVx, newVy, colliderWidth * 0.5, colliderHeight * 0.5);
|
newVpos[1] += self.jumpingInitVelY;
|
||||||
|
}
|
||||||
|
const halfColliderWidth = self.playerRichInfoArr[j].colliderRadius,
|
||||||
|
halfColliderHeight = self.playerRichInfoArr[j].colliderRadius + self.playerRichInfoArr[j].colliderRadius; // avoid multiplying
|
||||||
|
const newCpos = self.virtualGridToPolygonColliderBLPos(newVpos[0], newVpos[1], halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding);
|
||||||
playerCollider.x = newCpos[0];
|
playerCollider.x = newCpos[0];
|
||||||
playerCollider.y = newCpos[1];
|
playerCollider.y = newCpos[1];
|
||||||
|
|
||||||
@ -1223,8 +1243,10 @@ cc.Class({
|
|||||||
const [offenderWx, offenderWy] = self.virtualGridToWorldPos(offender.virtualGridX, offender.virtualGridY);
|
const [offenderWx, offenderWy] = self.virtualGridToWorldPos(offender.virtualGridX, offender.virtualGridY);
|
||||||
const bulletWx = offenderWx + xfac * meleeBullet.hitboxOffset;
|
const bulletWx = offenderWx + xfac * meleeBullet.hitboxOffset;
|
||||||
const bulletWy = offenderWy;
|
const bulletWy = offenderWy;
|
||||||
const bulletCpos = self.worldToPolygonColliderTLPos(bulletWx, bulletWy, meleeBullet.hitboxSize.x * 0.5, meleeBullet.hitboxSize.y * 0.5),
|
const halfColliderWidth = meleeBullet.hitboxSize.x * 0.5,
|
||||||
pts = [[0, 0], [meleeBullet.hitboxSize.x, 0], [meleeBullet.hitboxSize.x, -meleeBullet.hitboxSize.y], [0, -meleeBullet.hitboxSize.y]];
|
halfColliderHeight = meleeBullet.hitboxSize.y * 0.5;
|
||||||
|
const bulletCpos = self.worldToPolygonColliderBLPos(bulletWx, bulletWy, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding);
|
||||||
|
const pts = [[0, 0], [leftPadding + meleeBullet.hitboxSize.x + rightPadding, 0], [leftPadding + meleeBullet.hitboxSize.x + rightPadding, bottomPadding + meleeBullet.hitboxSize.y + topPadding], [0, bottomPadding + meleeBullet.hitboxSize.y + topPadding]];
|
||||||
const newBulletCollider = collisionSys.createPolygon(bulletCpos[0], bulletCpos[1], pts);
|
const newBulletCollider = collisionSys.createPolygon(bulletCpos[0], bulletCpos[1], pts);
|
||||||
newBulletCollider.data = meleeBullet;
|
newBulletCollider.data = meleeBullet;
|
||||||
collisionSysMap.set(collisionBulletIndex, newBulletCollider);
|
collisionSysMap.set(collisionBulletIndex, newBulletCollider);
|
||||||
@ -1248,6 +1270,9 @@ cc.Class({
|
|||||||
|
|
||||||
const currPlayerDownsync = currRenderFrame.players[playerId];
|
const currPlayerDownsync = currRenderFrame.players[playerId];
|
||||||
const thatPlayerInNextFrame = nextRenderFramePlayers[playerId];
|
const thatPlayerInNextFrame = nextRenderFramePlayers[playerId];
|
||||||
|
const halfColliderWidth = self.playerRichInfoArr[j].colliderRadius,
|
||||||
|
halfColliderHeight = self.playerRichInfoArr[j].colliderRadius + self.playerRichInfoArr[j].colliderRadius; // avoid multiplying
|
||||||
|
|
||||||
let fallStopping = false;
|
let fallStopping = false;
|
||||||
let possiblyFallStoppedOnAnotherPlayer = false;
|
let possiblyFallStoppedOnAnotherPlayer = false;
|
||||||
for (const potential of potentials) {
|
for (const potential of potentials) {
|
||||||
@ -1261,10 +1286,16 @@ cc.Class({
|
|||||||
const landedOnGravityPushback = (self.snapIntoPlatformThreshold < normAlignmentWithGravity); // prevents false snapping on the lateral sides
|
const landedOnGravityPushback = (self.snapIntoPlatformThreshold < normAlignmentWithGravity); // prevents false snapping on the lateral sides
|
||||||
let pushback = [result.overlap * result.overlap_x, result.overlap * result.overlap_y];
|
let pushback = [result.overlap * result.overlap_x, result.overlap * result.overlap_y];
|
||||||
if (landedOnGravityPushback) {
|
if (landedOnGravityPushback) {
|
||||||
// kindly note that one player might land on top of another player, and snapping is also required in such case
|
// kindly note that one player might land on top of another player
|
||||||
pushback = [(result.overlap - self.snapIntoPlatformOverlap) * result.overlap_x, (result.overlap - self.snapIntoPlatformOverlap) * result.overlap_y];
|
pushback = [(result.overlap - self.snapIntoPlatformOverlap) * result.overlap_x, (result.overlap - self.snapIntoPlatformOverlap) * result.overlap_y];
|
||||||
thatPlayerInNextFrame.inAir = false;
|
thatPlayerInNextFrame.inAir = false;
|
||||||
}
|
}
|
||||||
|
if (isAnotherPlayer) {
|
||||||
|
/*
|
||||||
|
[WARNING] The "zero overlap collision" might be randomly detected/missed on either frontend or backend, to have deterministic result we added paddings to all sides of a playerCollider. As each velocity component of (velX, velY) being a multiple of 0.5 at any renderFrame, each position component of (x, y) can only be a multiple of 0.5 too, thus whenever a 1-dimensional collision happens between players from [player#1: i*0.5, player#2: j*0.5, not collided yet] to [player#1: (i+k)*0.5, player#2: j*0.5, collided], the overlap becomes (i+k-j)*0.5+2*s, and after snapping subtraction the effPushback magnitude for each player is (i+k-j)*0.5, resulting in 0.5-multiples-position for the next renderFrame.
|
||||||
|
*/
|
||||||
|
pushback = [(result.overlap - self.snapIntoPlatformOverlap * 2) * result.overlap_x, (result.overlap - self.snapIntoPlatformOverlap * 2) * result.overlap_y]; // will overwrite the previous pushback value if "landedOnGravityPushback" is also true
|
||||||
|
}
|
||||||
for (let hardPushbackNorm of hardPushbackNorms[joinIndex - 1]) {
|
for (let hardPushbackNorm of hardPushbackNorms[joinIndex - 1]) {
|
||||||
// remove pushback component on the directions of "hardPushbackNorms[joinIndex-1]" (by now those hardPushbacks are already accounted in "effPushbacks[joinIndex-1]")
|
// remove pushback component on the directions of "hardPushbackNorms[joinIndex-1]" (by now those hardPushbacks are already accounted in "effPushbacks[joinIndex-1]")
|
||||||
const projectedMagnitude = pushback[0] * hardPushbackNorm[0] + pushback[1] * hardPushbackNorm[1];
|
const projectedMagnitude = pushback[0] * hardPushbackNorm[0] + pushback[1] * hardPushbackNorm[1];
|
||||||
@ -1281,22 +1312,28 @@ cc.Class({
|
|||||||
|
|
||||||
effPushbacks[joinIndex - 1][0] += pushback[0];
|
effPushbacks[joinIndex - 1][0] += pushback[0];
|
||||||
effPushbacks[joinIndex - 1][1] += pushback[1];
|
effPushbacks[joinIndex - 1][1] += pushback[1];
|
||||||
|
// It's not meaningful to log the virtual positions and velocities inside this step.
|
||||||
if (currPlayerDownsync.inAir && landedOnGravityPushback) {
|
if (currPlayerDownsync.inAir && landedOnGravityPushback) {
|
||||||
fallStopping = true;
|
fallStopping = true;
|
||||||
if (isAnotherPlayer) {
|
if (isAnotherPlayer) {
|
||||||
possiblyFallStoppedOnAnotherPlayer = true;
|
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}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (1 == joinIndex && currPlayerDownsync.inAir && isBarrier && !landedOnGravityPushback) {
|
if (1 == joinIndex) {
|
||||||
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 (fallStopping) {
|
||||||
|
console.info(`playerId=${playerId}, joinIndex=${thatPlayerInNextFrame.joinIndex} fallStopping#1:
|
||||||
|
{renderFrame.id: ${currRenderFrame.id}, possiblyFallStoppedOnAnotherPlayer: ${possiblyFallStoppedOnAnotherPlayer}}
|
||||||
|
playerColliderPos=${self.stringifyColliderCenterInWorld(playerCollider, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding)}, effPushback={${effPushbacks[joinIndex - 1][0].toFixed(3)}, ${effPushbacks[joinIndex - 1][1].toFixed(3)}}, overlayMag=${result.overlap.toFixed(4)}`);
|
||||||
|
} else if (currPlayerDownsync.inAir && isBarrier && !landedOnGravityPushback) {
|
||||||
|
console.warn(`playerId=${playerId}, joinIndex=${currPlayerDownsync.joinIndex} inAir & pushed back by barrier & not landed:
|
||||||
|
{renderFrame.id: ${currRenderFrame.id}}
|
||||||
|
playerColliderPos=${self.stringifyColliderCenterInWorld(playerCollider, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding)}, effPushback={${effPushbacks[joinIndex - 1][0].toFixed(3)}, ${effPushbacks[joinIndex - 1][1].toFixed(3)}}, overlayMag=${result.overlap.toFixed(4)}, len(hardPushbackNorms)=${hardPushbackNorms.length}`);
|
||||||
|
} else if (currPlayerDownsync.inAir && isAnotherPlayer) {
|
||||||
|
console.warn(`playerId=${playerId}, joinIndex=${currPlayerDownsync.joinIndex} inAir and pushed back by another player
|
||||||
|
{renderFrame.id: ${currRenderFrame.id}}
|
||||||
|
playerColliderPos=${self.stringifyColliderCenterInWorld(playerCollider, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding)}, anotherPlayerColliderPos=${self.stringifyColliderCenterInWorld(potential, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding)}, effPushback={${effPushbacks[joinIndex - 1][0].toFixed(3)}, ${effPushbacks[joinIndex - 1][1].toFixed(3)}}, landedOnGravityPushback=${landedOnGravityPushback}, fallStopping=${fallStopping}, 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}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1378,21 +1415,27 @@ cc.Class({
|
|||||||
// Update "virtual grid position"
|
// Update "virtual grid position"
|
||||||
const currPlayerDownsync = currRenderFrame.players[playerId];
|
const currPlayerDownsync = currRenderFrame.players[playerId];
|
||||||
const thatPlayerInNextFrame = nextRenderFramePlayers[playerId];
|
const thatPlayerInNextFrame = nextRenderFramePlayers[playerId];
|
||||||
const colliderWidth = self.playerRichInfoArr[joinIndex - 1].colliderRadius * 2,
|
const halfColliderWidth = self.playerRichInfoArr[j].colliderRadius,
|
||||||
colliderHeight = self.playerRichInfoArr[joinIndex - 1].colliderRadius * 4;
|
halfColliderHeight = self.playerRichInfoArr[j].colliderRadius + self.playerRichInfoArr[j].colliderRadius; // avoid multiplying
|
||||||
const newVpos = self.polygonColliderTLToVirtualGridPos(playerCollider.x - effPushbacks[joinIndex - 1][0], playerCollider.y - effPushbacks[joinIndex - 1][1], colliderWidth * 0.5, colliderHeight * 0.5);
|
const newVpos = self.polygonColliderBLToVirtualGridPos(playerCollider.x - effPushbacks[joinIndex - 1][0], playerCollider.y - effPushbacks[joinIndex - 1][1], halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding);
|
||||||
thatPlayerInNextFrame.virtualGridX = newVpos[0];
|
thatPlayerInNextFrame.virtualGridX = newVpos[0];
|
||||||
thatPlayerInNextFrame.virtualGridY = newVpos[1];
|
thatPlayerInNextFrame.virtualGridY = newVpos[1];
|
||||||
|
|
||||||
if (1 == thatPlayerInNextFrame.joinIndex) {
|
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) {
|
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)}}`);
|
console.warn(`playerId=${playerId}, joinIndex=${thatPlayerInNextFrame.joinIndex} fallStopping#2:
|
||||||
}
|
{nextRenderFrame.id: ${currRenderFrame.id + 1}, nextVirtualX: ${thatPlayerInNextFrame.virtualGridX}, nextVirtualY: ${thatPlayerInNextFrame.virtualGridY}, nextVelX: ${thatPlayerInNextFrame.velX}, nextVelY: ${thatPlayerInNextFrame.velY}}
|
||||||
if (!currPlayerDownsync.inAir && thatPlayerInNextFrame.inAir) {
|
calculated from <- playerColliderPos=${self.stringifyColliderCenterInWorld(playerCollider, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding)}, effPushback={${effPushbacks[joinIndex - 1][0].toFixed(3)}, ${effPushbacks[joinIndex - 1][1].toFixed(3)}}`);
|
||||||
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)}}`);
|
} else if (!currPlayerDownsync.inAir && thatPlayerInNextFrame.inAir) {
|
||||||
|
console.warn(`playerId=${playerId}, joinIndex=${thatPlayerInNextFrame.joinIndex} took off:
|
||||||
|
{nextRenderFrame.id: ${currRenderFrame.id + 1}, nextVirtualX: ${thatPlayerInNextFrame.virtualGridX}, nextVirtualY: ${thatPlayerInNextFrame.virtualGridY}, nextVelX: ${thatPlayerInNextFrame.velX}, nextVelY: ${thatPlayerInNextFrame.velY}}
|
||||||
|
calculated from <- playerColliderPos=${self.stringifyColliderCenterInWorld(playerCollider, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding)}, effPushback={${effPushbacks[joinIndex - 1][0].toFixed(3)}, ${effPushbacks[joinIndex - 1][1].toFixed(3)}}`);
|
||||||
|
} else 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}};
|
||||||
|
calculated from <- playerColliderPos=${self.stringifyColliderCenterInWorld(playerCollider, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding)}, effPushback={${effPushbacks[joinIndex - 1][0].toFixed(3)}, ${effPushbacks[joinIndex - 1][1].toFixed(3)}}`);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1457,16 +1500,16 @@ cc.Class({
|
|||||||
const immediatePlayerInfo = players[playerId];
|
const immediatePlayerInfo = players[playerId];
|
||||||
self.playerRichInfoDict.set(playerId, immediatePlayerInfo);
|
self.playerRichInfoDict.set(playerId, immediatePlayerInfo);
|
||||||
|
|
||||||
const [theNode, theScriptIns] = self.spawnPlayerNode(immediatePlayerInfo.joinIndex, immediatePlayerInfo.virtualGridX, immediatePlayerInfo.virtualGridY, immediatePlayerInfo);
|
const nodeAndScriptIns = self.spawnPlayerNode(immediatePlayerInfo.joinIndex, immediatePlayerInfo.virtualGridX, immediatePlayerInfo.virtualGridY, immediatePlayerInfo);
|
||||||
|
|
||||||
Object.assign(self.playerRichInfoDict.get(playerId), {
|
Object.assign(self.playerRichInfoDict.get(playerId), {
|
||||||
node: theNode,
|
node: nodeAndScriptIns[0],
|
||||||
scriptIns: theScriptIns,
|
scriptIns: nodeAndScriptIns[1],
|
||||||
});
|
});
|
||||||
|
|
||||||
if (self.selfPlayerInfo.id == playerId) {
|
if (self.selfPlayerInfo.id == playerId) {
|
||||||
self.selfPlayerInfo = Object.assign(self.selfPlayerInfo, immediatePlayerInfo);
|
self.selfPlayerInfo = Object.assign(self.selfPlayerInfo, immediatePlayerInfo);
|
||||||
theScriptIns.showArrowTipNode();
|
nodeAndScriptIns[1].showArrowTipNode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.playerRichInfoArr = new Array(self.playerRichInfoDict.size);
|
self.playerRichInfoArr = new Array(self.playerRichInfoDict.size);
|
||||||
@ -1513,29 +1556,31 @@ cc.Class({
|
|||||||
virtualGridToWorldPos(vx, vy) {
|
virtualGridToWorldPos(vx, vy) {
|
||||||
// No loss of precision
|
// No loss of precision
|
||||||
const self = this;
|
const self = this;
|
||||||
let wx = parseFloat(vx) * self.virtualGridToWorldRatio;
|
return [vx * self.virtualGridToWorldRatio, vy * self.virtualGridToWorldRatio];
|
||||||
let wy = parseFloat(vy) * self.virtualGridToWorldRatio;
|
|
||||||
return [wx, wy];
|
|
||||||
},
|
},
|
||||||
|
|
||||||
worldToPolygonColliderTLPos(wx, wy, halfBoundingW, halfBoundingH) {
|
worldToPolygonColliderBLPos(wx, wy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding) {
|
||||||
return [wx - halfBoundingW, wy + halfBoundingH];
|
return [wx - halfBoundingW - leftPadding, wy - halfBoundingH - bottomPadding];
|
||||||
},
|
},
|
||||||
|
|
||||||
polygonColliderTLToWorldPos(cx, cy, halfBoundingW, halfBoundingH) {
|
polygonColliderBLToWorldPos(cx, cy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding) {
|
||||||
return [cx + halfBoundingW, cy - halfBoundingH];
|
return [cx + halfBoundingW + leftPadding, cy + halfBoundingH + bottomPadding];
|
||||||
},
|
},
|
||||||
|
|
||||||
polygonColliderTLToVirtualGridPos(cx, cy, halfBoundingW, halfBoundingH) {
|
polygonColliderBLToVirtualGridPos(cx, cy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding) {
|
||||||
const self = this;
|
const self = this;
|
||||||
const [wx, wy] = self.polygonColliderTLToWorldPos(cx, cy, halfBoundingW, halfBoundingH);
|
const [wx, wy] = self.polygonColliderBLToWorldPos(cx, cy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding);
|
||||||
return self.worldToVirtualGridPos(wx, wy)
|
return self.worldToVirtualGridPos(wx, wy)
|
||||||
},
|
},
|
||||||
|
|
||||||
virtualGridToPolygonColliderTLPos(vx, vy, halfBoundingW, halfBoundingH) {
|
virtualGridToPolygonColliderBLPos(vx, vy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding) {
|
||||||
const self = this;
|
const self = this;
|
||||||
const [wx, wy] = self.virtualGridToWorldPos(vx, vy);
|
const [wx, wy] = self.virtualGridToWorldPos(vx, vy);
|
||||||
return self.worldToPolygonColliderTLPos(wx, wy, halfBoundingW, halfBoundingH)
|
return self.worldToPolygonColliderBLPos(wx, wy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding)
|
||||||
|
},
|
||||||
|
|
||||||
|
stringifyColliderCenterInWorld(playerCollider, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding) {
|
||||||
|
return `{${(playerCollider.x + leftPadding + halfBoundingW).toFixed(2)}, ${(playerCollider.y + bottomPadding + halfBoundingH).toFixed(2)}}`;
|
||||||
},
|
},
|
||||||
|
|
||||||
calcHardPushbacksNorms(collider, potentials, result, snapIntoPlatformOverlap, effPushback) {
|
calcHardPushbacksNorms(collider, potentials, result, snapIntoPlatformOverlap, effPushback) {
|
||||||
@ -1546,11 +1591,10 @@ cc.Class({
|
|||||||
if (!collider.collides(potential, result)) continue;
|
if (!collider.collides(potential, result)) continue;
|
||||||
// ALWAY snap into hardPushbacks!
|
// ALWAY snap into hardPushbacks!
|
||||||
// [overlay_x, overlap_y] is the unit vector that points into the platform
|
// [overlay_x, overlap_y] is the unit vector that points into the platform
|
||||||
const [pushbackX, pushbackY] = [(result.overlap - snapIntoPlatformOverlap) * result.overlap_x, (result.overlap - snapIntoPlatformOverlap) * result.overlap_y];
|
const pushback = [(result.overlap - snapIntoPlatformOverlap) * result.overlap_x, (result.overlap - snapIntoPlatformOverlap) * result.overlap_y];
|
||||||
|
|
||||||
ret.push([result.overlap_x, result.overlap_y]);
|
ret.push([result.overlap_x, result.overlap_y]);
|
||||||
effPushback[0] += pushbackX;
|
effPushback[0] += pushback[0];
|
||||||
effPushback[1] += pushbackY;
|
effPushback[1] += pushback[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -196,7 +196,7 @@ cc.Class({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.selfPlayerInfo = {
|
self.selfPlayerInfo = {
|
||||||
id: 11
|
id: 10
|
||||||
};
|
};
|
||||||
self._initPlayerRichInfoDict(startRdf.players);
|
self._initPlayerRichInfoDict(startRdf.players);
|
||||||
self.onRoomDownsyncFrame(startRdf);
|
self.onRoomDownsyncFrame(startRdf);
|
||||||
|
Loading…
Reference in New Issue
Block a user