mirror of
https://github.com/genxium/DelayNoMore
synced 2025-10-09 08:36:52 +00:00
Initial trial and error draft of using gopherjs.
This commit is contained in:
25
jsexport/Makefile
Normal file
25
jsexport/Makefile
Normal file
@@ -0,0 +1,25 @@
|
||||
PROJECTNAME=jsexport
|
||||
ROOT_DIR=.
|
||||
all: help
|
||||
## Available proxies for downloading go modules are listed in "https://github.com/golang/go/wiki/Modules#how-do-i-use-vendoring-with-modules-is-vendoring-going-away".
|
||||
#GOPROXY=https://mirrors.aliyun.com/goproxy
|
||||
GOPROXY=https://goproxy.io
|
||||
|
||||
serve:
|
||||
gopherjs serve $(PROJECTNAME)
|
||||
|
||||
build:
|
||||
gopherjs build $(PROJECTNAME)
|
||||
|
||||
build-min:
|
||||
gopherjs build -m $(PROJECTNAME)
|
||||
|
||||
.PHONY: help
|
||||
|
||||
help: Makefile
|
||||
@echo
|
||||
@echo " Choose a command run:"
|
||||
@echo
|
||||
@sed -n 's/^##//p' $< | column -t -s ':' | sed -e 's/^/ /'
|
||||
@echo
|
||||
|
5
jsexport/README.md
Normal file
5
jsexport/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
GopherJs is supposed to be run by `go run`.
|
||||
|
||||
If on-the-fly compilation is needed, run `gopherjs serve jsexport` and then visit `http://localhost:8080/jsexport.js` -- if 404 not found is responded, run `gopherjs build` to check syntax errors.
|
||||
|
||||
See the `Makefile` for more options.
|
19
jsexport/go.mod
Normal file
19
jsexport/go.mod
Normal file
@@ -0,0 +1,19 @@
|
||||
module jsexport
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
dnmshared v0.0.0
|
||||
github.com/gopherjs/gopherjs v1.18.0-beta1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/kvartborg/vector v0.0.0-20200419093813-2cba0cabb4f0 // indirect
|
||||
github.com/solarlune/resolv v0.5.1 // indirect
|
||||
go.uber.org/atomic v1.3.2 // indirect
|
||||
go.uber.org/multierr v1.1.0 // indirect
|
||||
go.uber.org/zap v1.9.1 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
)
|
||||
|
||||
replace dnmshared => ../dnmshared
|
20
jsexport/go.sum
Normal file
20
jsexport/go.sum
Normal file
@@ -0,0 +1,20 @@
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
|
||||
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
|
||||
github.com/gopherjs/gopherjs v1.18.0-beta1 h1:IbykhVEq4SAjwyBRuNHl0aOO6w6IqgL3RUdMhoBo4mY=
|
||||
github.com/gopherjs/gopherjs v1.18.0-beta1/go.mod h1:6UY8PXRnu51MqjYCCY4toG0S5GeH5uVJ3qDxIsa+kqo=
|
||||
github.com/kvartborg/vector v0.0.0-20200419093813-2cba0cabb4f0 h1:v8lWpj5957KtDMKu+xQtlu6G3ZoZR6Tn9bsfZCRG5Xw=
|
||||
github.com/kvartborg/vector v0.0.0-20200419093813-2cba0cabb4f0/go.mod h1:GAX7tMJqXx9fB1BrsTWPOXy6IBRX+J461BffVPAdpwo=
|
||||
github.com/solarlune/resolv v0.5.1 h1:Ul6PAs/zaxiMUOEYz1Z6VeUj5k3CDcWMvSh+kivybDY=
|
||||
github.com/solarlune/resolv v0.5.1/go.mod h1:HjM2f/0NoVjVdZsi26GtugX5aFbA62COEFEXkOhveRw=
|
||||
go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
18
jsexport/index.html
Normal file
18
jsexport/index.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<html>
|
||||
<head>
|
||||
<script src="jsexport.js"></script>
|
||||
</head>
|
||||
<script>
|
||||
var minStep = 8;
|
||||
var space = gopkgs.NewCollisionSpaceJs(2048, 2048, 8, 8);
|
||||
var snapIntoPlatformOverlap = 0.1;
|
||||
var spaceOffsetX = 0;
|
||||
var spaceOffsetY = 0;
|
||||
var a = gopkgs.GenerateRectColliderJs(189, 497, 48, 48, snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap, spaceOffsetX, spaceOffsetY, "Player");
|
||||
space.Add(a);
|
||||
var b = gopkgs.GenerateRectColliderJs(189, 504, 48, 48, snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap, spaceOffsetX, spaceOffsetY, "Player");
|
||||
space.Add(b);
|
||||
var collision = gopkgs.CheckCollisionJs(a, 0, 0);
|
||||
console.log(collision);
|
||||
</script>
|
||||
</html>
|
210240
jsexport/jsexport.js
Normal file
210240
jsexport/jsexport.js
Normal file
File diff suppressed because one or more lines are too long
1
jsexport/jsexport.js.map
Normal file
1
jsexport/jsexport.js.map
Normal file
File diff suppressed because one or more lines are too long
315
jsexport/main.go
Normal file
315
jsexport/main.go
Normal file
@@ -0,0 +1,315 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gopherjs/gopherjs/js"
|
||||
"github.com/solarlune/resolv"
|
||||
"dnmshared"
|
||||
. "dnmshared/sharedprotos"
|
||||
. "jsexport/protos"
|
||||
. "jsexport/models"
|
||||
)
|
||||
|
||||
var DIRECTION_DECODER = [][]int32{
|
||||
{0, 0},
|
||||
{0, +2},
|
||||
{0, -2},
|
||||
{+2, 0},
|
||||
{-2, 0},
|
||||
{+1, +1},
|
||||
{-1, -1},
|
||||
{+1, -1},
|
||||
{-1, +1},
|
||||
}
|
||||
|
||||
func ConvertToInputFrameId(renderFrameId int32, inputDelayFrames int32, inputScaleFrames int32) int32 {
|
||||
if renderFrameId < inputDelayFrames {
|
||||
return 0
|
||||
}
|
||||
return ((renderFrameId - inputDelayFrames) >> inputScaleFrames)
|
||||
}
|
||||
|
||||
func DecodeInput(encodedInput uint64) *InputFrameDecoded {
|
||||
encodedDirection := (encodedInput & uint64(15))
|
||||
btnALevel := int32((encodedInput >> 4) & 1)
|
||||
btnBLevel := int32((encodedInput >> 5) & 1)
|
||||
return &InputFrameDecoded{
|
||||
Dx: DIRECTION_DECODER[encodedDirection][0],
|
||||
Dy: DIRECTION_DECODER[encodedDirection][1],
|
||||
BtnALevel: btnALevel,
|
||||
BtnBLevel: btnBLevel,
|
||||
}
|
||||
}
|
||||
|
||||
func CalcHardPushbacksNorms(playerCollider *resolv.Object, playerShape *resolv.ConvexPolygon, snapIntoPlatformOverlap float64, pEffPushback *Vec2D) []Vec2D {
|
||||
ret := make([]Vec2D, 0, 10) // no one would simultaneously have more than 5 hardPushbacks
|
||||
collision := playerCollider.Check(0, 0)
|
||||
if nil == collision {
|
||||
return ret
|
||||
}
|
||||
for _, obj := range collision.Objects {
|
||||
switch obj.Data.(type) {
|
||||
case *Barrier:
|
||||
barrierShape := obj.Shape.(*resolv.ConvexPolygon)
|
||||
overlapped, pushbackX, pushbackY, overlapResult := dnmshared.CalcPushbacks(0, 0, playerShape, barrierShape)
|
||||
if !overlapped {
|
||||
continue
|
||||
}
|
||||
// ALWAY snap into hardPushbacks!
|
||||
// [OverlapX, OverlapY] is the unit vector that points into the platform
|
||||
pushbackX, pushbackY = (overlapResult.Overlap-snapIntoPlatformOverlap)*overlapResult.OverlapX, (overlapResult.Overlap-snapIntoPlatformOverlap)*overlapResult.OverlapY
|
||||
ret = append(ret, Vec2D{X: overlapResult.OverlapX, Y: overlapResult.OverlapY})
|
||||
pEffPushback.X += pushbackX
|
||||
pEffPushback.Y += pushbackY
|
||||
default:
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func NewRingBufferJs(n int32) *js.Object {
|
||||
return js.MakeWrapper(dnmshared.NewRingBuffer(n));
|
||||
}
|
||||
|
||||
func NewCollisionSpaceJs(spaceW, spaceH, minStepW, minStepH int) *js.Object {
|
||||
return js.MakeWrapper(resolv.NewSpace(spaceW, spaceH, minStepW, minStepH))
|
||||
}
|
||||
|
||||
func GenerateRectColliderJs(wx, wy, w, h, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY float64, tag string) *js.Object {
|
||||
/*
|
||||
[WARNING] It's important to note that we don't need "js.MakeFullWrapper" for a call sequence as follows.
|
||||
```
|
||||
var space = gopkgs.NewCollisionSpaceJs(2048, 2048, 8, 8);
|
||||
var a = gopkgs.GenerateRectColliderJs(189, 497, 48, 48, snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap, spaceOffsetX, spaceOffsetY, "Player");
|
||||
space.Add(a);
|
||||
```
|
||||
The "space" variable doesn't need access to the field of "a" in JavaScript level to run "space.Add(...)" method, which is good.
|
||||
*/
|
||||
return js.MakeWrapper(dnmshared.GenerateRectCollider(wx, wy, w, h, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, tag));
|
||||
|
||||
}
|
||||
|
||||
func CheckCollisionJs(obj *resolv.Object, dx, dy float64) *js.Object {
|
||||
// TODO: Support multiple tags in the future
|
||||
// Unfortunately I couldn't find a way to just call "var a = GenerateRectColliderJs(...); space.Add(a); a.Check(...)" to get the collision result, the unwrapped method will result in stack overflow. Need a better solution later.
|
||||
return js.MakeFullWrapper(obj.Check(dx, dy));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame *InputFrameDownsync, currRenderFrame *RoomDownsyncFrame, collisionSysMap map[int32]*resolv.Object, topPadding, bottomPadding, leftPadding, rightPadding float64, roomCapacity int, jumpingInitVelY int32, playersArr []*Player, inputDelayFrames int32, inputScaleFrames int32, inputsBuffer *RingBuffer, collisionSpaceOffsetX, collisionSpaceOffsetY int32, snapIntoPlatformOverlap, worldToVirtualGridRatio, virtualGridToWorldRatio float64) *RoomDownsyncFrame {
|
||||
// [WARNING] This function MUST BE called while "InputsBufferLock" is locked!
|
||||
nextRenderFramePlayers := make(map[int32]*PlayerDownsync, roomCapacity)
|
||||
// Make a copy first
|
||||
for playerId, currPlayerDownsync := range currRenderFrame.Players {
|
||||
nextRenderFramePlayers[playerId] = &PlayerDownsync{
|
||||
Id: playerId,
|
||||
VirtualGridX: currPlayerDownsync.VirtualGridX,
|
||||
VirtualGridY: currPlayerDownsync.VirtualGridY,
|
||||
DirX: currPlayerDownsync.DirX,
|
||||
DirY: currPlayerDownsync.DirY,
|
||||
VelX: currPlayerDownsync.VelX,
|
||||
VelY: currPlayerDownsync.VelY,
|
||||
CharacterState: currPlayerDownsync.CharacterState,
|
||||
InAir: true,
|
||||
Speed: currPlayerDownsync.Speed,
|
||||
BattleState: currPlayerDownsync.BattleState,
|
||||
Score: currPlayerDownsync.Score,
|
||||
Removed: currPlayerDownsync.Removed,
|
||||
JoinIndex: currPlayerDownsync.JoinIndex,
|
||||
FramesToRecover: currPlayerDownsync.FramesToRecover - 1,
|
||||
Hp: currPlayerDownsync.Hp,
|
||||
MaxHp: currPlayerDownsync.MaxHp,
|
||||
}
|
||||
if nextRenderFramePlayers[playerId].FramesToRecover < 0 {
|
||||
nextRenderFramePlayers[playerId].FramesToRecover = 0
|
||||
}
|
||||
}
|
||||
|
||||
nextRenderFrameMeleeBullets := make([]*MeleeBullet, 0, len(currRenderFrame.MeleeBullets)) // Is there any better way to reduce malloc/free impact, e.g. smart prediction for fixed memory allocation?
|
||||
effPushbacks := make([]Vec2D, roomCapacity)
|
||||
hardPushbackNorms := make([][]Vec2D, roomCapacity)
|
||||
|
||||
// 1. Process player inputs
|
||||
if nil != delayedInputFrame {
|
||||
var delayedInputFrameForPrevRenderFrame *InputFrameDownsync = nil
|
||||
tmp := inputsBuffer.GetByFrameId(ConvertToInputFrameId(currRenderFrame.Id-1, inputDelayFrames, inputScaleFrames))
|
||||
if nil != tmp {
|
||||
delayedInputFrameForPrevRenderFrame = tmp.(*InputFrameDownsync)
|
||||
}
|
||||
inputList := delayedInputFrame.InputList
|
||||
for _, player := range playersArr {
|
||||
playerId := player.Id
|
||||
joinIndex := player.JoinIndex
|
||||
currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
|
||||
if 0 < thatPlayerInNextFrame.FramesToRecover {
|
||||
continue
|
||||
}
|
||||
decodedInput := DecodeInput(inputList[joinIndex-1])
|
||||
prevBtnALevel, prevBtnBLevel := int32(0), int32(0)
|
||||
if nil != delayedInputFrameForPrevRenderFrame {
|
||||
prevDecodedInput := DecodeInput(delayedInputFrameForPrevRenderFrame.InputList[joinIndex-1])
|
||||
prevBtnALevel = prevDecodedInput.BtnALevel
|
||||
prevBtnBLevel = prevDecodedInput.BtnBLevel
|
||||
}
|
||||
|
||||
if decodedInput.BtnBLevel > prevBtnBLevel {
|
||||
characStateAlreadyInAir := false
|
||||
if ATK_CHARACTER_STATE_INAIR_IDLE1 == thatPlayerInNextFrame.CharacterState || ATK_CHARACTER_STATE_INAIR_ATK1 == thatPlayerInNextFrame.CharacterState || ATK_CHARACTER_STATE_INAIR_ATKED1 == thatPlayerInNextFrame.CharacterState {
|
||||
characStateAlreadyInAir = true
|
||||
}
|
||||
characStateIsInterruptWaivable := false
|
||||
if ATK_CHARACTER_STATE_IDLE1 == thatPlayerInNextFrame.CharacterState || ATK_CHARACTER_STATE_WALKING == thatPlayerInNextFrame.CharacterState || ATK_CHARACTER_STATE_INAIR_IDLE1 == thatPlayerInNextFrame.CharacterState {
|
||||
characStateIsInterruptWaivable = true
|
||||
}
|
||||
if !characStateAlreadyInAir && characStateIsInterruptWaivable {
|
||||
thatPlayerInNextFrame.VelY = jumpingInitVelY
|
||||
}
|
||||
}
|
||||
|
||||
// Note that by now "0 == thatPlayerInNextFrame.FramesToRecover", we should change "CharacterState" to "WALKING" or "IDLE" depending on player inputs
|
||||
if 0 != decodedInput.Dx || 0 != decodedInput.Dy {
|
||||
thatPlayerInNextFrame.DirX = decodedInput.Dx
|
||||
thatPlayerInNextFrame.DirY = decodedInput.Dy
|
||||
thatPlayerInNextFrame.VelX = decodedInput.Dx * currPlayerDownsync.Speed
|
||||
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_WALKING
|
||||
} else {
|
||||
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_IDLE1
|
||||
thatPlayerInNextFrame.VelX = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Process player movement
|
||||
for _, player := range playersArr {
|
||||
playerId := player.Id
|
||||
joinIndex := player.JoinIndex
|
||||
effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y = float64(0), float64(0)
|
||||
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
|
||||
playerCollider := collisionSysMap[collisionPlayerIndex]
|
||||
currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
|
||||
// Reset playerCollider position from the "virtual grid position"
|
||||
newVx, newVy := currPlayerDownsync.VirtualGridX+currPlayerDownsync.VelX, currPlayerDownsync.VirtualGridY+currPlayerDownsync.VelY
|
||||
if thatPlayerInNextFrame.VelY == jumpingInitVelY {
|
||||
newVy += thatPlayerInNextFrame.VelY
|
||||
}
|
||||
|
||||
halfColliderWidth, halfColliderHeight := player.ColliderRadius, player.ColliderRadius+player.ColliderRadius // avoid multiplying
|
||||
playerCollider.X, playerCollider.Y = VirtualGridToPolygonColliderBLPos(newVx, newVy, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY, virtualGridToWorldRatio)
|
||||
// Update in the collision system
|
||||
playerCollider.Update()
|
||||
|
||||
if currPlayerDownsync.InAir {
|
||||
thatPlayerInNextFrame.VelX += gravityX
|
||||
thatPlayerInNextFrame.VelY += gravityY
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Invoke collision system stepping (no-op for backend collision lib)
|
||||
|
||||
// 4. Calc pushbacks for each player (after its movement) w/o bullets
|
||||
for _, player := range playersArr {
|
||||
joinIndex := player.JoinIndex
|
||||
playerId := player.Id
|
||||
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
|
||||
playerCollider := collisionSysMap[collisionPlayerIndex]
|
||||
playerShape := playerCollider.Shape.(*resolv.ConvexPolygon)
|
||||
hardPushbackNorms[joinIndex-1] = CalcHardPushbacksNorms(playerCollider, playerShape, snapIntoPlatformOverlap, &(effPushbacks[joinIndex-1]))
|
||||
currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
|
||||
fallStopping := false
|
||||
possiblyFallStoppedOnAnotherPlayer := false
|
||||
if collision := playerCollider.Check(0, 0); nil != collision {
|
||||
for _, obj := range collision.Objects {
|
||||
isBarrier, isAnotherPlayer, isBullet := false, false, false
|
||||
switch obj.Data.(type) {
|
||||
case *Barrier:
|
||||
isBarrier = true
|
||||
case *Player:
|
||||
isAnotherPlayer = true
|
||||
case *MeleeBullet:
|
||||
isBullet = true
|
||||
}
|
||||
if isBullet {
|
||||
// ignore bullets for this step
|
||||
continue
|
||||
}
|
||||
bShape := obj.Shape.(*resolv.ConvexPolygon)
|
||||
overlapped, pushbackX, pushbackY, overlapResult := dnmshared.CalcPushbacks(0, 0, playerShape, bShape)
|
||||
if !overlapped {
|
||||
continue
|
||||
}
|
||||
normAlignmentWithGravity := (overlapResult.OverlapX*float64(0) + overlapResult.OverlapY*float64(-1.0))
|
||||
landedOnGravityPushback := (snapIntoPlatformThreshold < normAlignmentWithGravity) // prevents false snapping on the lateral sides
|
||||
if landedOnGravityPushback {
|
||||
// kindly note that one player might land on top of another player, and snapping is also required in such case
|
||||
pushbackX, pushbackY = (overlapResult.Overlap-snapIntoPlatformOverlap)*overlapResult.OverlapX, (overlapResult.Overlap-snapIntoPlatformOverlap)*overlapResult.OverlapY
|
||||
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.
|
||||
pushbackX, pushbackY = (overlapResult.Overlap-snapIntoPlatformOverlap*2)*overlapResult.OverlapX, (overlapResult.Overlap-snapIntoPlatformOverlap*2)*overlapResult.OverlapY
|
||||
}
|
||||
for _, hardPushbackNorm := range hardPushbackNorms[joinIndex-1] {
|
||||
projectedMagnitude := pushbackX*hardPushbackNorm.X + pushbackY*hardPushbackNorm.Y
|
||||
if isBarrier || (isAnotherPlayer && 0 > projectedMagnitude) {
|
||||
pushbackX -= projectedMagnitude * hardPushbackNorm.X
|
||||
pushbackY -= projectedMagnitude * hardPushbackNorm.Y
|
||||
}
|
||||
}
|
||||
effPushbacks[joinIndex-1].X += pushbackX
|
||||
effPushbacks[joinIndex-1].Y += pushbackY
|
||||
if currPlayerDownsync.InAir && landedOnGravityPushback {
|
||||
fallStopping = true
|
||||
if isAnotherPlayer {
|
||||
possiblyFallStoppedOnAnotherPlayer = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if fallStopping {
|
||||
thatPlayerInNextFrame.VelX = 0
|
||||
thatPlayerInNextFrame.VelY = 0
|
||||
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_IDLE1
|
||||
thatPlayerInNextFrame.FramesToRecover = 0
|
||||
}
|
||||
if currPlayerDownsync.InAir {
|
||||
oldNextCharacterState := thatPlayerInNextFrame.CharacterState
|
||||
switch oldNextCharacterState {
|
||||
case ATK_CHARACTER_STATE_IDLE1, ATK_CHARACTER_STATE_WALKING:
|
||||
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_IDLE1
|
||||
case ATK_CHARACTER_STATE_ATK1:
|
||||
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_ATK1
|
||||
case ATK_CHARACTER_STATE_ATKED1:
|
||||
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_ATKED1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 7. Get players out of stuck barriers if there's any
|
||||
for _, player := range playersArr {
|
||||
joinIndex := player.JoinIndex
|
||||
playerId := player.Id
|
||||
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
|
||||
playerCollider := collisionSysMap[collisionPlayerIndex]
|
||||
// Update "virtual grid position"
|
||||
currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
|
||||
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, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY, worldToVirtualGridRatio)
|
||||
}
|
||||
|
||||
return &RoomDownsyncFrame{
|
||||
Id: currRenderFrame.Id + 1,
|
||||
Players: nextRenderFramePlayers,
|
||||
MeleeBullets: nextRenderFrameMeleeBullets,
|
||||
CountdownNanos: (BattleDurationNanos - int64(currRenderFrame.Id)*RollbackEstimatedDtNanos),
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
func main() {
|
||||
js.Global.Set("gopkgs", map[string]interface{}{
|
||||
"NewRingBufferJs": NewRingBufferJs,
|
||||
"NewCollisionSpaceJs": NewCollisionSpaceJs,
|
||||
"GenerateRectColliderJs": GenerateRectColliderJs,
|
||||
"CheckCollisionJs": CheckCollisionJs,
|
||||
})
|
||||
}
|
9
jsexport/models/barrier.go
Normal file
9
jsexport/models/barrier.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
. "dnmshared/sharedprotos"
|
||||
)
|
||||
|
||||
type Barrier struct {
|
||||
Boundary *Polygon2D
|
||||
}
|
1817
jsexport/protos/room_downsync_frame.pb.go
Normal file
1817
jsexport/protos/room_downsync_frame.pb.go
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user