From 150e30db2a0502e2544e53221c2005d37af54599 Mon Sep 17 00:00:00 2001 From: yflu Date: Fri, 21 Oct 2022 22:39:08 +0800 Subject: [PATCH] Drafted backend collision with pushback calculations. --- battle_srv/models/room.go | 69 +++++++++------------ collider_visualizer/worldColliderDisplay.go | 6 +- frontend/assets/scenes/login.fire | 2 +- frontend/assets/scripts/Map.js | 21 +++++-- 4 files changed, 48 insertions(+), 50 deletions(-) diff --git a/battle_srv/models/room.go b/battle_srv/models/room.go index bc26f5f..cf29001 100644 --- a/battle_srv/models/room.go +++ b/battle_srv/models/room.go @@ -5,9 +5,9 @@ import ( "fmt" "github.com/golang/protobuf/proto" "github.com/gorilla/websocket" + "github.com/kvartborg/vector" "github.com/solarlune/resolv" "go.uber.org/zap" - "math" "math/rand" . "server/common" "server/common/utils" @@ -1151,19 +1151,35 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende continue } baseChange := player.Speed * pR.RollbackEstimatedDt * decodedInputSpeedFactor - dx := baseChange * float64(decodedInput[0]) - dy := baseChange * float64(decodedInput[1]) + oldDx, oldDy := baseChange * float64(decodedInput[0]), baseChange * float64(decodedInput[1]) + dx, dy := oldDx, oldDy collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex playerCollider := pR.CollisionSysMap[collisionPlayerIndex] - if collision := playerCollider.Check(dx, dy, "Barrier"); collision != nil { - changeWithCollision := collision.ContactWithObject(collision.Objects[0]) - Logger.Info(fmt.Sprintf("Collided: roomId=%v, playerId=%v, orig dx=%v, orig dy=%v, proposed new dx =%v, proposed new dy=%v", pR.Id, player.Id, dx, dy, changeWithCollision.X(), changeWithCollision.Y())) - // FIXME: Use a mechanism equivalent to that of the frontend! - // dx = changeWithCollision.X() - // dy = changeWithCollision.Y() - dx = 0 - dy = 0 + if collision := playerCollider.Check(oldDx, oldDy, "Barrier"); collision != nil { + playerShape := playerCollider.Shape.(*resolv.ConvexPolygon) + barrierShape := collision.Objects[0].Shape.(*resolv.ConvexPolygon) + origX, origY := playerShape.Position() + playerShape.SetPosition(origX+oldDx, origY+oldDy) + if colliding := IsPolygonPairColliding(playerShape, barrierShape, nil); colliding { + Logger.Info(fmt.Sprintf("Collided: playerShape=%v, oldDx=%v, oldDy=%v", playerShape, oldDx, oldDy)) + overlapResult := &SatResult{ + Overlap: 0, + OverlapX: 0, + OverlapY: 0, + AContainedInB: true, + BContainedInA: true, + Axis: vector.Vector{0, 0}, + } + e := vector.Vector{oldDx, oldDy}.Unit() + if separatableAlongMovement := IsPolygonPairSeparatedByDir(playerShape, barrierShape, e, overlapResult); !separatableAlongMovement { + pushbackX, pushbackY := overlapResult.Overlap*overlapResult.OverlapX, overlapResult.Overlap*overlapResult.OverlapY + Logger.Info(fmt.Sprintf("Collided: playerShape=%v, oldDx=%v, oldDy=%v, toCheckBarrier=%v, pushbackX=%v, pushbackY=%v", playerShape, oldDx, oldDy, barrierShape, pushbackX, pushbackY)) + dx, dy = oldDx-pushbackX, oldDy-pushbackY + } + } + + playerShape.SetPosition(origX, origY) } playerCollider.X += dx playerCollider.Y += dy @@ -1203,9 +1219,7 @@ func (pR *Room) refreshColliders() { 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 for _, player := range pR.Players { - playerCollider := resolv.NewObject(player.X-playerColliderRadius+spaceOffsetX, player.Y-playerColliderRadius+spaceOffsetY, playerColliderRadius*2, playerColliderRadius*2) - playerColliderShape := resolv.NewCircle(+playerColliderRadius, +playerColliderRadius, playerColliderRadius) - playerCollider.SetShape(playerColliderShape) + playerCollider := GenerateRectCollider(player.X, player.Y, playerColliderRadius*2, playerColliderRadius*2, spaceOffsetX, spaceOffsetY, "Player") space.Add(playerCollider) // Keep track of the collider in "pR.CollisionSysMap" joinIndex := player.JoinIndex @@ -1215,31 +1229,8 @@ func (pR *Room) refreshColliders() { } for _, barrier := range pR.Barriers { - - var w float64 = 0 - var h float64 = 0 - - for i, pi := range barrier.Boundary.Points { - for j, pj := range barrier.Boundary.Points { - if i == j { - continue - } - if math.Abs(pj.X-pi.X) > w { - w = math.Abs(pj.X - pi.X) - } - if math.Abs(pj.Y-pi.Y) > h { - h = math.Abs(pj.Y - pi.Y) - } - } - } - - barrierColliderShape := resolv.NewConvexPolygon() - for _, p := range barrier.Boundary.Points { - barrierColliderShape.AddPoints(p.X, p.Y) - } - - barrierCollider := resolv.NewObject(barrier.Boundary.Anchor.X+spaceOffsetX, barrier.Boundary.Anchor.Y+spaceOffsetY, w, h, "Barrier") - barrierCollider.SetShape(barrierColliderShape) + boundaryUnaligned := barrier.Boundary + barrierCollider := GenerateConvexPolygonCollider(boundaryUnaligned, spaceOffsetX, spaceOffsetY, "Barrier") space.Add(barrierCollider) } } diff --git a/collider_visualizer/worldColliderDisplay.go b/collider_visualizer/worldColliderDisplay.go index de2879a..0f41483 100644 --- a/collider_visualizer/worldColliderDisplay.go +++ b/collider_visualizer/worldColliderDisplay.go @@ -56,10 +56,8 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi moveToCollide := true if moveToCollide { toTestPlayerCollider := playerColliders[0] - oldDx := 135.0 - oldDy := 135.0 - dx := oldDx - dy := oldDy + oldDx, oldDy := 135.0, 135.0 + dx, dy := oldDx, oldDy if collision := toTestPlayerCollider.Check(oldDx, oldDy, "Barrier"); collision != nil { playerShape := toTestPlayerCollider.Shape.(*resolv.ConvexPolygon) barrierShape := collision.Objects[0].Shape.(*resolv.ConvexPolygon) diff --git a/frontend/assets/scenes/login.fire b/frontend/assets/scenes/login.fire index 31ccba3..b62a942 100644 --- a/frontend/assets/scenes/login.fire +++ b/frontend/assets/scenes/login.fire @@ -440,7 +440,7 @@ "array": [ 0, 0, - 209.73151519075364, + 342.9460598986377, 0, 0, 0, diff --git a/frontend/assets/scripts/Map.js b/frontend/assets/scripts/Map.js index 826d110..7aa45b0 100644 --- a/frontend/assets/scripts/Map.js +++ b/frontend/assets/scripts/Map.js @@ -740,9 +740,13 @@ cc.Class({ newPlayerNode.setPosition(cc.v2(x, y)); newPlayerNode.getComponent("SelfPlayer").mapNode = self.node; const currentSelfColliderCircle = newPlayerNode.getComponent(cc.CircleCollider); + const r = currentSelfColliderCircle.radius, d = 2*r; + // The collision box of an individual player is a polygon instead of a circle, because the backend collision engine doesn't handle circle alignment well. + const x0 = x-r, y0 = y-r; + let pts = [[0, 0], [d, 0], [d, d], [0, d]]; - const newPlayerColliderLatest = self.latestCollisionSys.createCircle(x, y, currentSelfColliderCircle.radius); - const newPlayerColliderChaser = self.chaserCollisionSys.createCircle(x, y, currentSelfColliderCircle.radius); + const newPlayerColliderLatest = self.latestCollisionSys.createPolygon(x0, y0, pts); + const newPlayerColliderChaser = self.chaserCollisionSys.createPolygon(x0, y0, pts); const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex; self.latestCollisionSysMap.set(collisionPlayerIndex, newPlayerColliderLatest); self.chaserCollisionSysMap.set(collisionPlayerIndex, newPlayerColliderChaser); @@ -952,10 +956,12 @@ cc.Class({ const joinIndex = playerRichInfo.joinIndex; const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex; const playerCollider = collisionSysMap.get(collisionPlayerIndex); + const currentSelfColliderCircle = playerRichInfo.node.getComponent(cc.CircleCollider); + const r = currentSelfColliderCircle.radius; rdf.players[playerRichInfo.id] = { id: playerRichInfo.id, - x: playerCollider.x, - y: playerCollider.y, + x: playerCollider.x + r, // [WARNING] the (x, y) of "playerCollider" is offset to the anchor (i.e. first point of all points) of the polygon shape + y: playerCollider.y + r, dir: self.ctrl.decodeDirection(null == inputFrameAppliedOnPrevRenderFrame ? 0 : inputFrameAppliedOnPrevRenderFrame.inputList[joinIndex - 1]), speed: (null == speedRefRenderFrame ? playerRichInfo.speed : speedRefRenderFrame.players[playerRichInfo.id].speed), joinIndex: joinIndex @@ -1025,8 +1031,11 @@ cc.Class({ const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex; const playerCollider = collisionSysMap.get(collisionPlayerIndex); const player = latestRdf.players[playerId]; - playerCollider.x = player.x; - playerCollider.y = player.y; + + const currentSelfColliderCircle = playerRichInfo.node.getComponent(cc.CircleCollider); + const r = currentSelfColliderCircle.radius; + playerCollider.x = player.x - r; + playerCollider.y = player.y - r; }); /*