Minor update to floating number precision.

This commit is contained in:
genxium 2022-11-08 21:38:23 +08:00
parent 1a3b3a0a7a
commit f37f4337de
2 changed files with 56 additions and 43 deletions

View File

@ -128,11 +128,12 @@ func calRoomScore(inRoomPlayerCount int32, roomPlayerCnt int, currentRoomBattleS
} }
type Room struct { type Room struct {
Id int32 Id int32
Capacity int Capacity int
Players map[int32]*Player playerColliderRadius float64
PlayersArr []*Player // ordered by joinIndex Players map[int32]*Player
CollisionSysMap map[int32]*resolv.Object PlayersArr []*Player // ordered by joinIndex
CollisionSysMap map[int32]*resolv.Object
/** /**
* The following `PlayerDownsyncSessionDict` is NOT individually put * The following `PlayerDownsyncSessionDict` is NOT individually put
* under `type Player struct` for a reason. * under `type Player struct` for a reason.
@ -415,7 +416,12 @@ func (pR *Room) StartBattle() {
pR.RenderFrameBuffer.Put(kickoffFrame) pR.RenderFrameBuffer.Put(kickoffFrame)
// Refresh "Colliders" // Refresh "Colliders"
pR.refreshColliders() spaceW := pR.StageDiscreteW * pR.StageTileW
spaceH := pR.StageDiscreteH * pR.StageTileH
spaceOffsetX := float64(spaceW) * 0.5
spaceOffsetY := float64(spaceH) * 0.5
pR.refreshColliders(spaceW, spaceH, spaceOffsetX, spaceOffsetY)
/** /**
* 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.
@ -488,7 +494,7 @@ func (pR *Room) StartBattle() {
// Apply "all-confirmed inputFrames" to move forward "pR.CurDynamicsRenderFrameId" // Apply "all-confirmed inputFrames" to move forward "pR.CurDynamicsRenderFrameId"
nextDynamicsRenderFrameId := pR.ConvertToLastUsedRenderFrameId(pR.LastAllConfirmedInputFrameId, pR.InputDelayFrames) nextDynamicsRenderFrameId := pR.ConvertToLastUsedRenderFrameId(pR.LastAllConfirmedInputFrameId, pR.InputDelayFrames)
Logger.Debug(fmt.Sprintf("roomId=%v, room.RenderFrameId=%v, LastAllConfirmedInputFrameId=%v, InputDelayFrames=%v, nextDynamicsRenderFrameId=%v", pR.Id, pR.RenderFrameId, pR.LastAllConfirmedInputFrameId, pR.InputDelayFrames, nextDynamicsRenderFrameId)) Logger.Debug(fmt.Sprintf("roomId=%v, room.RenderFrameId=%v, LastAllConfirmedInputFrameId=%v, InputDelayFrames=%v, nextDynamicsRenderFrameId=%v", pR.Id, pR.RenderFrameId, pR.LastAllConfirmedInputFrameId, pR.InputDelayFrames, nextDynamicsRenderFrameId))
pR.applyInputFrameDownsyncDynamics(pR.CurDynamicsRenderFrameId, nextDynamicsRenderFrameId) pR.applyInputFrameDownsyncDynamics(pR.CurDynamicsRenderFrameId, nextDynamicsRenderFrameId, spaceOffsetX, spaceOffsetY)
dynamicsDuration = utils.UnixtimeNano() - dynamicsStartedAt dynamicsDuration = utils.UnixtimeNano() - dynamicsStartedAt
} }
@ -792,6 +798,7 @@ func (pR *Room) Dismiss() {
func (pR *Room) OnDismissed() { func (pR *Room) OnDismissed() {
// Always instantiates new HeapRAM blocks and let the old blocks die out due to not being retained by any root reference. // Always instantiates new HeapRAM blocks and let the old blocks die out due to not being retained by any root reference.
pR.playerColliderRadius = float64(12) // hardcoded
pR.Players = make(map[int32]*Player) pR.Players = make(map[int32]*Player)
pR.PlayersArr = make([]*Player, pR.Capacity) pR.PlayersArr = make([]*Player, pR.Capacity)
pR.CollisionSysMap = make(map[int32]*resolv.Object) pR.CollisionSysMap = make(map[int32]*resolv.Object)
@ -1175,7 +1182,7 @@ func (pR *Room) forceConfirmationIfApplicable() uint64 {
return unconfirmedMask return unconfirmedMask
} }
func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRenderFrameId int32) { func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRenderFrameId int32, spaceOffsetX, spaceOffsetY float64) {
if fromRenderFrameId >= toRenderFrameId { if fromRenderFrameId >= toRenderFrameId {
return return
} }
@ -1216,26 +1223,27 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende
playerCollider := pR.CollisionSysMap[collisionPlayerIndex] playerCollider := pR.CollisionSysMap[collisionPlayerIndex]
if collision := playerCollider.Check(oldDx, oldDy, "Barrier"); collision != nil { if collision := playerCollider.Check(oldDx, oldDy, "Barrier"); collision != nil {
playerShape := playerCollider.Shape.(*resolv.ConvexPolygon) playerShape := playerCollider.Shape.(*resolv.ConvexPolygon)
for _, obj := range collision.Objects { for _, obj := range collision.Objects {
barrierShape := obj.Shape.(*resolv.ConvexPolygon) barrierShape := obj.Shape.(*resolv.ConvexPolygon)
if overlapped, pushbackX, pushbackY := CalcPushbacks(oldDx, oldDy, playerShape, barrierShape); overlapped { if overlapped, pushbackX, pushbackY := CalcPushbacks(oldDx, oldDy, playerShape, barrierShape); overlapped {
Logger.Debug(fmt.Sprintf("Collided & overlapped: player.X=%v, player.Y=%v, oldDx=%v, oldDy=%v, playerShape=%v, toCheckBarrier=%v, pushbackX=%v, pushbackY=%v", playerCollider.X, playerCollider.Y, oldDx, oldDy, ConvexPolygonStr(playerShape), ConvexPolygonStr(barrierShape), pushbackX, pushbackY)) Logger.Debug(fmt.Sprintf("Collided & overlapped: player.X=%v, player.Y=%v, oldDx=%v, oldDy=%v, playerShape=%v, toCheckBarrier=%v, pushbackX=%v, pushbackY=%v", playerCollider.X, playerCollider.Y, oldDx, oldDy, ConvexPolygonStr(playerShape), ConvexPolygonStr(barrierShape), pushbackX, pushbackY))
dx -= pushbackX dx -= pushbackX
dy -= pushbackY dy -= pushbackY
} else { } else {
Logger.Debug(fmt.Sprintf("Collided BUT not overlapped: player.X=%v, player.Y=%v, oldDx=%v, oldDy=%v, playerShape=%v, toCheckBarrier=%v", playerCollider.X, playerCollider.Y, oldDx, oldDy, ConvexPolygonStr(playerShape), ConvexPolygonStr(barrierShape))) Logger.Debug(fmt.Sprintf("Collided BUT not overlapped: player.X=%v, player.Y=%v, oldDx=%v, oldDy=%v, playerShape=%v, toCheckBarrier=%v", playerCollider.X, playerCollider.Y, oldDx, oldDy, ConvexPolygonStr(playerShape), ConvexPolygonStr(barrierShape)))
} }
} }
} }
playerCollider.X += dx playerCollider.X += dx
playerCollider.Y += dy playerCollider.Y += dy
// Update in "collision space" // Update in "collision space"
playerCollider.Update() playerCollider.Update()
player.Dir.Dx = decodedInput[0] player.Dir.Dx = decodedInput[0]
player.Dir.Dy = decodedInput[1] player.Dir.Dy = decodedInput[1]
player.X += dx player.X = playerCollider.X + pR.playerColliderRadius - spaceOffsetX
player.Y += dy player.Y = playerCollider.Y + pR.playerColliderRadius - spaceOffsetY
} }
} }
@ -1253,19 +1261,13 @@ func (pR *Room) inputFrameIdDebuggable(inputFrameId int32) bool {
return 0 == (inputFrameId % 10) return 0 == (inputFrameId % 10)
} }
func (pR *Room) refreshColliders() { func (pR *Room) refreshColliders(spaceW, spaceH int32, spaceOffsetX, spaceOffsetY float64) {
playerColliderRadius := float64(12) // hardcoded
// 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"
spaceW := pR.StageDiscreteW * pR.StageTileW
spaceH := pR.StageDiscreteH * pR.StageTileH
spaceOffsetX := float64(spaceW) * 0.5
spaceOffsetY := float64(spaceH) * 0.5
minStep := int(3) // the approx minimum distance a player can move per frame minStep := int(3) // the approx minimum distance a player can move per frame
space := resolv.NewSpace(int(spaceW), int(spaceH), minStep, minStep) // allocate a new collision space everytime after a battle is settled 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 {
playerCollider := GenerateRectCollider(player.X, player.Y, playerColliderRadius*2, playerColliderRadius*2, spaceOffsetX, spaceOffsetY, "Player") playerCollider := GenerateRectCollider(player.X, player.Y, pR.playerColliderRadius*2, pR.playerColliderRadius*2, spaceOffsetX, spaceOffsetY, "Player")
space.Add(playerCollider) space.Add(playerCollider)
// Keep track of the collider in "pR.CollisionSysMap" // Keep track of the collider in "pR.CollisionSysMap"
joinIndex := player.JoinIndex joinIndex := player.JoinIndex

View File

@ -121,13 +121,19 @@ cc.Class({
return (0 == inputFrameId % 10); return (0 == inputFrameId % 10);
}, },
dumpToRenderCache: function(roomDownsyncFrame) { dumpToRenderCache: function(rdf) {
const self = this; const self = this;
// round player position to lower precision
for (let playerId in rdf.players) {
const immediatePlayerInfo = rdf.players[playerId];
rdf.players[playerId].x = parseFloat(parseInt(immediatePlayerInfo.x * 100)) / 100.0;
rdf.players[playerId].y = parseFloat(parseInt(immediatePlayerInfo.y * 100)) / 100.0;
}
const minToKeepRenderFrameId = self.lastAllConfirmedRenderFrameId; const minToKeepRenderFrameId = self.lastAllConfirmedRenderFrameId;
while (0 < self.recentRenderCache.cnt && self.recentRenderCache.stFrameId < minToKeepRenderFrameId) { while (0 < self.recentRenderCache.cnt && self.recentRenderCache.stFrameId < minToKeepRenderFrameId) {
self.recentRenderCache.pop(); self.recentRenderCache.pop();
} }
const ret = self.recentRenderCache.setByFrameId(roomDownsyncFrame, roomDownsyncFrame.id); const ret = self.recentRenderCache.setByFrameId(rdf, rdf.id);
return ret; return ret;
}, },
@ -382,8 +388,7 @@ cc.Class({
window.clearBoundRoomIdInBothVolatileAndPersistentStorage(); window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
window.initPersistentSessionClient(self.initAfterWSConnected, null /* Deliberately NOT passing in any `expectedRoomId`. -- YFLu */ ); window.initPersistentSessionClient(self.initAfterWSConnected, null /* Deliberately NOT passing in any `expectedRoomId`. -- YFLu */ );
}; };
resultPanelScriptIns.onCloseDelegate = () => { resultPanelScriptIns.onCloseDelegate = () => {};
};
self.gameRuleNode = cc.instantiate(self.gameRulePrefab); self.gameRuleNode = cc.instantiate(self.gameRulePrefab);
self.gameRuleNode.width = self.canvasNode.width; self.gameRuleNode.width = self.canvasNode.width;
@ -575,6 +580,7 @@ cc.Class({
if (rdf.id < self.lastAllConfirmedRenderFrameId) { if (rdf.id < self.lastAllConfirmedRenderFrameId) {
return window.RING_BUFF_FAILED_TO_SET; return window.RING_BUFF_FAILED_TO_SET;
} }
const dumpRenderCacheRet = self.dumpToRenderCache(rdf); const dumpRenderCacheRet = self.dumpToRenderCache(rdf);
if (window.RING_BUFF_FAILED_TO_SET == dumpRenderCacheRet) { if (window.RING_BUFF_FAILED_TO_SET == dumpRenderCacheRet) {
console.error("Something is wrong while setting the RingBuffer by frameId!"); console.error("Something is wrong while setting the RingBuffer by frameId!");
@ -589,8 +595,12 @@ cc.Class({
return dumpRenderCacheRet; return dumpRenderCacheRet;
} }
// The logic below applies to (window.MAGIC_ROOM_DOWNSYNC_FRAME_ID.BATTLE_START == rdf.id || window.RING_BUFF_NON_CONSECUTIVE_SET == dumpRenderCacheRet) // The logic below applies to ( || window.RING_BUFF_NON_CONSECUTIVE_SET == dumpRenderCacheRet)
console.log('On battle started or resynced! renderFrameId=', rdf.id); if (window.MAGIC_ROOM_DOWNSYNC_FRAME_ID.BATTLE_START == rdf.id) {
console.log('On battle resynced! renderFrameId=', rdf.id);
} else {
console.log('On battle resynced! renderFrameId=', rdf.id);
}
self.renderFrameId = rdf.id; self.renderFrameId = rdf.id;
self.lastRenderFrameIdTriggeredAt = performance.now(); self.lastRenderFrameIdTriggeredAt = performance.now();
@ -973,12 +983,14 @@ cc.Class({
if ( if (
null != inputFrameAppliedOnPrevRenderFrame && self._allConfirmed(inputFrameAppliedOnPrevRenderFrame.confirmedList) null != inputFrameAppliedOnPrevRenderFrame && self._allConfirmed(inputFrameAppliedOnPrevRenderFrame.confirmedList)
&& &&
self.lastAllConfirmedRenderFrameId >= prevRenderFrameId
&&
rdf.id > self.lastAllConfirmedRenderFrameId rdf.id > self.lastAllConfirmedRenderFrameId
) { ) {
// We got a more up-to-date "all-confirmed-render-frame".
self.lastAllConfirmedRenderFrameId = rdf.id; self.lastAllConfirmedRenderFrameId = rdf.id;
self.chaserRenderFrameId = rdf.id; // it must be true that "chaserRenderFrameId >= lastAllConfirmedRenderFrameId" if (rdf.id > self.chaserRenderFrameId) {
// it must be true that "chaserRenderFrameId >= lastAllConfirmedRenderFrameId"
self.chaserRenderFrameId = rdf.id;
}
} }
self.dumpToRenderCache(rdf); self.dumpToRenderCache(rdf);
return rdf; return rdf;
@ -991,11 +1003,10 @@ cc.Class({
const immediatePlayerInfo = rdf.players[playerId]; const immediatePlayerInfo = rdf.players[playerId];
const dx = (immediatePlayerInfo.x - playerRichInfo.node.x); const dx = (immediatePlayerInfo.x - playerRichInfo.node.x);
const dy = (immediatePlayerInfo.y - playerRichInfo.node.y); const dy = (immediatePlayerInfo.y - playerRichInfo.node.y);
const selfJiggling = (playerId == self.selfPlayerInfo.playerId && (0 != dx && self.teleportEps1D >= Math.abs(dx) && 0 != dy && self.teleportEps1D >= Math.abs(dy))); const justJiggling = (self.teleportEps1D >= Math.abs(dx) && self.teleportEps1D >= Math.abs(dy));
if (!selfJiggling) { if (!justJiggling) {
console.log("@renderFrameId=" + self.renderFrameId + ", teleporting playerId=" + playerId + ": '(" + playerRichInfo.node.x + ", " + playerRichInfo.node.y, ")' to '(" + immediatePlayerInfo.x + ", " + immediatePlayerInfo.y + ")'");
playerRichInfo.node.setPosition(immediatePlayerInfo.x, immediatePlayerInfo.y); playerRichInfo.node.setPosition(immediatePlayerInfo.x, immediatePlayerInfo.y);
} else {
console.log("selfJiggling: dx = ", dx, ", dy = ", dy);
} }
playerRichInfo.scriptIns.scheduleNewDirection(immediatePlayerInfo.dir, false); playerRichInfo.scriptIns.scheduleNewDirection(immediatePlayerInfo.dir, false);
playerRichInfo.scriptIns.updateSpeed(immediatePlayerInfo.speed); playerRichInfo.scriptIns.updateSpeed(immediatePlayerInfo.speed);
@ -1074,9 +1085,9 @@ cc.Class({
const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex; const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex;
const playerCollider = collisionSysMap.get(collisionPlayerIndex); const playerCollider = collisionSysMap.get(collisionPlayerIndex);
const potentials = playerCollider.potentials(); const potentials = playerCollider.potentials();
for (const barrier of potentials) { for (const potential of potentials) {
// Test if the player collides with the wall // Test if the player collides with the wall
if (!playerCollider.collides(barrier, result)) continue; if (!playerCollider.collides(potential, result)) continue;
// Push the player out of the wall // Push the player out of the wall
playerCollider.x -= result.overlap * result.overlap_x; playerCollider.x -= result.overlap * result.overlap_x;
playerCollider.y -= result.overlap * result.overlap_y; playerCollider.y -= result.overlap * result.overlap_y;