mirror of
				https://github.com/genxium/DelayNoMore
				synced 2025-10-31 03:17:20 +00:00 
			
		
		
		
	Drafted backend collision with pushback calculations.
This commit is contained in:
		| @@ -5,9 +5,9 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"github.com/golang/protobuf/proto" | 	"github.com/golang/protobuf/proto" | ||||||
| 	"github.com/gorilla/websocket" | 	"github.com/gorilla/websocket" | ||||||
|  | 	"github.com/kvartborg/vector" | ||||||
| 	"github.com/solarlune/resolv" | 	"github.com/solarlune/resolv" | ||||||
| 	"go.uber.org/zap" | 	"go.uber.org/zap" | ||||||
| 	"math" |  | ||||||
| 	"math/rand" | 	"math/rand" | ||||||
| 	. "server/common" | 	. "server/common" | ||||||
| 	"server/common/utils" | 	"server/common/utils" | ||||||
| @@ -1151,19 +1151,35 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende | |||||||
| 					continue | 					continue | ||||||
| 				} | 				} | ||||||
| 				baseChange := player.Speed * pR.RollbackEstimatedDt * decodedInputSpeedFactor | 				baseChange := player.Speed * pR.RollbackEstimatedDt * decodedInputSpeedFactor | ||||||
| 				dx := baseChange * float64(decodedInput[0]) | 				oldDx, oldDy := baseChange * float64(decodedInput[0]), baseChange * float64(decodedInput[1])   | ||||||
| 				dy := baseChange * float64(decodedInput[1]) | 				dx, dy := oldDx, oldDy  | ||||||
|  |  | ||||||
| 				collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex | 				collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex | ||||||
| 				playerCollider := pR.CollisionSysMap[collisionPlayerIndex] | 				playerCollider := pR.CollisionSysMap[collisionPlayerIndex] | ||||||
| 				if collision := playerCollider.Check(dx, dy, "Barrier"); collision != nil { | 				if collision := playerCollider.Check(oldDx, oldDy, "Barrier"); collision != nil { | ||||||
| 					changeWithCollision := collision.ContactWithObject(collision.Objects[0]) | 					playerShape := playerCollider.Shape.(*resolv.ConvexPolygon) | ||||||
| 					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())) | 					barrierShape := collision.Objects[0].Shape.(*resolv.ConvexPolygon) | ||||||
|                     // FIXME: Use a mechanism equivalent to that of the frontend! | 					origX, origY := playerShape.Position()  | ||||||
| 					// dx = changeWithCollision.X() | 					playerShape.SetPosition(origX+oldDx, origY+oldDy)  | ||||||
| 					// dy = changeWithCollision.Y() | 					if colliding := IsPolygonPairColliding(playerShape, barrierShape, nil); colliding { | ||||||
| 					dx = 0 | 						Logger.Info(fmt.Sprintf("Collided: playerShape=%v, oldDx=%v, oldDy=%v", playerShape, oldDx, oldDy)) | ||||||
| 					dy = 0 | 						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.X += dx | ||||||
| 				playerCollider.Y += dy | 				playerCollider.Y += dy | ||||||
| @@ -1203,9 +1219,7 @@ func (pR *Room) refreshColliders() { | |||||||
|     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 := resolv.NewObject(player.X-playerColliderRadius+spaceOffsetX, player.Y-playerColliderRadius+spaceOffsetY, playerColliderRadius*2, playerColliderRadius*2) | 		playerCollider := GenerateRectCollider(player.X, player.Y, playerColliderRadius*2, playerColliderRadius*2, spaceOffsetX, spaceOffsetY, "Player") | ||||||
| 		playerColliderShape := resolv.NewCircle(+playerColliderRadius, +playerColliderRadius, playerColliderRadius) |  | ||||||
| 		playerCollider.SetShape(playerColliderShape) |  | ||||||
| 		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 | ||||||
| @@ -1215,31 +1229,8 @@ func (pR *Room) refreshColliders() { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for _, barrier := range pR.Barriers { | 	for _, barrier := range pR.Barriers { | ||||||
|  | 		boundaryUnaligned := barrier.Boundary | ||||||
| 		var w float64 = 0 | 		barrierCollider := GenerateConvexPolygonCollider(boundaryUnaligned, spaceOffsetX, spaceOffsetY, "Barrier") | ||||||
| 		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) |  | ||||||
| 		space.Add(barrierCollider) | 		space.Add(barrierCollider) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -56,10 +56,8 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi | |||||||
|     moveToCollide := true  |     moveToCollide := true  | ||||||
|     if moveToCollide { |     if moveToCollide { | ||||||
|         toTestPlayerCollider := playerColliders[0]  |         toTestPlayerCollider := playerColliders[0]  | ||||||
|         oldDx := 135.0 |         oldDx, oldDy := 135.0, 135.0 | ||||||
|         oldDy := 135.0 |         dx, dy := oldDx, oldDy | ||||||
|         dx := oldDx |  | ||||||
|         dy := oldDy |  | ||||||
|         if collision := toTestPlayerCollider.Check(oldDx, oldDy, "Barrier"); collision != nil { |         if collision := toTestPlayerCollider.Check(oldDx, oldDy, "Barrier"); collision != nil { | ||||||
|             playerShape := toTestPlayerCollider.Shape.(*resolv.ConvexPolygon) |             playerShape := toTestPlayerCollider.Shape.(*resolv.ConvexPolygon) | ||||||
|             barrierShape := collision.Objects[0].Shape.(*resolv.ConvexPolygon) |             barrierShape := collision.Objects[0].Shape.(*resolv.ConvexPolygon) | ||||||
|   | |||||||
| @@ -440,7 +440,7 @@ | |||||||
|       "array": [ |       "array": [ | ||||||
|         0, |         0, | ||||||
|         0, |         0, | ||||||
|         209.73151519075364, |         342.9460598986377, | ||||||
|         0, |         0, | ||||||
|         0, |         0, | ||||||
|         0, |         0, | ||||||
|   | |||||||
| @@ -740,9 +740,13 @@ cc.Class({ | |||||||
|     newPlayerNode.setPosition(cc.v2(x, y)); |     newPlayerNode.setPosition(cc.v2(x, y)); | ||||||
|     newPlayerNode.getComponent("SelfPlayer").mapNode = self.node; |     newPlayerNode.getComponent("SelfPlayer").mapNode = self.node; | ||||||
|     const currentSelfColliderCircle = newPlayerNode.getComponent(cc.CircleCollider); |     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 newPlayerColliderLatest = self.latestCollisionSys.createPolygon(x0, y0, pts); | ||||||
|     const newPlayerColliderChaser = self.chaserCollisionSys.createCircle(x, y, currentSelfColliderCircle.radius); |     const newPlayerColliderChaser = self.chaserCollisionSys.createPolygon(x0, y0, pts); | ||||||
|     const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex; |     const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex; | ||||||
|     self.latestCollisionSysMap.set(collisionPlayerIndex, newPlayerColliderLatest); |     self.latestCollisionSysMap.set(collisionPlayerIndex, newPlayerColliderLatest); | ||||||
|     self.chaserCollisionSysMap.set(collisionPlayerIndex, newPlayerColliderChaser); |     self.chaserCollisionSysMap.set(collisionPlayerIndex, newPlayerColliderChaser); | ||||||
| @@ -952,10 +956,12 @@ cc.Class({ | |||||||
|       const joinIndex = playerRichInfo.joinIndex; |       const joinIndex = playerRichInfo.joinIndex; | ||||||
|       const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex; |       const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex; | ||||||
|       const playerCollider = collisionSysMap.get(collisionPlayerIndex); |       const playerCollider = collisionSysMap.get(collisionPlayerIndex); | ||||||
|  |       const currentSelfColliderCircle = playerRichInfo.node.getComponent(cc.CircleCollider); | ||||||
|  | 	  const r = currentSelfColliderCircle.radius; | ||||||
|       rdf.players[playerRichInfo.id] = { |       rdf.players[playerRichInfo.id] = { | ||||||
|         id: playerRichInfo.id, |         id: playerRichInfo.id, | ||||||
|         x: playerCollider.x, |         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, |         y: playerCollider.y + r, | ||||||
|         dir: self.ctrl.decodeDirection(null == inputFrameAppliedOnPrevRenderFrame ? 0 : inputFrameAppliedOnPrevRenderFrame.inputList[joinIndex - 1]), |         dir: self.ctrl.decodeDirection(null == inputFrameAppliedOnPrevRenderFrame ? 0 : inputFrameAppliedOnPrevRenderFrame.inputList[joinIndex - 1]), | ||||||
|         speed: (null == speedRefRenderFrame ? playerRichInfo.speed : speedRefRenderFrame.players[playerRichInfo.id].speed), |         speed: (null == speedRefRenderFrame ? playerRichInfo.speed : speedRefRenderFrame.players[playerRichInfo.id].speed), | ||||||
|         joinIndex: joinIndex |         joinIndex: joinIndex | ||||||
| @@ -1025,8 +1031,11 @@ cc.Class({ | |||||||
|       const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex; |       const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex; | ||||||
|       const playerCollider = collisionSysMap.get(collisionPlayerIndex); |       const playerCollider = collisionSysMap.get(collisionPlayerIndex); | ||||||
|       const player = latestRdf.players[playerId]; |       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; | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     /* |     /* | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user