mirror of
https://github.com/genxium/DelayNoMore
synced 2024-12-26 03:39:00 +00:00
A temp dirty commit having mysterious left moving players.
This commit is contained in:
parent
c6b98855af
commit
2b304eaa75
@ -518,7 +518,7 @@
|
|||||||
"array": [
|
"array": [
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
216.50635094610968,
|
210.4441731196186,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
@ -380,6 +380,8 @@ cc.Class({
|
|||||||
}
|
}
|
||||||
self.pJumpedOrNotList = [];
|
self.pJumpedOrNotList = [];
|
||||||
for (let i = 0; i < window.boundRoomCapacity; i++) self.pJumpedOrNotList.push(false);
|
for (let i = 0; i < window.boundRoomCapacity; i++) self.pJumpedOrNotList.push(false);
|
||||||
|
self.dynamicRectangleColliders = gopkgs.NewDynamicRectangleColliders(64);
|
||||||
|
|
||||||
self.recentRenderCache = gopkgs.NewRingBufferJs(self.renderCacheSize);
|
self.recentRenderCache = gopkgs.NewRingBufferJs(self.renderCacheSize);
|
||||||
|
|
||||||
self.recentInputCache = gopkgs.NewRingBufferJs((self.renderCacheSize >> 1) + 1);
|
self.recentInputCache = gopkgs.NewRingBufferJs((self.renderCacheSize >> 1) + 1);
|
||||||
@ -1401,7 +1403,7 @@ othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame
|
|||||||
};
|
};
|
||||||
self.rdfIdToActuallyUsedInput.set(i, inputFrameDownsyncClone);
|
self.rdfIdToActuallyUsedInput.set(i, inputFrameDownsyncClone);
|
||||||
}
|
}
|
||||||
const renderRes = gopkgs.ApplyInputFrameDownsyncDynamicsOnSingleRenderFrameJs(self.recentInputCache, i, collisionSys, collisionSysMap, self.spaceOffsetX, self.spaceOffsetY, self.chConfigsOrderedByJoinIndex, self.recentRenderCache, self.collisionHolder, self.pEffPushbacks, self.pHardPushbackNormsArr, self.pJumpedOrNotList);
|
const renderRes = gopkgs.ApplyInputFrameDownsyncDynamicsOnSingleRenderFrameJs(self.recentInputCache, i, collisionSys, collisionSysMap, self.spaceOffsetX, self.spaceOffsetY, self.chConfigsOrderedByJoinIndex, self.recentRenderCache, self.collisionHolder, self.pEffPushbacks, self.pHardPushbackNormsArr, self.pJumpedOrNotList, self.dynamicRectangleColliders);
|
||||||
const nextRdf = gopkgs.GetRoomDownsyncFrame(self.recentRenderCache, self.renderFrameId + 1);
|
const nextRdf = gopkgs.GetRoomDownsyncFrame(self.recentRenderCache, self.renderFrameId + 1);
|
||||||
|
|
||||||
if (true == isChasing) {
|
if (true == isChasing) {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -217,21 +217,23 @@ func calcPushbacks(oldDx, oldDy float64, playerShape, barrierShape *resolv.Conve
|
|||||||
}
|
}
|
||||||
|
|
||||||
func isPolygonPairOverlapped(a, b *resolv.ConvexPolygon, result *SatResult) bool {
|
func isPolygonPairOverlapped(a, b *resolv.ConvexPolygon, result *SatResult) bool {
|
||||||
aCnt, bCnt := len(a.Points), len(b.Points)
|
aCnt, bCnt := a.Points.Cnt, b.Points.Cnt
|
||||||
// Single point case
|
// Single point case
|
||||||
if 1 == aCnt && 1 == bCnt {
|
if 1 == aCnt && 1 == bCnt {
|
||||||
if nil != result {
|
if nil != result {
|
||||||
result.Overlap = 0
|
result.Overlap = 0
|
||||||
}
|
}
|
||||||
return a.Points[0][0] == b.Points[0][0] && a.Points[0][1] == b.Points[0][1]
|
aPoint := a.GetPointByOffset(0)
|
||||||
|
bPoint := b.GetPointByOffset(0)
|
||||||
|
return aPoint[0] == bPoint[0] && aPoint[1] == bPoint[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
if 1 < aCnt {
|
if 1 < aCnt {
|
||||||
// Deliberately using "Points" instead of "SATAxes" to avoid unnecessary heap memory alloc
|
// Deliberately using "Points" instead of "SATAxes" to avoid unnecessary heap memory alloc
|
||||||
for i, _ := range a.Points {
|
for i := int32(0); i < a.Points.Cnt; i++ {
|
||||||
u, v := a.Points[i], a.Points[0]
|
u, v := a.GetPointByOffset(i), a.GetPointByOffset(0)
|
||||||
if i != len(a.Points)-1 {
|
if i != a.Points.Cnt-1 {
|
||||||
v = a.Points[i+1]
|
v = a.GetPointByOffset(i + 1)
|
||||||
}
|
}
|
||||||
dy := v[1] - u[1]
|
dy := v[1] - u[1]
|
||||||
dx := v[0] - u[0]
|
dx := v[0] - u[0]
|
||||||
@ -243,10 +245,10 @@ func isPolygonPairOverlapped(a, b *resolv.ConvexPolygon, result *SatResult) bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
if 1 < bCnt {
|
if 1 < bCnt {
|
||||||
for i, _ := range b.Points {
|
for i := int32(0); i < b.Points.Cnt; i++ {
|
||||||
u, v := b.Points[i], b.Points[0]
|
u, v := b.GetPointByOffset(i), b.GetPointByOffset(0)
|
||||||
if i != len(b.Points)-1 {
|
if i != b.Points.Cnt-1 {
|
||||||
v = b.Points[i+1]
|
v = b.GetPointByOffset(i + 1)
|
||||||
}
|
}
|
||||||
dy := v[1] - u[1]
|
dy := v[1] - u[1]
|
||||||
dx := v[0] - u[0]
|
dx := v[0] - u[0]
|
||||||
@ -307,7 +309,8 @@ func isPolygonPairSeparatedByDir(a, b *resolv.ConvexPolygon, e resolv.Vector, re
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var aStart, aEnd, bStart, bEnd float64 = MAX_FLOAT64, -MAX_FLOAT64, MAX_FLOAT64, -MAX_FLOAT64
|
var aStart, aEnd, bStart, bEnd float64 = MAX_FLOAT64, -MAX_FLOAT64, MAX_FLOAT64, -MAX_FLOAT64
|
||||||
for _, p := range a.Points {
|
for i := int32(0); i < a.Points.Cnt; i++ {
|
||||||
|
p := a.GetPointByOffset(i)
|
||||||
dot := (p[0]+a.X)*e[0] + (p[1]+a.Y)*e[1]
|
dot := (p[0]+a.X)*e[0] + (p[1]+a.Y)*e[1]
|
||||||
|
|
||||||
if aStart > dot {
|
if aStart > dot {
|
||||||
@ -319,7 +322,8 @@ func isPolygonPairSeparatedByDir(a, b *resolv.ConvexPolygon, e resolv.Vector, re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range b.Points {
|
for i := int32(0); i < b.Points.Cnt; i++ {
|
||||||
|
p := b.GetPointByOffset(i)
|
||||||
dot := (p[0]+b.X)*e[0] + (p[1]+b.Y)*e[1]
|
dot := (p[0]+b.X)*e[0] + (p[1]+b.Y)*e[1]
|
||||||
|
|
||||||
if bStart > dot {
|
if bStart > dot {
|
||||||
@ -454,7 +458,7 @@ func calcHardPushbacksNorms(joinIndex int32, currPlayerDownsync, thatPlayerInNex
|
|||||||
//playerColliderCenterX, playerColliderCenterY := playerCollider.Center()
|
//playerColliderCenterX, playerColliderCenterY := playerCollider.Center()
|
||||||
//fmt.Printf("joinIndex=%d calcHardPushbacksNorms has non-empty collision;playerColliderPos=(%.2f,%.2f)\n", joinIndex, playerColliderCenterX, playerColliderCenterY)
|
//fmt.Printf("joinIndex=%d calcHardPushbacksNorms has non-empty collision;playerColliderPos=(%.2f,%.2f)\n", joinIndex, playerColliderCenterX, playerColliderCenterY)
|
||||||
for true {
|
for true {
|
||||||
obj := collision.FirstCollidedObject()
|
obj := collision.PopFirstCollidedObject()
|
||||||
if nil == obj {
|
if nil == obj {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -558,11 +562,9 @@ func deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame *PlayerDownsync,
|
|||||||
/*
|
/*
|
||||||
[LONG TERM PERFORMANCE ENHANCEMENT PLAN]
|
[LONG TERM PERFORMANCE ENHANCEMENT PLAN]
|
||||||
|
|
||||||
The function "ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame" is creating new heap-memory blocks at 60fps, e.g. nextRenderFramePlayers & nextRenderFrameMeleeBullets & nextRenderFrameFireballBullets & effPushbacks & hardPushbackNorms & jumpedOrNotList & playerColliders & bulletColliders, which would induce "possibly performance impacting garbage collections" when many rooms are running simultaneously.
|
The function "ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame" is creating new heap-memory blocks at 60fps, e.g. nextRenderFramePlayers & nextRenderFrameMeleeBullets & nextRenderFrameFireballBullets & effPushbacks & hardPushbackNorms & jumpedOrNotList & dynamicRectangleColliders("player" & "bullet"), which would induce "possibly performance impacting garbage collections" when many rooms are running simultaneously.
|
||||||
|
|
||||||
It's not easy to remove all of the dynamic heap-memory blocks allocation/deallocation, but we can reduce them to some extent.
|
|
||||||
*/
|
*/
|
||||||
func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *resolv.RingBuffer, currRenderFrameId int32, collisionSys *resolv.Space, collisionSysMap map[int32]*resolv.Object, collisionSpaceOffsetX, collisionSpaceOffsetY float64, chConfigsOrderedByJoinIndex []*CharacterConfig, renderFrameBuffer *resolv.RingBuffer, collision *resolv.Collision, effPushbacks []*Vec2D, hardPushbackNormsArr [][]*Vec2D, jumpedOrNotList []bool) bool {
|
func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *resolv.RingBuffer, currRenderFrameId int32, collisionSys *resolv.Space, collisionSysMap map[int32]*resolv.Object, collisionSpaceOffsetX, collisionSpaceOffsetY float64, chConfigsOrderedByJoinIndex []*CharacterConfig, renderFrameBuffer *resolv.RingBuffer, collision *resolv.Collision, effPushbacks []*Vec2D, hardPushbackNormsArr [][]*Vec2D, jumpedOrNotList []bool, dynamicRectangleColliders []*resolv.Object) bool {
|
||||||
currRenderFrame := renderFrameBuffer.GetByFrameId(currRenderFrameId).(*RoomDownsyncFrame)
|
currRenderFrame := renderFrameBuffer.GetByFrameId(currRenderFrameId).(*RoomDownsyncFrame)
|
||||||
nextRenderFrameId := currRenderFrameId + 1
|
nextRenderFrameId := currRenderFrameId + 1
|
||||||
roomCapacity := len(currRenderFrame.PlayersArr)
|
roomCapacity := len(currRenderFrame.PlayersArr)
|
||||||
@ -759,8 +761,14 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *resolv.Rin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
[WARNING]
|
||||||
|
1. The dynamic colliders will all be removed from "Space" at the end of this function due to the need for being rollback-compatible.
|
||||||
|
2. To achieve "zero gc" in "ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame", I deliberately chose a collision system that doesn't use dynamic tree node alloc.
|
||||||
|
*/
|
||||||
|
colliderCnt := 0
|
||||||
|
|
||||||
// 2. Process player movement
|
// 2. Process player movement
|
||||||
playerColliders := make([]*resolv.Object, len(currRenderFrame.PlayersArr), len(currRenderFrame.PlayersArr)) // Will all be removed at the end of this function due to the need for being rollback-compatible
|
|
||||||
for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
|
for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
|
||||||
joinIndex := currPlayerDownsync.JoinIndex
|
joinIndex := currPlayerDownsync.JoinIndex
|
||||||
effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y = float64(0), float64(0)
|
effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y = float64(0), float64(0)
|
||||||
@ -819,8 +827,9 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *resolv.Rin
|
|||||||
|
|
||||||
colliderWorldWidth, colliderWorldHeight := VirtualGridToWorldPos(colliderWidth, colliderHeight)
|
colliderWorldWidth, colliderWorldHeight := VirtualGridToWorldPos(colliderWidth, colliderHeight)
|
||||||
|
|
||||||
playerCollider := GenerateRectCollider(wx, wy, colliderWorldWidth, colliderWorldHeight, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, collisionSpaceOffsetX, collisionSpaceOffsetY, currPlayerDownsync, "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 := dynamicRectangleColliders[colliderCnt]
|
||||||
playerColliders[i] = playerCollider
|
UpdateRectCollider(playerCollider, wx, wy, colliderWorldWidth, colliderWorldHeight, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, collisionSpaceOffsetX, collisionSpaceOffsetY, currPlayerDownsync, "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
|
||||||
|
colliderCnt++
|
||||||
|
|
||||||
// Add to collision system
|
// Add to collision system
|
||||||
collisionSys.AddSingle(playerCollider)
|
collisionSys.AddSingle(playerCollider)
|
||||||
@ -838,9 +847,8 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *resolv.Rin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Add bullet colliders into collision system
|
// 3. Add bullet colliders into collision system; [DIRTY TRICK] Players always precede bullets in "dynamicRectangleColliders".
|
||||||
// [WARNING] For rollback compatibility, static data of "BulletConfig" & "BattleAttr(static since instantiated)" can just be copies of the pointers in "RenderFrameBuffer", however, FireballBullets movement data as well as bullet animation data must be copies of instances for each RenderFrame!
|
// [WARNING] For rollback compatibility, static data of "BulletConfig" & "BattleAttr(static since instantiated)" can just be copies of the pointers in "RenderFrameBuffer", however, FireballBullets movement data as well as bullet animation data must be copies of instances for each RenderFrame!
|
||||||
bulletColliders := make([]*resolv.Object, 0, ((len(currRenderFrame.MeleeBullets) + len(currRenderFrame.FireballBullets)) << 1)) // Will all be removed at the end of this function due to the need for being rollback-compatible
|
|
||||||
for _, prevFireball := range currRenderFrame.FireballBullets {
|
for _, prevFireball := range currRenderFrame.FireballBullets {
|
||||||
if TERMINATING_BULLET_LOCAL_ID == prevFireball.BattleAttr.BulletLocalId {
|
if TERMINATING_BULLET_LOCAL_ID == prevFireball.BattleAttr.BulletLocalId {
|
||||||
break
|
break
|
||||||
@ -862,9 +870,12 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *resolv.Rin
|
|||||||
if IsFireballBulletActive(fireballBullet, currRenderFrame) {
|
if IsFireballBulletActive(fireballBullet, currRenderFrame) {
|
||||||
bulletWx, bulletWy := VirtualGridToWorldPos(fireballBullet.VirtualGridX, fireballBullet.VirtualGridY)
|
bulletWx, bulletWy := VirtualGridToWorldPos(fireballBullet.VirtualGridX, fireballBullet.VirtualGridY)
|
||||||
hitboxSizeWx, hitboxSizeWy := VirtualGridToWorldPos(fireballBullet.Bullet.HitboxSizeX, fireballBullet.Bullet.HitboxSizeY)
|
hitboxSizeWx, hitboxSizeWy := VirtualGridToWorldPos(fireballBullet.Bullet.HitboxSizeX, fireballBullet.Bullet.HitboxSizeY)
|
||||||
newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, hitboxSizeWx, hitboxSizeWy, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, collisionSpaceOffsetX, collisionSpaceOffsetY, fireballBullet, "FireballBullet")
|
|
||||||
|
newBulletCollider := dynamicRectangleColliders[colliderCnt]
|
||||||
|
UpdateRectCollider(newBulletCollider, bulletWx, bulletWy, hitboxSizeWx, hitboxSizeWy, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, collisionSpaceOffsetX, collisionSpaceOffsetY, fireballBullet, "FireballBullet")
|
||||||
|
colliderCnt++
|
||||||
|
|
||||||
collisionSys.AddSingle(newBulletCollider)
|
collisionSys.AddSingle(newBulletCollider)
|
||||||
bulletColliders = append(bulletColliders, newBulletCollider)
|
|
||||||
fireballBullet.BlState = BULLET_ACTIVE
|
fireballBullet.BlState = BULLET_ACTIVE
|
||||||
if fireballBullet.BlState != prevFireball.BlState {
|
if fireballBullet.BlState != prevFireball.BlState {
|
||||||
fireballBullet.FramesInBlState = 0
|
fireballBullet.FramesInBlState = 0
|
||||||
@ -906,9 +917,12 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *resolv.Rin
|
|||||||
}
|
}
|
||||||
bulletWx, bulletWy := VirtualGridToWorldPos(offender.VirtualGridX+xfac*meleeBullet.Bullet.HitboxOffsetX, offender.VirtualGridY)
|
bulletWx, bulletWy := VirtualGridToWorldPos(offender.VirtualGridX+xfac*meleeBullet.Bullet.HitboxOffsetX, offender.VirtualGridY)
|
||||||
hitboxSizeWx, hitboxSizeWy := VirtualGridToWorldPos(meleeBullet.Bullet.HitboxSizeX, meleeBullet.Bullet.HitboxSizeY)
|
hitboxSizeWx, hitboxSizeWy := VirtualGridToWorldPos(meleeBullet.Bullet.HitboxSizeX, meleeBullet.Bullet.HitboxSizeY)
|
||||||
newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, hitboxSizeWx, hitboxSizeWy, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, collisionSpaceOffsetX, collisionSpaceOffsetY, meleeBullet, "MeleeBullet")
|
|
||||||
|
newBulletCollider := dynamicRectangleColliders[colliderCnt]
|
||||||
|
UpdateRectCollider(newBulletCollider, bulletWx, bulletWy, hitboxSizeWx, hitboxSizeWy, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, collisionSpaceOffsetX, collisionSpaceOffsetY, meleeBullet, "MeleeBullet")
|
||||||
|
colliderCnt++
|
||||||
|
|
||||||
collisionSys.AddSingle(newBulletCollider)
|
collisionSys.AddSingle(newBulletCollider)
|
||||||
bulletColliders = append(bulletColliders, newBulletCollider)
|
|
||||||
meleeBullet.BlState = BULLET_ACTIVE
|
meleeBullet.BlState = BULLET_ACTIVE
|
||||||
if meleeBullet.BlState != prevMelee.BlState {
|
if meleeBullet.BlState != prevMelee.BlState {
|
||||||
meleeBullet.FramesInBlState = 0
|
meleeBullet.FramesInBlState = 0
|
||||||
@ -921,7 +935,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *resolv.Rin
|
|||||||
// 4. Calc pushbacks for each player (after its movement) w/o bullets
|
// 4. Calc pushbacks for each player (after its movement) w/o bullets
|
||||||
for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
|
for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
|
||||||
joinIndex := currPlayerDownsync.JoinIndex
|
joinIndex := currPlayerDownsync.JoinIndex
|
||||||
playerCollider := playerColliders[i]
|
playerCollider := dynamicRectangleColliders[i]
|
||||||
playerShape := playerCollider.Shape.(*resolv.ConvexPolygon)
|
playerShape := playerCollider.Shape.(*resolv.ConvexPolygon)
|
||||||
thatPlayerInNextFrame := nextRenderFramePlayers[i]
|
thatPlayerInNextFrame := nextRenderFramePlayers[i]
|
||||||
hardPushbackCnt := calcHardPushbacksNorms(joinIndex, currPlayerDownsync, thatPlayerInNextFrame, playerCollider, playerShape, SNAP_INTO_PLATFORM_OVERLAP, effPushbacks[joinIndex-1], hardPushbackNormsArr[joinIndex-1], collision)
|
hardPushbackCnt := calcHardPushbacksNorms(joinIndex, currPlayerDownsync, thatPlayerInNextFrame, playerCollider, playerShape, SNAP_INTO_PLATFORM_OVERLAP, effPushbacks[joinIndex-1], hardPushbackNormsArr[joinIndex-1], collision)
|
||||||
@ -930,7 +944,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *resolv.Rin
|
|||||||
|
|
||||||
if collided := playerCollider.CheckAllWithHolder(0, 0, collision); collided {
|
if collided := playerCollider.CheckAllWithHolder(0, 0, collision); collided {
|
||||||
for true {
|
for true {
|
||||||
obj := collision.FirstCollidedObject()
|
obj := collision.PopFirstCollidedObject()
|
||||||
if nil == obj {
|
if nil == obj {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -963,7 +977,6 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *resolv.Rin
|
|||||||
// [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.
|
// [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.
|
||||||
pushbackX, pushbackY = (overlapResult.Overlap-SNAP_INTO_PLATFORM_OVERLAP*2)*overlapResult.OverlapX, (overlapResult.Overlap-SNAP_INTO_PLATFORM_OVERLAP*2)*overlapResult.OverlapY
|
pushbackX, pushbackY = (overlapResult.Overlap-SNAP_INTO_PLATFORM_OVERLAP*2)*overlapResult.OverlapX, (overlapResult.Overlap-SNAP_INTO_PLATFORM_OVERLAP*2)*overlapResult.OverlapY
|
||||||
}
|
}
|
||||||
if 0 < hardPushbackCnt {
|
|
||||||
for i := 0; i < hardPushbackCnt; i++ {
|
for i := 0; i < hardPushbackCnt; i++ {
|
||||||
hardPushbackNorm := hardPushbackNormsArr[joinIndex-1][i]
|
hardPushbackNorm := hardPushbackNormsArr[joinIndex-1][i]
|
||||||
projectedMagnitude := pushbackX*hardPushbackNorm.X + pushbackY*hardPushbackNorm.Y
|
projectedMagnitude := pushbackX*hardPushbackNorm.X + pushbackY*hardPushbackNorm.Y
|
||||||
@ -972,7 +985,6 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *resolv.Rin
|
|||||||
pushbackY -= projectedMagnitude * hardPushbackNorm.Y
|
pushbackY -= projectedMagnitude * hardPushbackNorm.Y
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
effPushbacks[joinIndex-1].X += pushbackX
|
effPushbacks[joinIndex-1].X += pushbackX
|
||||||
effPushbacks[joinIndex-1].Y += pushbackY
|
effPushbacks[joinIndex-1].Y += pushbackY
|
||||||
|
|
||||||
@ -1028,7 +1040,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *resolv.Rin
|
|||||||
if chConfig.OnWallEnabled {
|
if chConfig.OnWallEnabled {
|
||||||
if thatPlayerInNextFrame.InAir {
|
if thatPlayerInNextFrame.InAir {
|
||||||
// [WARNING] Sticking to wall MUST BE based on "InAir", otherwise we would get gravity reduction from ground up incorrectly!
|
// [WARNING] Sticking to wall MUST BE based on "InAir", otherwise we would get gravity reduction from ground up incorrectly!
|
||||||
if _, existent := noOpSet[currPlayerDownsync.CharacterState]; !existent && 0 < hardPushbackCnt {
|
if _, existent := noOpSet[currPlayerDownsync.CharacterState]; !existent {
|
||||||
// [WARNING] Sticking to wall could only be triggered by proactive player input
|
// [WARNING] Sticking to wall could only be triggered by proactive player input
|
||||||
for i := 0; i < hardPushbackCnt; i++ {
|
for i := 0; i < hardPushbackCnt; i++ {
|
||||||
hardPushbackNorm := hardPushbackNormsArr[joinIndex-1][i]
|
hardPushbackNorm := hardPushbackNormsArr[joinIndex-1][i]
|
||||||
@ -1051,13 +1063,12 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *resolv.Rin
|
|||||||
thatPlayerInNextFrame.OnWallNormX, thatPlayerInNextFrame.OnWallNormY = 0, 0
|
thatPlayerInNextFrame.OnWallNormX, thatPlayerInNextFrame.OnWallNormY = 0, 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Check bullet-anything collisions
|
// 5. Check bullet-anything collisions
|
||||||
for _, bulletCollider := range bulletColliders {
|
for i := len(nextRenderFramePlayers); i < colliderCnt; i++ {
|
||||||
|
bulletCollider := dynamicRectangleColliders[i]
|
||||||
collided := bulletCollider.CheckAllWithHolder(0, 0, collision)
|
collided := bulletCollider.CheckAllWithHolder(0, 0, collision)
|
||||||
bulletCollider.Space.RemoveSingle(bulletCollider) // Make sure that the bulletCollider is always removed for each renderFrame
|
|
||||||
if !collided {
|
if !collided {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -1079,7 +1090,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *resolv.Rin
|
|||||||
bulletShape := bulletCollider.Shape.(*resolv.ConvexPolygon)
|
bulletShape := bulletCollider.Shape.(*resolv.ConvexPolygon)
|
||||||
offender := currRenderFrame.PlayersArr[bulletBattleAttr.OffenderJoinIndex-1]
|
offender := currRenderFrame.PlayersArr[bulletBattleAttr.OffenderJoinIndex-1]
|
||||||
for true {
|
for true {
|
||||||
obj := collision.FirstCollidedObject()
|
obj := collision.PopFirstCollidedObject()
|
||||||
if nil == obj {
|
if nil == obj {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -1153,7 +1164,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *resolv.Rin
|
|||||||
// 6. Get players out of stuck barriers if there's any
|
// 6. Get players out of stuck barriers if there's any
|
||||||
for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
|
for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
|
||||||
joinIndex := currPlayerDownsync.JoinIndex
|
joinIndex := currPlayerDownsync.JoinIndex
|
||||||
playerCollider := playerColliders[i]
|
playerCollider := dynamicRectangleColliders[i]
|
||||||
// Update "virtual grid position"
|
// Update "virtual grid position"
|
||||||
thatPlayerInNextFrame := nextRenderFramePlayers[i]
|
thatPlayerInNextFrame := nextRenderFramePlayers[i]
|
||||||
thatPlayerInNextFrame.VirtualGridX, thatPlayerInNextFrame.VirtualGridY = PolygonColliderBLToVirtualGridPos(playerCollider.X-effPushbacks[joinIndex-1].X, playerCollider.Y-effPushbacks[joinIndex-1].Y, playerCollider.W*0.5, playerCollider.H*0.5, 0, 0, 0, 0, collisionSpaceOffsetX, collisionSpaceOffsetY)
|
thatPlayerInNextFrame.VirtualGridX, thatPlayerInNextFrame.VirtualGridY = PolygonColliderBLToVirtualGridPos(playerCollider.X-effPushbacks[joinIndex-1].X, playerCollider.Y-effPushbacks[joinIndex-1].Y, playerCollider.W*0.5, playerCollider.H*0.5, 0, 0, 0, 0, collisionSpaceOffsetX, collisionSpaceOffsetY)
|
||||||
@ -1199,8 +1210,9 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *resolv.Rin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, playerCollider := range playerColliders {
|
for i := 0; i < colliderCnt; i++ {
|
||||||
playerCollider.Space.RemoveSingle(playerCollider)
|
dynamicCollider := dynamicRectangleColliders[i]
|
||||||
|
dynamicCollider.Space.RemoveSingle(dynamicCollider)
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.Id = nextRenderFrameId
|
ret.Id = nextRenderFrameId
|
||||||
@ -1222,6 +1234,15 @@ func generateRectColliderInCollisionSpace(blX, blY, w, h float64, data interface
|
|||||||
return collider
|
return collider
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UpdateRectCollider(collider *resolv.Object, wx, wy, w, h, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY float64, data interface{}, tag string) {
|
||||||
|
blX, blY := WorldToPolygonColliderBLPos(wx, wy, w*0.5, h*0.5, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY)
|
||||||
|
collider.X, collider.Y, collider.W, collider.H = blX, blY, w, h
|
||||||
|
rectShape := collider.Shape.(*resolv.ConvexPolygon)
|
||||||
|
rectShape.UpdateAsRectangle(0, 0, w, h)
|
||||||
|
collider.Data = data
|
||||||
|
// Ignore "tag" for now
|
||||||
|
}
|
||||||
|
|
||||||
func GenerateConvexPolygonCollider(unalignedSrc *Polygon2D, spaceOffsetX, spaceOffsetY float64, data interface{}, tag string) *resolv.Object {
|
func GenerateConvexPolygonCollider(unalignedSrc *Polygon2D, spaceOffsetX, spaceOffsetY float64, data interface{}, tag string) *resolv.Object {
|
||||||
aligned := AlignPolygon2DToBoundingBox(unalignedSrc)
|
aligned := AlignPolygon2DToBoundingBox(unalignedSrc)
|
||||||
var w, h float64 = 0, 0
|
var w, h float64 = 0, 0
|
||||||
|
@ -9,6 +9,14 @@ import (
|
|||||||
/*
|
/*
|
||||||
[WARNING] Should avoid using "MakeFullWrapper" as much as possible, and completely remove its usage in 60fps calls like "update(dt)" on frontend!
|
[WARNING] Should avoid using "MakeFullWrapper" as much as possible, and completely remove its usage in 60fps calls like "update(dt)" on frontend!
|
||||||
*/
|
*/
|
||||||
|
func NewDynamicRectangleColliders(cnt int) []*js.Object {
|
||||||
|
ret := make([]*js.Object, cnt)
|
||||||
|
for i := 0; i < cnt; i++ {
|
||||||
|
ret[i] = js.MakeWrapper(GenerateRectCollider(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nil, ""))
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
func NewCollisionHolder() *js.Object {
|
func NewCollisionHolder() *js.Object {
|
||||||
return js.MakeWrapper(resolv.NewCollision())
|
return js.MakeWrapper(resolv.NewCollision())
|
||||||
}
|
}
|
||||||
@ -103,9 +111,9 @@ func GetCharacterConfigsOrderedByJoinIndex(speciesIdList []int) []*js.Object {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrameJs(inputsBuffer *resolv.RingBuffer, currRenderFrameId int32, collisionSys *resolv.Space, collisionSysMap map[int32]*resolv.Object, collisionSpaceOffsetX, collisionSpaceOffsetY float64, chConfigsOrderedByJoinIndex []*CharacterConfig, renderFrameBuffer *resolv.RingBuffer, collision *resolv.Collision, effPushbacks []*Vec2D, hardPushbackNormsArr [][]*Vec2D, jumpedOrNotList []bool) bool {
|
func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrameJs(inputsBuffer *resolv.RingBuffer, currRenderFrameId int32, collisionSys *resolv.Space, collisionSysMap map[int32]*resolv.Object, collisionSpaceOffsetX, collisionSpaceOffsetY float64, chConfigsOrderedByJoinIndex []*CharacterConfig, renderFrameBuffer *resolv.RingBuffer, collision *resolv.Collision, effPushbacks []*Vec2D, hardPushbackNormsArr [][]*Vec2D, jumpedOrNotList []bool, dynamicRectangleColliders []*resolv.Object) bool {
|
||||||
// We need access to all fields of RoomDownsyncFrame for displaying in frontend
|
// We need access to all fields of RoomDownsyncFrame for displaying in frontend
|
||||||
return ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer, currRenderFrameId, collisionSys, collisionSysMap, collisionSpaceOffsetX, collisionSpaceOffsetY, chConfigsOrderedByJoinIndex, renderFrameBuffer, collision, effPushbacks, hardPushbackNormsArr, jumpedOrNotList)
|
return ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer, currRenderFrameId, collisionSys, collisionSysMap, collisionSpaceOffsetX, collisionSpaceOffsetY, chConfigsOrderedByJoinIndex, renderFrameBuffer, collision, effPushbacks, hardPushbackNormsArr, jumpedOrNotList, dynamicRectangleColliders)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetRoomDownsyncFrame(renderFrameBuffer *resolv.RingBuffer, frameId int32) *js.Object {
|
func GetRoomDownsyncFrame(renderFrameBuffer *resolv.RingBuffer, frameId int32) *js.Object {
|
||||||
@ -183,5 +191,6 @@ func main() {
|
|||||||
"GetMeleeBullet": GetMeleeBullet,
|
"GetMeleeBullet": GetMeleeBullet,
|
||||||
"GetFireballBullet": GetFireballBullet,
|
"GetFireballBullet": GetFireballBullet,
|
||||||
"GetInput": GetInput,
|
"GetInput": GetInput,
|
||||||
|
"NewDynamicRectangleColliders": NewDynamicRectangleColliders,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ func (cc *Collision) Clear() {
|
|||||||
cc.Cells.Clear()
|
cc.Cells.Clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cc *Collision) FirstCollidedObject() *Object {
|
func (cc *Collision) PopFirstCollidedObject() *Object {
|
||||||
if 0 >= cc.Objects.Cnt {
|
if 0 >= cc.Objects.Cnt {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -254,7 +254,7 @@ func (obj *Object) CheckAllWithHolder(dx, dy float64, cc *Collision) bool {
|
|||||||
if obj.Space == nil {
|
if obj.Space == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
cc.Clear()
|
||||||
cc.checkingObject = obj
|
cc.checkingObject = obj
|
||||||
|
|
||||||
if dx < 0 {
|
if dx < 0 {
|
||||||
|
@ -125,7 +125,7 @@ func (line *Line) IntersectionPointsCircle(circle *Circle) []Vector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ConvexPolygon struct {
|
type ConvexPolygon struct {
|
||||||
Points []Vector
|
Points *RingBuffer
|
||||||
X, Y float64
|
X, Y float64
|
||||||
Closed bool
|
Closed bool
|
||||||
}
|
}
|
||||||
@ -135,46 +135,72 @@ type ConvexPolygon struct {
|
|||||||
// polygon square, with the vertices at {0,0}, {10,0}, {10, 10}, and {0, 10}.
|
// polygon square, with the vertices at {0,0}, {10,0}, {10, 10}, and {0, 10}.
|
||||||
func NewConvexPolygon(points ...float64) *ConvexPolygon {
|
func NewConvexPolygon(points ...float64) *ConvexPolygon {
|
||||||
|
|
||||||
// if len(points)/2 < 2 {
|
cp := &ConvexPolygon{
|
||||||
// return nil
|
Points: NewRingBuffer(6), // I don't expected more points to be coped with in this particular game
|
||||||
// }
|
Closed: true,
|
||||||
|
}
|
||||||
cp := &ConvexPolygon{Points: []Vector{}, Closed: true}
|
|
||||||
|
|
||||||
cp.AddPoints(points...)
|
cp.AddPoints(points...)
|
||||||
|
|
||||||
return cp
|
return cp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *ConvexPolygon) Clone() Shape {
|
func (cp *ConvexPolygon) GetPointByOffset(offset int32) Vector {
|
||||||
|
if cp.Points.Cnt <= offset {
|
||||||
points := []Vector{}
|
return nil
|
||||||
|
|
||||||
for _, point := range cp.Points {
|
|
||||||
points = append(points, point.Clone())
|
|
||||||
}
|
}
|
||||||
|
return cp.Points.GetByFrameId(cp.Points.StFrameId + offset).(Vector)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cp *ConvexPolygon) Clone() Shape {
|
||||||
|
|
||||||
newPoly := NewConvexPolygon()
|
newPoly := NewConvexPolygon()
|
||||||
newPoly.X = cp.X
|
newPoly.X = cp.X
|
||||||
newPoly.Y = cp.Y
|
newPoly.Y = cp.Y
|
||||||
newPoly.AddPointsVec(points...)
|
for i := int32(0); i < cp.Points.Cnt; i++ {
|
||||||
|
newPoly.Points.Put(cp.GetPointByOffset(i))
|
||||||
|
}
|
||||||
newPoly.Closed = cp.Closed
|
newPoly.Closed = cp.Closed
|
||||||
return newPoly
|
return newPoly
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddPointsVec allows you to add points to the ConvexPolygon with a slice of Vectors, each indicating a point / vertex.
|
|
||||||
func (cp *ConvexPolygon) AddPointsVec(points ...Vector) {
|
|
||||||
cp.Points = append(cp.Points, points...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddPoints allows you to add points to the ConvexPolygon with a slice or selection of float64s, with each pair indicating an X or Y value for
|
// AddPoints allows you to add points to the ConvexPolygon with a slice or selection of float64s, with each pair indicating an X or Y value for
|
||||||
// a point / vertex (i.e. AddPoints(0, 1, 2, 3) would add two points - one at {0, 1}, and another at {2, 3}).
|
// a point / vertex (i.e. AddPoints(0, 1, 2, 3) would add two points - one at {0, 1}, and another at {2, 3}).
|
||||||
func (cp *ConvexPolygon) AddPoints(vertexPositions ...float64) {
|
func (cp *ConvexPolygon) AddPoints(vertexPositions ...float64) {
|
||||||
for v := 0; v < len(vertexPositions); v += 2 {
|
for v := 0; v < len(vertexPositions); v += 2 {
|
||||||
cp.Points = append(cp.Points, Vector{vertexPositions[v], vertexPositions[v+1]})
|
// "resolv.Vector" is an alias of "[]float64", thus already a pointer type
|
||||||
|
cp.Points.Put(Vector{vertexPositions[v], vertexPositions[v+1]})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cp *ConvexPolygon) UpdateAsRectangle(x, y, w, h float64) bool {
|
||||||
|
// This function might look ugly but it's a fast in-place update!
|
||||||
|
if 4 != cp.Points.Cnt {
|
||||||
|
panic("ConvexPolygon not having exactly 4 vertices to form a rectangle#1!")
|
||||||
|
}
|
||||||
|
for i := int32(0); i < cp.Points.Cnt; i++ {
|
||||||
|
thatVec := cp.GetPointByOffset(i)
|
||||||
|
if nil == thatVec {
|
||||||
|
panic("ConvexPolygon not having exactly 4 vertices to form a rectangle#2!")
|
||||||
|
}
|
||||||
|
switch i {
|
||||||
|
case 0:
|
||||||
|
thatVec[0] = x
|
||||||
|
thatVec[1] = y
|
||||||
|
case 1:
|
||||||
|
thatVec[0] = x + w
|
||||||
|
thatVec[1] = y
|
||||||
|
case 2:
|
||||||
|
thatVec[0] = x + w
|
||||||
|
thatVec[1] = y + h
|
||||||
|
case 3:
|
||||||
|
thatVec[0] = x
|
||||||
|
thatVec[1] = y + h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// Lines returns a slice of transformed Lines composing the ConvexPolygon.
|
// Lines returns a slice of transformed Lines composing the ConvexPolygon.
|
||||||
func (cp *ConvexPolygon) Lines() []*Line {
|
func (cp *ConvexPolygon) Lines() []*Line {
|
||||||
|
|
||||||
@ -200,8 +226,9 @@ func (cp *ConvexPolygon) Lines() []*Line {
|
|||||||
|
|
||||||
// Transformed returns the ConvexPolygon's points / vertices, transformed according to the ConvexPolygon's position.
|
// Transformed returns the ConvexPolygon's points / vertices, transformed according to the ConvexPolygon's position.
|
||||||
func (cp *ConvexPolygon) Transformed() []Vector {
|
func (cp *ConvexPolygon) Transformed() []Vector {
|
||||||
transformed := make([]Vector, len(cp.Points))
|
transformed := make([]Vector, cp.Points.Cnt)
|
||||||
for i, point := range cp.Points {
|
for i := int32(0); i < cp.Points.Cnt; i++ {
|
||||||
|
point := cp.GetPointByOffset(i)
|
||||||
transformed[i] = Vector{point[0] + cp.X, point[1] + cp.Y}
|
transformed[i] = Vector{point[0] + cp.X, point[1] + cp.Y}
|
||||||
}
|
}
|
||||||
return transformed
|
return transformed
|
||||||
@ -331,10 +358,6 @@ func (polygon *ConvexPolygon) PointInside(point Vector) bool {
|
|||||||
return contactCount == 1
|
return contactCount == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (polygon *ConvexPolygon) GetPoints() []Vector {
|
|
||||||
return polygon.Points
|
|
||||||
}
|
|
||||||
|
|
||||||
type ContactSet struct {
|
type ContactSet struct {
|
||||||
Points []Vector // Slice of Points indicating contact between the two Shapes.
|
Points []Vector // Slice of Points indicating contact between the two Shapes.
|
||||||
MTV Vector // Minimum Translation Vector; this is the vector to move a Shape on to move it outside of its contacting Shape.
|
MTV Vector // Minimum Translation Vector; this is the vector to move a Shape on to move it outside of its contacting Shape.
|
||||||
@ -553,42 +576,6 @@ func (cp *ConvexPolygon) ContainedBy(otherShape Shape) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlipH flips the ConvexPolygon's vertices horizontally according to their initial offset when adding the points.
|
|
||||||
func (cp *ConvexPolygon) FlipH() {
|
|
||||||
|
|
||||||
for _, v := range cp.Points {
|
|
||||||
v[0] = -v[0]
|
|
||||||
}
|
|
||||||
// We have to reverse vertex order after flipping the vertices to ensure the winding order is consistent between Objects (so that the normals are consistently outside or inside, which is important
|
|
||||||
// when doing Intersection tests). If we assume that the normal of a line, going from vertex A to vertex B, is one direction, then the normal would be inverted if the vertices were flipped in position,
|
|
||||||
// but not in order. This would make Intersection tests drive objects into each other, instead of giving the delta to move away.
|
|
||||||
cp.ReverseVertexOrder()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// FlipV flips the ConvexPolygon's vertices vertically according to their initial offset when adding the points.
|
|
||||||
func (cp *ConvexPolygon) FlipV() {
|
|
||||||
|
|
||||||
for _, v := range cp.Points {
|
|
||||||
v[1] = -v[1]
|
|
||||||
}
|
|
||||||
cp.ReverseVertexOrder()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReverseVertexOrder reverses the vertex ordering of the ConvexPolygon.
|
|
||||||
func (cp *ConvexPolygon) ReverseVertexOrder() {
|
|
||||||
|
|
||||||
verts := []Vector{cp.Points[0]}
|
|
||||||
|
|
||||||
for i := len(cp.Points) - 1; i >= 1; i-- {
|
|
||||||
verts = append(verts, cp.Points[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
cp.Points = verts
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRectangle returns a rectangular ConvexPolygon with the vertices in clockwise order. In actuality, an AABBRectangle should be its own
|
// NewRectangle returns a rectangular ConvexPolygon with the vertices in clockwise order. In actuality, an AABBRectangle should be its own
|
||||||
// "thing" with its own optimized Intersection code check.
|
// "thing" with its own optimized Intersection code check.
|
||||||
func NewRectangle(x, y, w, h float64) *ConvexPolygon {
|
func NewRectangle(x, y, w, h float64) *ConvexPolygon {
|
||||||
|
Loading…
Reference in New Issue
Block a user