mirror of
https://github.com/genxium/DelayNoMore
synced 2024-12-26 03:39:00 +00:00
Preparation of server-side collision calc.
This commit is contained in:
parent
ff092a40ed
commit
14fb8e94b2
@ -7,7 +7,6 @@ import (
|
|||||||
type Barrier struct {
|
type Barrier struct {
|
||||||
X float64
|
X float64
|
||||||
Y float64
|
Y float64
|
||||||
Type uint32
|
|
||||||
Boundary *Polygon2D
|
Boundary *Polygon2D
|
||||||
CollidableBody *box2d.B2Body
|
CollidableBody *box2d.B2Body
|
||||||
}
|
}
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
package models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/ByteArena/box2d"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Bullet struct {
|
|
||||||
LocalIdInBattle int32 `json:"-"`
|
|
||||||
LinearSpeed float64 `json:"-"`
|
|
||||||
X float64 `json:"-"`
|
|
||||||
Y float64 `json:"-"`
|
|
||||||
Removed bool `json:"-"`
|
|
||||||
Dir *Direction `json:"-"`
|
|
||||||
StartAtPoint *Vec2D `json:"-"`
|
|
||||||
EndAtPoint *Vec2D `json:"-"`
|
|
||||||
DamageBoundary *Polygon2D `json:"-"`
|
|
||||||
CollidableBody *box2d.B2Body `json:"-"`
|
|
||||||
RemovedAtFrameId int32 `json:"-"`
|
|
||||||
}
|
|
@ -90,114 +90,3 @@ func toPbPlayers(modelInstances map[int32]*Player) map[int32]*pb.Player {
|
|||||||
|
|
||||||
return toRet
|
return toRet
|
||||||
}
|
}
|
||||||
|
|
||||||
func toPbTreasures(modelInstances map[int32]*Treasure) map[int32]*pb.Treasure {
|
|
||||||
toRet := make(map[int32]*pb.Treasure, 0)
|
|
||||||
if nil == modelInstances {
|
|
||||||
return toRet
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, last := range modelInstances {
|
|
||||||
toRet[k] = &pb.Treasure{
|
|
||||||
Id: last.Id,
|
|
||||||
LocalIdInBattle: last.LocalIdInBattle,
|
|
||||||
Score: last.Score,
|
|
||||||
X: last.X,
|
|
||||||
Y: last.Y,
|
|
||||||
Removed: last.Removed,
|
|
||||||
Type: last.Type,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return toRet
|
|
||||||
}
|
|
||||||
|
|
||||||
func toPbTraps(modelInstances map[int32]*Trap) map[int32]*pb.Trap {
|
|
||||||
toRet := make(map[int32]*pb.Trap, 0)
|
|
||||||
if nil == modelInstances {
|
|
||||||
return toRet
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, last := range modelInstances {
|
|
||||||
toRet[k] = &pb.Trap{
|
|
||||||
Id: last.Id,
|
|
||||||
LocalIdInBattle: last.LocalIdInBattle,
|
|
||||||
X: last.X,
|
|
||||||
Y: last.Y,
|
|
||||||
Removed: last.Removed,
|
|
||||||
Type: last.Type,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return toRet
|
|
||||||
}
|
|
||||||
|
|
||||||
func toPbBullets(modelInstances map[int32]*Bullet) map[int32]*pb.Bullet {
|
|
||||||
toRet := make(map[int32]*pb.Bullet, 0)
|
|
||||||
if nil == modelInstances {
|
|
||||||
return toRet
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, last := range modelInstances {
|
|
||||||
if nil == last.StartAtPoint || nil == last.EndAtPoint {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
toRet[k] = &pb.Bullet{
|
|
||||||
LocalIdInBattle: last.LocalIdInBattle,
|
|
||||||
LinearSpeed: last.LinearSpeed,
|
|
||||||
X: last.X,
|
|
||||||
Y: last.Y,
|
|
||||||
Removed: last.Removed,
|
|
||||||
StartAtPoint: &pb.Vec2D{
|
|
||||||
X: last.StartAtPoint.X,
|
|
||||||
Y: last.StartAtPoint.Y,
|
|
||||||
},
|
|
||||||
EndAtPoint: &pb.Vec2D{
|
|
||||||
X: last.EndAtPoint.X,
|
|
||||||
Y: last.EndAtPoint.Y,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return toRet
|
|
||||||
}
|
|
||||||
|
|
||||||
func toPbSpeedShoes(modelInstances map[int32]*SpeedShoe) map[int32]*pb.SpeedShoe {
|
|
||||||
toRet := make(map[int32]*pb.SpeedShoe, 0)
|
|
||||||
if nil == modelInstances {
|
|
||||||
return toRet
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, last := range modelInstances {
|
|
||||||
toRet[k] = &pb.SpeedShoe{
|
|
||||||
Id: last.Id,
|
|
||||||
LocalIdInBattle: last.LocalIdInBattle,
|
|
||||||
X: last.X,
|
|
||||||
Y: last.Y,
|
|
||||||
Removed: last.Removed,
|
|
||||||
Type: last.Type,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return toRet
|
|
||||||
}
|
|
||||||
|
|
||||||
func toPbGuardTowers(modelInstances map[int32]*GuardTower) map[int32]*pb.GuardTower {
|
|
||||||
toRet := make(map[int32]*pb.GuardTower, 0)
|
|
||||||
if nil == modelInstances {
|
|
||||||
return toRet
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, last := range modelInstances {
|
|
||||||
toRet[k] = &pb.GuardTower{
|
|
||||||
Id: last.Id,
|
|
||||||
LocalIdInBattle: last.LocalIdInBattle,
|
|
||||||
X: last.X,
|
|
||||||
Y: last.Y,
|
|
||||||
Removed: last.Removed,
|
|
||||||
Type: last.Type,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return toRet
|
|
||||||
}
|
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
package models
|
|
||||||
|
|
||||||
import "github.com/ByteArena/box2d"
|
|
||||||
|
|
||||||
type Pumpkin struct {
|
|
||||||
LocalIdInBattle int32 `json:"localIdInBattle,omitempty"`
|
|
||||||
LinearSpeed float64 `json:"linearSpeed,omitempty"`
|
|
||||||
X float64 `json:"x,omitempty"`
|
|
||||||
Y float64 `json:"y,omitempty"`
|
|
||||||
Removed bool `json:"removed,omitempty"`
|
|
||||||
Dir *Direction `json:"-"`
|
|
||||||
CollidableBody *box2d.B2Body `json:"-"`
|
|
||||||
RemovedAtFrameId int32 `json:"-"`
|
|
||||||
}
|
|
@ -43,20 +43,10 @@ const (
|
|||||||
const (
|
const (
|
||||||
// You can equivalently use the `GroupIndex` approach, but the more complicated and general purpose approach is used deliberately here. Reference http://www.aurelienribon.com/post/2011-07-box2d-tutorial-collision-filtering.
|
// You can equivalently use the `GroupIndex` approach, but the more complicated and general purpose approach is used deliberately here. Reference http://www.aurelienribon.com/post/2011-07-box2d-tutorial-collision-filtering.
|
||||||
COLLISION_CATEGORY_CONTROLLED_PLAYER = (1 << 1)
|
COLLISION_CATEGORY_CONTROLLED_PLAYER = (1 << 1)
|
||||||
COLLISION_CATEGORY_TREASURE = (1 << 2)
|
COLLISION_CATEGORY_BARRIER = (1 << 2)
|
||||||
COLLISION_CATEGORY_TRAP = (1 << 3)
|
|
||||||
COLLISION_CATEGORY_TRAP_BULLET = (1 << 4)
|
|
||||||
COLLISION_CATEGORY_BARRIER = (1 << 5)
|
|
||||||
COLLISION_CATEGORY_PUMPKIN = (1 << 6)
|
|
||||||
COLLISION_CATEGORY_SPEED_SHOES = (1 << 7)
|
|
||||||
|
|
||||||
COLLISION_MASK_FOR_CONTROLLED_PLAYER = (COLLISION_CATEGORY_TREASURE | COLLISION_CATEGORY_TRAP | COLLISION_CATEGORY_TRAP_BULLET | COLLISION_CATEGORY_SPEED_SHOES)
|
COLLISION_MASK_FOR_CONTROLLED_PLAYER = (COLLISION_CATEGORY_BARRIER)
|
||||||
COLLISION_MASK_FOR_TREASURE = (COLLISION_CATEGORY_CONTROLLED_PLAYER)
|
COLLISION_MASK_FOR_BARRIER = (COLLISION_CATEGORY_CONTROLLED_PLAYER)
|
||||||
COLLISION_MASK_FOR_TRAP = (COLLISION_CATEGORY_CONTROLLED_PLAYER)
|
|
||||||
COLLISION_MASK_FOR_TRAP_BULLET = (COLLISION_CATEGORY_CONTROLLED_PLAYER)
|
|
||||||
COLLISION_MASK_FOR_BARRIER = (COLLISION_CATEGORY_PUMPKIN)
|
|
||||||
COLLISION_MASK_FOR_PUMPKIN = (COLLISION_CATEGORY_BARRIER)
|
|
||||||
COLLISION_MASK_FOR_SPEED_SHOES = (COLLISION_CATEGORY_CONTROLLED_PLAYER)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var DIRECTION_DECODER = [][]int32{
|
var DIRECTION_DECODER = [][]int32{
|
||||||
@ -75,6 +65,22 @@ var DIRECTION_DECODER = [][]int32{
|
|||||||
{0, -1},
|
{0, -1},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var DIRECTION_DECODER_INVERSE_LENGTH = []float32{
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
0.5,
|
||||||
|
0.5,
|
||||||
|
0.4472,
|
||||||
|
0.4472,
|
||||||
|
0.4472,
|
||||||
|
0.4472,
|
||||||
|
0.5,
|
||||||
|
0.5,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
}
|
||||||
|
|
||||||
type RoomBattleState struct {
|
type RoomBattleState struct {
|
||||||
IDLE int32
|
IDLE int32
|
||||||
WAITING int32
|
WAITING int32
|
||||||
@ -142,16 +148,11 @@ type Room struct {
|
|||||||
BattleDurationNanos int64
|
BattleDurationNanos int64
|
||||||
EffectivePlayerCount int32
|
EffectivePlayerCount int32
|
||||||
DismissalWaitGroup sync.WaitGroup
|
DismissalWaitGroup sync.WaitGroup
|
||||||
Treasures map[int32]*Treasure
|
|
||||||
Traps map[int32]*Trap
|
|
||||||
GuardTowers map[int32]*GuardTower
|
|
||||||
Bullets map[int32]*Bullet
|
|
||||||
SpeedShoes map[int32]*SpeedShoe
|
|
||||||
Barriers map[int32]*Barrier
|
Barriers map[int32]*Barrier
|
||||||
Pumpkins map[int32]*Pumpkin
|
|
||||||
AccumulatedLocalIdForBullets int32
|
AccumulatedLocalIdForBullets int32
|
||||||
CollidableWorld *box2d.B2World
|
CollidableWorld *box2d.B2World
|
||||||
AllPlayerInputsBuffer *RingBuffer
|
AllPlayerInputsBuffer *RingBuffer
|
||||||
|
RenderFrameBuffer *RingBuffer
|
||||||
LastAllConfirmedInputFrameId int32
|
LastAllConfirmedInputFrameId int32
|
||||||
LastAllConfirmedInputFrameIdWithChange int32
|
LastAllConfirmedInputFrameIdWithChange int32
|
||||||
LastAllConfirmedInputList []uint64
|
LastAllConfirmedInputList []uint64
|
||||||
@ -168,58 +169,11 @@ type Room struct {
|
|||||||
RawBattleStrToPolygon2DListMap StrToPolygon2DListMap
|
RawBattleStrToPolygon2DListMap StrToPolygon2DListMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pR *Room) onTreasurePickedUp(contactingPlayer *Player, contactingTreasure *Treasure) {
|
|
||||||
if _, existent := pR.Treasures[contactingTreasure.LocalIdInBattle]; existent {
|
|
||||||
Logger.Info("Player has picked up treasure:", zap.Any("roomId", pR.Id), zap.Any("contactingPlayer.Id", contactingPlayer.Id), zap.Any("contactingTreasure.LocalIdInBattle", contactingTreasure.LocalIdInBattle))
|
|
||||||
pR.CollidableWorld.DestroyBody(contactingTreasure.CollidableBody)
|
|
||||||
pR.Treasures[contactingTreasure.LocalIdInBattle] = &Treasure{Removed: true}
|
|
||||||
pR.Players[contactingPlayer.Id].Score += contactingTreasure.Score
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PLAYER_DEFAULT_SPEED = 200 // Hardcoded
|
PLAYER_DEFAULT_SPEED = 200 // Hardcoded
|
||||||
ADD_SPEED = 100 // Hardcoded
|
ADD_SPEED = 100 // Hardcoded
|
||||||
)
|
)
|
||||||
|
|
||||||
func (pR *Room) onSpeedShoePickedUp(contactingPlayer *Player, contactingSpeedShoe *SpeedShoe, nowMillis int64) {
|
|
||||||
if _, existent := pR.SpeedShoes[contactingSpeedShoe.LocalIdInBattle]; existent && contactingPlayer.AddSpeedAtGmtMillis == -1 {
|
|
||||||
Logger.Info("Player has picked up a SpeedShoe:", zap.Any("roomId", pR.Id), zap.Any("contactingPlayer.Id", contactingPlayer.Id), zap.Any("contactingSpeedShoe.LocalIdInBattle", contactingSpeedShoe.LocalIdInBattle))
|
|
||||||
pR.CollidableWorld.DestroyBody(contactingSpeedShoe.CollidableBody)
|
|
||||||
pR.SpeedShoes[contactingSpeedShoe.LocalIdInBattle] = &SpeedShoe{
|
|
||||||
Removed: true,
|
|
||||||
RemovedAtFrameId: pR.Tick,
|
|
||||||
}
|
|
||||||
pR.Players[contactingPlayer.Id].Speed += ADD_SPEED
|
|
||||||
pR.Players[contactingPlayer.Id].AddSpeedAtGmtMillis = nowMillis
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pR *Room) onBulletCrashed(contactingPlayer *Player, contactingBullet *Bullet, nowMillis int64, maxMillisToFreezePerPlayer int64) {
|
|
||||||
if _, existent := pR.Bullets[contactingBullet.LocalIdInBattle]; existent {
|
|
||||||
pR.CollidableWorld.DestroyBody(contactingBullet.CollidableBody)
|
|
||||||
pR.Bullets[contactingBullet.LocalIdInBattle] = &Bullet{
|
|
||||||
Removed: true,
|
|
||||||
RemovedAtFrameId: pR.Tick,
|
|
||||||
}
|
|
||||||
|
|
||||||
if contactingPlayer != nil {
|
|
||||||
if maxMillisToFreezePerPlayer > (nowMillis - pR.Players[contactingPlayer.Id].FrozenAtGmtMillis) {
|
|
||||||
// Deliberately doing nothing. -- YFLu, 2019-09-04.
|
|
||||||
} else {
|
|
||||||
pR.Players[contactingPlayer.Id].Speed = 0
|
|
||||||
pR.Players[contactingPlayer.Id].FrozenAtGmtMillis = nowMillis
|
|
||||||
pR.Players[contactingPlayer.Id].AddSpeedAtGmtMillis = -1
|
|
||||||
//Logger.Info("Player has picked up bullet:", zap.Any("roomId", pR.Id), zap.Any("contactingPlayer.Id", contactingPlayer.Id), zap.Any("contactingBullet.LocalIdInBattle", contactingBullet.LocalIdInBattle), zap.Any("pR.Players[contactingPlayer.Id].Speed", pR.Players[contactingPlayer.Id].Speed))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pR *Room) onPumpkinEncounterPlayer(pumpkin *Pumpkin, player *Player) {
|
|
||||||
Logger.Info("pumpkin has caught the player: ", zap.Any("pumpkinId", pumpkin.LocalIdInBattle), zap.Any("playerId", player.Id))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pR *Room) updateScore() {
|
func (pR *Room) updateScore() {
|
||||||
pR.Score = calRoomScore(pR.EffectivePlayerCount, pR.Capacity, pR.State)
|
pR.Score = calRoomScore(pR.EffectivePlayerCount, pR.Capacity, pR.State)
|
||||||
}
|
}
|
||||||
@ -280,251 +234,6 @@ func (pR *Room) ReAddPlayerIfPossible(pTmpPlayerInstance *Player, session *webso
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pR *Room) refreshColliders() {
|
|
||||||
/*
|
|
||||||
"BarrierCollider"s are NOT added to the "colliders in B2World of the current battle", thus NOT involved in server-side collision detection!
|
|
||||||
|
|
||||||
-- YFLu, 2019-09-04
|
|
||||||
*/
|
|
||||||
gravity := box2d.MakeB2Vec2(0.0, 0.0)
|
|
||||||
world := box2d.MakeB2World(gravity)
|
|
||||||
world.SetContactFilter(&box2d.B2ContactFilter{})
|
|
||||||
pR.CollidableWorld = &world
|
|
||||||
|
|
||||||
Logger.Info("Begins `refreshColliders` for players:", zap.Any("roomId", pR.Id))
|
|
||||||
for _, player := range pR.Players {
|
|
||||||
var bdDef box2d.B2BodyDef
|
|
||||||
colliderOffset := box2d.MakeB2Vec2(0, 0) // Matching that of client-side setting.
|
|
||||||
bdDef = box2d.MakeB2BodyDef()
|
|
||||||
bdDef.Type = box2d.B2BodyType.B2_dynamicBody
|
|
||||||
bdDef.Position.Set(player.X+colliderOffset.X, player.Y+colliderOffset.Y)
|
|
||||||
|
|
||||||
b2Body := pR.CollidableWorld.CreateBody(&bdDef)
|
|
||||||
|
|
||||||
b2CircleShape := box2d.MakeB2CircleShape()
|
|
||||||
b2CircleShape.M_radius = 32 // Matching that of client-side setting.
|
|
||||||
|
|
||||||
fd := box2d.MakeB2FixtureDef()
|
|
||||||
fd.Shape = &b2CircleShape
|
|
||||||
fd.Filter.CategoryBits = COLLISION_CATEGORY_CONTROLLED_PLAYER
|
|
||||||
fd.Filter.MaskBits = COLLISION_MASK_FOR_CONTROLLED_PLAYER
|
|
||||||
fd.Density = 0.0
|
|
||||||
b2Body.CreateFixtureFromDef(&fd)
|
|
||||||
|
|
||||||
player.CollidableBody = b2Body
|
|
||||||
b2Body.SetUserData(player)
|
|
||||||
}
|
|
||||||
Logger.Info("Ends `refreshColliders` for players:", zap.Any("roomId", pR.Id))
|
|
||||||
|
|
||||||
Logger.Info("Begins `refreshColliders` for treasures:", zap.Any("roomId", pR.Id))
|
|
||||||
for _, treasure := range pR.Treasures {
|
|
||||||
var bdDef box2d.B2BodyDef
|
|
||||||
bdDef.Type = box2d.B2BodyType.B2_dynamicBody
|
|
||||||
bdDef = box2d.MakeB2BodyDef()
|
|
||||||
bdDef.Position.Set(treasure.PickupBoundary.Anchor.X, treasure.PickupBoundary.Anchor.Y)
|
|
||||||
|
|
||||||
b2Body := pR.CollidableWorld.CreateBody(&bdDef)
|
|
||||||
|
|
||||||
pointsCount := len(treasure.PickupBoundary.Points)
|
|
||||||
|
|
||||||
b2Vertices := make([]box2d.B2Vec2, pointsCount)
|
|
||||||
for vIndex, v2 := range treasure.PickupBoundary.Points {
|
|
||||||
b2Vertices[vIndex] = v2.ToB2Vec2()
|
|
||||||
}
|
|
||||||
|
|
||||||
b2PolygonShape := box2d.MakeB2PolygonShape()
|
|
||||||
b2PolygonShape.Set(b2Vertices, pointsCount)
|
|
||||||
|
|
||||||
fd := box2d.MakeB2FixtureDef()
|
|
||||||
fd.Shape = &b2PolygonShape
|
|
||||||
fd.Filter.CategoryBits = COLLISION_CATEGORY_TREASURE
|
|
||||||
fd.Filter.MaskBits = COLLISION_MASK_FOR_TREASURE
|
|
||||||
fd.Density = 0.0
|
|
||||||
b2Body.CreateFixtureFromDef(&fd)
|
|
||||||
|
|
||||||
treasure.CollidableBody = b2Body
|
|
||||||
b2Body.SetUserData(treasure)
|
|
||||||
}
|
|
||||||
Logger.Info("Ends `refreshColliders` for treasures:", zap.Any("roomId", pR.Id))
|
|
||||||
|
|
||||||
Logger.Info("Begins `refreshColliders` for towers:", zap.Any("roomId", pR.Id))
|
|
||||||
for _, tower := range pR.GuardTowers {
|
|
||||||
// Logger.Info("Begins `refreshColliders` for single tower:", zap.Any("k-th", k), zap.Any("tower.LocalIdInBattle", tower.LocalIdInBattle), zap.Any("tower.X", tower.X), zap.Any("tower.Y", tower.Y), zap.Any("tower.PickupBoundary", tower.PickupBoundary), zap.Any("tower.PickupBoundary.Points", tower.PickupBoundary.Points), zap.Any("tower.WidthInB2World", tower.WidthInB2World), zap.Any("tower.HeightInB2World", tower.HeightInB2World), zap.Any("roomId", pR.Id))
|
|
||||||
var bdDef box2d.B2BodyDef
|
|
||||||
bdDef.Type = box2d.B2BodyType.B2_dynamicBody
|
|
||||||
bdDef = box2d.MakeB2BodyDef()
|
|
||||||
bdDef.Position.Set(tower.PickupBoundary.Anchor.X, tower.PickupBoundary.Anchor.Y)
|
|
||||||
|
|
||||||
b2Body := pR.CollidableWorld.CreateBody(&bdDef)
|
|
||||||
// Logger.Info("Checks#1 `refreshColliders` for single tower:", zap.Any("k-th", k), zap.Any("tower", tower), zap.Any("roomId", pR.Id))
|
|
||||||
|
|
||||||
pointsCount := len(tower.PickupBoundary.Points)
|
|
||||||
|
|
||||||
b2Vertices := make([]box2d.B2Vec2, pointsCount)
|
|
||||||
for vIndex, v2 := range tower.PickupBoundary.Points {
|
|
||||||
b2Vertices[vIndex] = v2.ToB2Vec2()
|
|
||||||
}
|
|
||||||
// Logger.Info("Checks#2 `refreshColliders` for single tower:", zap.Any("k-th", k), zap.Any("tower", tower), zap.Any("roomId", pR.Id))
|
|
||||||
|
|
||||||
b2PolygonShape := box2d.MakeB2PolygonShape()
|
|
||||||
// Logger.Info("Checks#3 `refreshColliders` for single tower:", zap.Any("k-th", k), zap.Any("tower", tower), zap.Any("roomId", pR.Id))
|
|
||||||
b2PolygonShape.Set(b2Vertices, pointsCount)
|
|
||||||
// Logger.Info("Checks#4 `refreshColliders` for single tower:", zap.Any("k-th", k), zap.Any("tower", tower), zap.Any("roomId", pR.Id))
|
|
||||||
|
|
||||||
fd := box2d.MakeB2FixtureDef()
|
|
||||||
fd.Shape = &b2PolygonShape
|
|
||||||
fd.Filter.CategoryBits = COLLISION_CATEGORY_TRAP
|
|
||||||
fd.Filter.MaskBits = COLLISION_MASK_FOR_TRAP
|
|
||||||
fd.Density = 0.0
|
|
||||||
b2Body.CreateFixtureFromDef(&fd)
|
|
||||||
// Logger.Info("Checks#5 `refreshColliders` for single tower:", zap.Any("k-th", k), zap.Any("tower", tower), zap.Any("roomId", pR.Id))
|
|
||||||
|
|
||||||
tower.CollidableBody = b2Body
|
|
||||||
b2Body.SetUserData(tower)
|
|
||||||
// Logger.Info("Ends `refreshColliders` for single tower:", zap.Any("k-th", k), zap.Any("tower", tower), zap.Any("roomId", pR.Id))
|
|
||||||
}
|
|
||||||
Logger.Info("Ends `refreshColliders` for towers:", zap.Any("roomId", pR.Id))
|
|
||||||
|
|
||||||
listener := RoomBattleContactListener{
|
|
||||||
name: "TreasureHunterX",
|
|
||||||
room: pR,
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Setting a "ContactListener" for "pR.CollidableWorld"
|
|
||||||
* will only trigger corresponding callbacks in the
|
|
||||||
* SAME GOROUTINE of "pR.CollidableWorld.Step(...)" according
|
|
||||||
* to "https://github.com/ByteArena/box2d/blob/master/DynamicsB2World.go" and
|
|
||||||
* "https://github.com/ByteArena/box2d/blob/master/DynamicsB2Contact.go".
|
|
||||||
*
|
|
||||||
* The invocation-chain involves "Step -> SolveTOI -> B2ContactUpdate -> [BeginContact, EndContact, PreSolve]".
|
|
||||||
*/
|
|
||||||
pR.CollidableWorld.SetContactListener(listener)
|
|
||||||
}
|
|
||||||
|
|
||||||
func calculateDiffFrame(currentFrame *pb.RoomDownsyncFrame, lastFrame *pb.RoomDownsyncFrame) *pb.RoomDownsyncFrame {
|
|
||||||
if lastFrame == nil {
|
|
||||||
return currentFrame
|
|
||||||
}
|
|
||||||
diffFrame := &pb.RoomDownsyncFrame{
|
|
||||||
Id: currentFrame.Id,
|
|
||||||
RefFrameId: lastFrame.Id,
|
|
||||||
Players: currentFrame.Players,
|
|
||||||
SentAt: currentFrame.SentAt,
|
|
||||||
CountdownNanos: currentFrame.CountdownNanos,
|
|
||||||
Bullets: currentFrame.Bullets,
|
|
||||||
Treasures: make(map[int32]*pb.Treasure, 0),
|
|
||||||
Traps: make(map[int32]*pb.Trap, 0),
|
|
||||||
SpeedShoes: make(map[int32]*pb.SpeedShoe, 0),
|
|
||||||
GuardTowers: make(map[int32]*pb.GuardTower, 0),
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, last := range lastFrame.Treasures {
|
|
||||||
if last.Removed {
|
|
||||||
diffFrame.Treasures[k] = last
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
curr, ok := currentFrame.Treasures[k]
|
|
||||||
if !ok {
|
|
||||||
diffFrame.Treasures[k] = &pb.Treasure{Removed: true}
|
|
||||||
Logger.Info("A treasure is removed.", zap.Any("diffFrame.id", diffFrame.Id), zap.Any("treasure.LocalIdInBattle", curr.LocalIdInBattle))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if ok, v := diffTreasure(last, curr); ok {
|
|
||||||
diffFrame.Treasures[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, last := range lastFrame.Bullets {
|
|
||||||
curr, ok := currentFrame.Bullets[k]
|
|
||||||
/*
|
|
||||||
* The use of 'bullet.RemovedAtFrameId' implies that you SHOULDN'T create a record '&Bullet{Removed: true}' here after it's already deleted from 'room.Bullets'. Same applies for `Traps` and `SpeedShoes`.
|
|
||||||
*
|
|
||||||
* -- YFLu
|
|
||||||
*/
|
|
||||||
if false == ok {
|
|
||||||
diffFrame.Bullets[k] = &pb.Bullet{Removed: true}
|
|
||||||
// Logger.Info("A bullet is removed.", zap.Any("diffFrame.id", diffFrame.Id), zap.Any("bullet.LocalIdInBattle", lastFrame.Bullets[k].LocalIdInBattle))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if ok, v := diffBullet(last, curr); ok {
|
|
||||||
diffFrame.Bullets[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, last := range lastFrame.Traps {
|
|
||||||
curr, ok := currentFrame.Traps[k]
|
|
||||||
if false == ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if ok, v := diffTrap(last, curr); ok {
|
|
||||||
diffFrame.Traps[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, last := range lastFrame.SpeedShoes {
|
|
||||||
curr, ok := currentFrame.SpeedShoes[k]
|
|
||||||
if false == ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if ok, v := diffSpeedShoe(last, curr); ok {
|
|
||||||
diffFrame.SpeedShoes[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return diffFrame
|
|
||||||
}
|
|
||||||
|
|
||||||
func diffTreasure(last *pb.Treasure, curr *pb.Treasure) (bool, *pb.Treasure) {
|
|
||||||
treature := &pb.Treasure{}
|
|
||||||
t := false
|
|
||||||
if last.Score != curr.Score {
|
|
||||||
treature.Score = curr.Score
|
|
||||||
t = true
|
|
||||||
}
|
|
||||||
if last.X != curr.X {
|
|
||||||
treature.X = curr.X
|
|
||||||
t = true
|
|
||||||
}
|
|
||||||
if last.Y != curr.Y {
|
|
||||||
treature.Y = curr.Y
|
|
||||||
t = true
|
|
||||||
}
|
|
||||||
return t, treature
|
|
||||||
}
|
|
||||||
|
|
||||||
func diffTrap(last *pb.Trap, curr *pb.Trap) (bool, *pb.Trap) {
|
|
||||||
trap := &pb.Trap{}
|
|
||||||
t := false
|
|
||||||
if last.X != curr.X {
|
|
||||||
trap.X = curr.X
|
|
||||||
t = true
|
|
||||||
}
|
|
||||||
if last.Y != curr.Y {
|
|
||||||
trap.Y = curr.Y
|
|
||||||
t = true
|
|
||||||
}
|
|
||||||
return t, trap
|
|
||||||
}
|
|
||||||
|
|
||||||
func diffSpeedShoe(last *pb.SpeedShoe, curr *pb.SpeedShoe) (bool, *pb.SpeedShoe) {
|
|
||||||
speedShoe := &pb.SpeedShoe{}
|
|
||||||
t := false
|
|
||||||
if last.X != curr.X {
|
|
||||||
speedShoe.X = curr.X
|
|
||||||
t = true
|
|
||||||
}
|
|
||||||
if last.Y != curr.Y {
|
|
||||||
speedShoe.Y = curr.Y
|
|
||||||
t = true
|
|
||||||
}
|
|
||||||
return t, speedShoe
|
|
||||||
}
|
|
||||||
|
|
||||||
func diffBullet(last *pb.Bullet, curr *pb.Bullet) (bool, *pb.Bullet) {
|
|
||||||
t := true
|
|
||||||
return t, curr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pR *Room) ChooseStage() error {
|
func (pR *Room) ChooseStage() error {
|
||||||
/*
|
/*
|
||||||
* We use the verb "refresh" here to imply that upon invocation of this function, all colliders will be recovered if they were destroyed in the previous battle.
|
* We use the verb "refresh" here to imply that upon invocation of this function, all colliders will be recovered if they were destroyed in the previous battle.
|
||||||
@ -592,81 +301,21 @@ func (pR *Room) ChooseStage() error {
|
|||||||
pR.RawBattleStrToVec2DListMap = toRetStrToVec2DListMap
|
pR.RawBattleStrToVec2DListMap = toRetStrToVec2DListMap
|
||||||
pR.RawBattleStrToPolygon2DListMap = toRetStrToPolygon2DListMap
|
pR.RawBattleStrToPolygon2DListMap = toRetStrToPolygon2DListMap
|
||||||
|
|
||||||
// Refresh "Treasure" data for RoomDownsyncFrame.
|
barrierPolygon2DList := *(toRetStrToPolygon2DListMap["Barrier"])
|
||||||
lowScoreTreasurePolygon2DList := *(toRetStrToPolygon2DListMap["LowScoreTreasure"])
|
|
||||||
highScoreTreasurePolygon2DList := *(toRetStrToPolygon2DListMap["HighScoreTreasure"])
|
|
||||||
|
|
||||||
var treasureLocalIdInBattle int32 = 0
|
var barrierLocalIdInBattle int32 = 0
|
||||||
for _, polygon2D := range lowScoreTreasurePolygon2DList {
|
for _, polygon2D := range barrierPolygon2DList {
|
||||||
/*
|
/*
|
||||||
// For debug-printing only.
|
// For debug-printing only.
|
||||||
|
Logger.Info("ChooseStage printing polygon2D for barrierPolygon2DList", zap.Any("barrierLocalIdInBattle", barrierLocalIdInBattle), zap.Any("polygon2D.Anchor", polygon2D.Anchor), zap.Any("polygon2D.Points", polygon2D.Points))
|
||||||
Logger.Info("ChooseStage printing polygon2D for lowScoreTreasurePolygon2DList", zap.Any("treasureLocalIdInBattle", treasureLocalIdInBattle), zap.Any("polygon2D.Anchor", polygon2D.Anchor), zap.Any("polygon2D.Points", polygon2D.Points))
|
|
||||||
*/
|
*/
|
||||||
|
pR.Barriers[barrierLocalIdInBattle] = &Barrier{
|
||||||
theTreasure := &Treasure{
|
|
||||||
Id: 0,
|
|
||||||
LocalIdInBattle: treasureLocalIdInBattle,
|
|
||||||
Score: LOW_SCORE_TREASURE_SCORE,
|
|
||||||
Type: LOW_SCORE_TREASURE_TYPE,
|
|
||||||
X: polygon2D.Anchor.X,
|
X: polygon2D.Anchor.X,
|
||||||
Y: polygon2D.Anchor.Y,
|
Y: polygon2D.Anchor.Y,
|
||||||
PickupBoundary: polygon2D,
|
Boundary: polygon2D,
|
||||||
}
|
}
|
||||||
|
|
||||||
pR.Treasures[theTreasure.LocalIdInBattle] = theTreasure
|
barrierLocalIdInBattle++
|
||||||
treasureLocalIdInBattle++
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, polygon2D := range highScoreTreasurePolygon2DList {
|
|
||||||
/*
|
|
||||||
// For debug-printing only.
|
|
||||||
|
|
||||||
Logger.Info("ChooseStage printing polygon2D for highScoreTreasurePolygon2DList", zap.Any("treasureLocalIdInBattle", treasureLocalIdInBattle), zap.Any("polygon2D.Anchor", polygon2D.Anchor), zap.Any("polygon2D.Points", polygon2D.Points))
|
|
||||||
*/
|
|
||||||
theTreasure := &Treasure{
|
|
||||||
Id: 0,
|
|
||||||
LocalIdInBattle: treasureLocalIdInBattle,
|
|
||||||
Score: HIGH_SCORE_TREASURE_SCORE,
|
|
||||||
Type: HIGH_SCORE_TREASURE_TYPE,
|
|
||||||
X: polygon2D.Anchor.X,
|
|
||||||
Y: polygon2D.Anchor.Y,
|
|
||||||
PickupBoundary: polygon2D,
|
|
||||||
}
|
|
||||||
|
|
||||||
pR.Treasures[theTreasure.LocalIdInBattle] = theTreasure
|
|
||||||
|
|
||||||
treasureLocalIdInBattle++
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh "GuardTower" data for RoomDownsyncFrame.
|
|
||||||
guardTowerPolygon2DList := *(toRetStrToPolygon2DListMap["GuardTower"])
|
|
||||||
var guardTowerLocalIdInBattle int32 = 0
|
|
||||||
for _, polygon2D := range guardTowerPolygon2DList {
|
|
||||||
/*
|
|
||||||
// For debug-printing only.
|
|
||||||
|
|
||||||
Logger.Info("ChooseStage printing polygon2D for guardTowerPolygon2DList", zap.Any("guardTowerLocalIdInBattle", guardTowerLocalIdInBattle), zap.Any("polygon2D.Anchor", polygon2D.Anchor), zap.Any("polygon2D.Points", polygon2D.Points), zap.Any("pR.GuardTowers", pR.GuardTowers))
|
|
||||||
*/
|
|
||||||
|
|
||||||
var inRangePlayers InRangePlayerCollection
|
|
||||||
pInRangePlayers := &inRangePlayers
|
|
||||||
pInRangePlayers = pInRangePlayers.Init(10)
|
|
||||||
theGuardTower := &GuardTower{
|
|
||||||
Id: 0,
|
|
||||||
LocalIdInBattle: guardTowerLocalIdInBattle,
|
|
||||||
X: polygon2D.Anchor.X,
|
|
||||||
Y: polygon2D.Anchor.Y,
|
|
||||||
PickupBoundary: polygon2D,
|
|
||||||
InRangePlayers: pInRangePlayers,
|
|
||||||
LastAttackTick: utils.UnixtimeNano(),
|
|
||||||
WidthInB2World: float64(polygon2D.TmxObjectWidth),
|
|
||||||
HeightInB2World: float64(polygon2D.TmxObjectHeight),
|
|
||||||
}
|
|
||||||
|
|
||||||
pR.GuardTowers[theGuardTower.LocalIdInBattle] = theGuardTower
|
|
||||||
|
|
||||||
guardTowerLocalIdInBattle++
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -754,11 +403,6 @@ func (pR *Room) StartBattle() {
|
|||||||
Id: pR.Tick,
|
Id: pR.Tick,
|
||||||
RefFrameId: MAGIC_ROOM_DOWNSYNC_FRAME_ID_BATTLE_START,
|
RefFrameId: MAGIC_ROOM_DOWNSYNC_FRAME_ID_BATTLE_START,
|
||||||
Players: toPbPlayers(pR.Players),
|
Players: toPbPlayers(pR.Players),
|
||||||
Treasures: toPbTreasures(pR.Treasures),
|
|
||||||
Traps: toPbTraps(pR.Traps),
|
|
||||||
Bullets: toPbBullets(pR.Bullets),
|
|
||||||
SpeedShoes: toPbSpeedShoes(pR.SpeedShoes),
|
|
||||||
GuardTowers: toPbGuardTowers(pR.GuardTowers),
|
|
||||||
SentAt: utils.UnixtimeMilli(),
|
SentAt: utils.UnixtimeMilli(),
|
||||||
CountdownNanos: (pR.BattleDurationNanos - totalElapsedNanos),
|
CountdownNanos: (pR.BattleDurationNanos - totalElapsedNanos),
|
||||||
}
|
}
|
||||||
@ -783,6 +427,8 @@ func (pR *Room) StartBattle() {
|
|||||||
}
|
}
|
||||||
stCalculation := utils.UnixtimeNano()
|
stCalculation := utils.UnixtimeNano()
|
||||||
|
|
||||||
|
// TODO: Force confirm some non-all-confirmed but outdated input frames, derive server-sider RenderFrameBuffer elements from them, and send to respective players with "RoomDownsyncFrame.refFrameId=MAGIC_ROOM_DOWNSYNC_FRAME_ID_PLAYER_READDED_AND_ACKED"
|
||||||
|
|
||||||
refInputFrameId := int32(999999999) // Hardcoded as a max reference.
|
refInputFrameId := int32(999999999) // Hardcoded as a max reference.
|
||||||
for playerId, _ := range pR.Players {
|
for playerId, _ := range pR.Players {
|
||||||
thatId := atomic.LoadInt32(&(pR.Players[playerId].AckingInputFrameId))
|
thatId := atomic.LoadInt32(&(pR.Players[playerId].AckingInputFrameId))
|
||||||
@ -981,8 +627,6 @@ func (pR *Room) StopBattleForSettlement() {
|
|||||||
Players: toPbPlayers(pR.Players),
|
Players: toPbPlayers(pR.Players),
|
||||||
SentAt: utils.UnixtimeMilli(),
|
SentAt: utils.UnixtimeMilli(),
|
||||||
CountdownNanos: -1, // TODO: Replace this magic constant!
|
CountdownNanos: -1, // TODO: Replace this magic constant!
|
||||||
Treasures: toPbTreasures(pR.Treasures),
|
|
||||||
Traps: toPbTraps(pR.Traps),
|
|
||||||
}
|
}
|
||||||
pR.sendSafely(assembledFrame, playerId)
|
pR.sendSafely(assembledFrame, playerId)
|
||||||
}
|
}
|
||||||
@ -1089,11 +733,6 @@ 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.Players = make(map[int32]*Player)
|
pR.Players = make(map[int32]*Player)
|
||||||
pR.Treasures = make(map[int32]*Treasure)
|
|
||||||
pR.Traps = make(map[int32]*Trap)
|
|
||||||
pR.GuardTowers = make(map[int32]*GuardTower)
|
|
||||||
pR.Bullets = make(map[int32]*Bullet)
|
|
||||||
pR.SpeedShoes = make(map[int32]*SpeedShoe)
|
|
||||||
pR.PlayerDownsyncSessionDict = make(map[int32]*websocket.Conn)
|
pR.PlayerDownsyncSessionDict = make(map[int32]*websocket.Conn)
|
||||||
pR.PlayerSignalToCloseDict = make(map[int32]SignalToCloseConnCbType)
|
pR.PlayerSignalToCloseDict = make(map[int32]SignalToCloseConnCbType)
|
||||||
|
|
||||||
@ -1105,6 +744,7 @@ func (pR *Room) onDismissed() {
|
|||||||
pR.JoinIndexBooleanArr[indice] = false
|
pR.JoinIndexBooleanArr[indice] = false
|
||||||
}
|
}
|
||||||
pR.AllPlayerInputsBuffer = NewRingBuffer(1024)
|
pR.AllPlayerInputsBuffer = NewRingBuffer(1024)
|
||||||
|
pR.RenderFrameBuffer = NewRingBuffer(1024)
|
||||||
|
|
||||||
pR.ChooseStage()
|
pR.ChooseStage()
|
||||||
pR.EffectivePlayerCount = 0
|
pR.EffectivePlayerCount = 0
|
||||||
@ -1116,14 +756,6 @@ func (pR *Room) onDismissed() {
|
|||||||
Logger.Info("The room is completely dismissed:", zap.Any("roomId", pR.Id))
|
Logger.Info("The room is completely dismissed:", zap.Any("roomId", pR.Id))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pR *Room) Unicast(toPlayerId int32, msg interface{}) {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pR *Room) Broadcast(msg interface{}) {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pR *Room) expelPlayerDuringGame(playerId int32) {
|
func (pR *Room) expelPlayerDuringGame(playerId int32) {
|
||||||
defer pR.onPlayerExpelledDuringGame(playerId)
|
defer pR.onPlayerExpelledDuringGame(playerId)
|
||||||
}
|
}
|
||||||
@ -1368,6 +1000,84 @@ func (pR *Room) inputFrameIdDebuggable(inputFrameId int32) bool {
|
|||||||
return 0 == (inputFrameId % 10)
|
return 0 == (inputFrameId % 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pR *Room) refreshColliders() {
|
||||||
|
gravity := box2d.MakeB2Vec2(0.0, 0.0)
|
||||||
|
world := box2d.MakeB2World(gravity)
|
||||||
|
world.SetContactFilter(&box2d.B2ContactFilter{})
|
||||||
|
pR.CollidableWorld = &world
|
||||||
|
|
||||||
|
Logger.Info("Begins players collider processing:", zap.Any("roomId", pR.Id))
|
||||||
|
for _, player := range pR.Players {
|
||||||
|
var bdDef box2d.B2BodyDef
|
||||||
|
colliderOffset := box2d.MakeB2Vec2(0, 0) // Matching that of client-side setting.
|
||||||
|
bdDef = box2d.MakeB2BodyDef()
|
||||||
|
bdDef.Type = box2d.B2BodyType.B2_dynamicBody
|
||||||
|
bdDef.Position.Set(player.X+colliderOffset.X, player.Y+colliderOffset.Y)
|
||||||
|
|
||||||
|
b2Body := pR.CollidableWorld.CreateBody(&bdDef)
|
||||||
|
|
||||||
|
b2CircleShape := box2d.MakeB2CircleShape()
|
||||||
|
b2CircleShape.M_radius = 32 // Matching that of client-side setting.
|
||||||
|
|
||||||
|
fd := box2d.MakeB2FixtureDef()
|
||||||
|
fd.Shape = &b2CircleShape
|
||||||
|
fd.Filter.CategoryBits = COLLISION_CATEGORY_CONTROLLED_PLAYER
|
||||||
|
fd.Filter.MaskBits = COLLISION_MASK_FOR_CONTROLLED_PLAYER
|
||||||
|
fd.Density = 0.0
|
||||||
|
b2Body.CreateFixtureFromDef(&fd)
|
||||||
|
|
||||||
|
player.CollidableBody = b2Body
|
||||||
|
b2Body.SetUserData(player)
|
||||||
|
}
|
||||||
|
Logger.Info("Ends players collider processing:", zap.Any("roomId", pR.Id))
|
||||||
|
|
||||||
|
Logger.Info("Begins barriers collider processing:", zap.Any("roomId", pR.Id))
|
||||||
|
for _, barrier := range pR.Barriers {
|
||||||
|
var bdDef box2d.B2BodyDef
|
||||||
|
bdDef.Type = box2d.B2BodyType.B2_dynamicBody
|
||||||
|
bdDef = box2d.MakeB2BodyDef()
|
||||||
|
bdDef.Position.Set(barrier.Boundary.Anchor.X, barrier.Boundary.Anchor.Y)
|
||||||
|
|
||||||
|
b2Body := pR.CollidableWorld.CreateBody(&bdDef)
|
||||||
|
|
||||||
|
pointsCount := len(barrier.Boundary.Points)
|
||||||
|
|
||||||
|
b2Vertices := make([]box2d.B2Vec2, pointsCount)
|
||||||
|
for vIndex, v2 := range barrier.Boundary.Points {
|
||||||
|
b2Vertices[vIndex] = v2.ToB2Vec2()
|
||||||
|
}
|
||||||
|
|
||||||
|
b2PolygonShape := box2d.MakeB2PolygonShape()
|
||||||
|
b2PolygonShape.Set(b2Vertices, pointsCount)
|
||||||
|
|
||||||
|
fd := box2d.MakeB2FixtureDef()
|
||||||
|
fd.Shape = &b2PolygonShape
|
||||||
|
fd.Filter.CategoryBits = COLLISION_CATEGORY_BARRIER
|
||||||
|
fd.Filter.MaskBits = COLLISION_MASK_FOR_BARRIER
|
||||||
|
fd.Density = 0.0
|
||||||
|
b2Body.CreateFixtureFromDef(&fd)
|
||||||
|
|
||||||
|
barrier.CollidableBody = b2Body
|
||||||
|
b2Body.SetUserData(barrier)
|
||||||
|
}
|
||||||
|
Logger.Info("Ends barriers collider processing:", zap.Any("roomId", pR.Id))
|
||||||
|
|
||||||
|
listener := RoomBattleContactListener{
|
||||||
|
name: "DelayNoMore",
|
||||||
|
room: pR,
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Setting a "ContactListener" for "pR.CollidableWorld"
|
||||||
|
* will only trigger corresponding callbacks in the
|
||||||
|
* SAME GOROUTINE of "pR.CollidableWorld.Step(...)" according
|
||||||
|
* to "https://github.com/ByteArena/box2d/blob/master/DynamicsB2World.go" and
|
||||||
|
* "https://github.com/ByteArena/box2d/blob/master/DynamicsB2Contact.go".
|
||||||
|
*
|
||||||
|
* The invocation-chain involves "Step -> SolveTOI -> B2ContactUpdate -> [BeginContact, EndContact, PreSolve]".
|
||||||
|
*/
|
||||||
|
pR.CollidableWorld.SetContactListener(listener)
|
||||||
|
}
|
||||||
|
|
||||||
type RoomBattleContactListener struct {
|
type RoomBattleContactListener struct {
|
||||||
name string
|
name string
|
||||||
room *Room
|
room *Room
|
||||||
@ -1376,15 +1086,15 @@ type RoomBattleContactListener struct {
|
|||||||
// Implementing the GolangBox2d contact listeners [begins].
|
// Implementing the GolangBox2d contact listeners [begins].
|
||||||
/**
|
/**
|
||||||
* Note that the execution of these listeners is within the SAME GOROUTINE as that of "`battleMainLoop` in the same room".
|
* Note that the execution of these listeners is within the SAME GOROUTINE as that of "`battleMainLoop` in the same room".
|
||||||
* See the comments in `Room.refreshContactListener()` for details.
|
* See the comments in `Room.refreshColliders()` for details.
|
||||||
*/
|
*/
|
||||||
func (l RoomBattleContactListener) BeginContact(contact box2d.B2ContactInterface) {
|
func (l RoomBattleContactListener) BeginContact(contact box2d.B2ContactInterface) {
|
||||||
var pTower *GuardTower
|
var pBarrier *Barrier
|
||||||
var pPlayer *Player
|
var pPlayer *Player
|
||||||
|
|
||||||
switch v := contact.GetNodeA().Other.GetUserData().(type) {
|
switch v := contact.GetNodeA().Other.GetUserData().(type) {
|
||||||
case *GuardTower:
|
case *Barrier:
|
||||||
pTower = v
|
pBarrier = v
|
||||||
case *Player:
|
case *Player:
|
||||||
pPlayer = v
|
pPlayer = v
|
||||||
default:
|
default:
|
||||||
@ -1392,40 +1102,41 @@ func (l RoomBattleContactListener) BeginContact(contact box2d.B2ContactInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch v := contact.GetNodeB().Other.GetUserData().(type) {
|
switch v := contact.GetNodeB().Other.GetUserData().(type) {
|
||||||
case *GuardTower:
|
case *Barrier:
|
||||||
pTower = v
|
pBarrier = v
|
||||||
case *Player:
|
case *Player:
|
||||||
pPlayer = v
|
pPlayer = v
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
if pTower != nil && pPlayer != nil {
|
if pBarrier != nil && pPlayer != nil {
|
||||||
pTower.InRangePlayers.AppendPlayer(pPlayer)
|
Logger.Info("player begins collision with barrier:", zap.Any("barrier", pBarrier), zap.Any("player", pPlayer))
|
||||||
|
// TODO: Push back player
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l RoomBattleContactListener) EndContact(contact box2d.B2ContactInterface) {
|
func (l RoomBattleContactListener) EndContact(contact box2d.B2ContactInterface) {
|
||||||
var pTower *GuardTower
|
var pBarrier *Barrier
|
||||||
var pPlayer *Player
|
var pPlayer *Player
|
||||||
|
|
||||||
switch v := contact.GetNodeA().Other.GetUserData().(type) {
|
switch v := contact.GetNodeA().Other.GetUserData().(type) {
|
||||||
case *GuardTower:
|
case *Barrier:
|
||||||
pTower = v
|
pBarrier = v
|
||||||
case *Player:
|
case *Player:
|
||||||
pPlayer = v
|
pPlayer = v
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
switch v := contact.GetNodeB().Other.GetUserData().(type) {
|
switch v := contact.GetNodeB().Other.GetUserData().(type) {
|
||||||
case *GuardTower:
|
case *Barrier:
|
||||||
pTower = v
|
pBarrier = v
|
||||||
case *Player:
|
case *Player:
|
||||||
pPlayer = v
|
pPlayer = v
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
if pTower != nil && pPlayer != nil {
|
if pBarrier != nil && pPlayer != nil {
|
||||||
pTower.InRangePlayers.RemovePlayerById(pPlayer.Id)
|
Logger.Info("player ends collision with barrier:", zap.Any("barrier", pBarrier), zap.Any("player", pPlayer))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,15 +111,10 @@ func InitRoomHeapManager() {
|
|||||||
//BattleDurationNanos: int64(5 * 1000 * 1000 * 1000),
|
//BattleDurationNanos: int64(5 * 1000 * 1000 * 1000),
|
||||||
BattleDurationNanos: int64(30 * 1000 * 1000 * 1000),
|
BattleDurationNanos: int64(30 * 1000 * 1000 * 1000),
|
||||||
ServerFPS: 60,
|
ServerFPS: 60,
|
||||||
Treasures: make(map[int32]*Treasure),
|
|
||||||
Traps: make(map[int32]*Trap),
|
|
||||||
GuardTowers: make(map[int32]*GuardTower),
|
|
||||||
Bullets: make(map[int32]*Bullet),
|
|
||||||
SpeedShoes: make(map[int32]*SpeedShoe),
|
|
||||||
Barriers: make(map[int32]*Barrier),
|
Barriers: make(map[int32]*Barrier),
|
||||||
Pumpkins: make(map[int32]*Pumpkin),
|
|
||||||
AccumulatedLocalIdForBullets: 0,
|
AccumulatedLocalIdForBullets: 0,
|
||||||
AllPlayerInputsBuffer: NewRingBuffer(1024),
|
AllPlayerInputsBuffer: NewRingBuffer(1024),
|
||||||
|
RenderFrameBuffer: NewRingBuffer(1024),
|
||||||
LastAllConfirmedInputFrameId: -1,
|
LastAllConfirmedInputFrameId: -1,
|
||||||
LastAllConfirmedInputFrameIdWithChange: -1,
|
LastAllConfirmedInputFrameIdWithChange: -1,
|
||||||
LastAllConfirmedInputList: make([]uint64, roomCapacity),
|
LastAllConfirmedInputList: make([]uint64, roomCapacity),
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
package models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/ByteArena/box2d"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SpeedShoe struct {
|
|
||||||
Id int32 `json:"id,omitempty"`
|
|
||||||
LocalIdInBattle int32 `json:"localIdInBattle,omitempty"`
|
|
||||||
X float64 `json:"x,omitempty"`
|
|
||||||
Y float64 `json:"y,omitempty"`
|
|
||||||
Removed bool `json:"removed,omitempty"`
|
|
||||||
Type int32 `json:"type,omitempty"`
|
|
||||||
PickupBoundary *Polygon2D `json:"-"`
|
|
||||||
CollidableBody *box2d.B2Body `json:"-"`
|
|
||||||
RemovedAtFrameId int32 `json:"-"`
|
|
||||||
}
|
|
@ -19,7 +19,6 @@ import (
|
|||||||
const (
|
const (
|
||||||
LOW_SCORE_TREASURE_TYPE = 1
|
LOW_SCORE_TREASURE_TYPE = 1
|
||||||
HIGH_SCORE_TREASURE_TYPE = 2
|
HIGH_SCORE_TREASURE_TYPE = 2
|
||||||
|
|
||||||
SPEED_SHOES_TYPE = 3
|
SPEED_SHOES_TYPE = 3
|
||||||
|
|
||||||
LOW_SCORE_TREASURE_SCORE = 100
|
LOW_SCORE_TREASURE_SCORE = 100
|
||||||
@ -297,7 +296,7 @@ func DeserializeTsxToColliderDict(pTmxMapIns *TmxMap, byteArrOfTsxFile []byte, f
|
|||||||
for _, tile := range pTsxIns.Tiles {
|
for _, tile := range pTsxIns.Tiles {
|
||||||
globalGid := (firstGid + int(tile.Id))
|
globalGid := (firstGid + int(tile.Id))
|
||||||
/**
|
/**
|
||||||
Per tile xml str could be
|
A tile xml string could be
|
||||||
|
|
||||||
```
|
```
|
||||||
<tile id="13">
|
<tile id="13">
|
||||||
@ -367,8 +366,6 @@ func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMapInB2World map[i
|
|||||||
- "Polygon2D"s of "toRetStrToPolygon2DListMap"
|
- "Polygon2D"s of "toRetStrToPolygon2DListMap"
|
||||||
|
|
||||||
are already transformed into the "coordinate of B2World".
|
are already transformed into the "coordinate of B2World".
|
||||||
|
|
||||||
-- YFLu
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for _, objGroup := range pTmxMapIns.ObjectGroups {
|
for _, objGroup := range pTmxMapIns.ObjectGroups {
|
||||||
@ -391,13 +388,8 @@ func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMapInB2World map[i
|
|||||||
thePosInWorld := pTmxMapIns.continuousObjLayerOffsetToContinuousMapNodePos(theUntransformedPos)
|
thePosInWorld := pTmxMapIns.continuousObjLayerOffsetToContinuousMapNodePos(theUntransformedPos)
|
||||||
*pTheVec2DListToCache = append(*pTheVec2DListToCache, &thePosInWorld)
|
*pTheVec2DListToCache = append(*pTheVec2DListToCache, &thePosInWorld)
|
||||||
}
|
}
|
||||||
case "Pumpkin", "SpeedShoe":
|
|
||||||
case "Barrier":
|
case "Barrier":
|
||||||
/*
|
// Note that in this case, the "Polygon2D.Anchor" of each "TmxOrTsxObject" is exactly overlapping with "Polygon2D.Points[0]" w.r.t. B2World.
|
||||||
Note that in this case, the "Polygon2D.Anchor" of each "TmxOrTsxObject" is located exactly in an overlapping with "Polygon2D.Points[0]" w.r.t. B2World.
|
|
||||||
|
|
||||||
-- YFLu
|
|
||||||
*/
|
|
||||||
var pThePolygon2DListToCache *Polygon2DList
|
var pThePolygon2DListToCache *Polygon2DList
|
||||||
_, ok := toRetStrToPolygon2DListMap[objGroup.Name]
|
_, ok := toRetStrToPolygon2DListMap[objGroup.Name]
|
||||||
if false == ok {
|
if false == ok {
|
||||||
@ -422,65 +414,6 @@ func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMapInB2World map[i
|
|||||||
}
|
}
|
||||||
*pThePolygon2DListToCache = append(*pThePolygon2DListToCache, thePolygon2DInWorld)
|
*pThePolygon2DListToCache = append(*pThePolygon2DListToCache, thePolygon2DInWorld)
|
||||||
}
|
}
|
||||||
case "LowScoreTreasure", "GuardTower", "HighScoreTreasure":
|
|
||||||
/*
|
|
||||||
Note that in this case, the "Polygon2D.Anchor" of each "TmxOrTsxObject" ISN'T located exactly in an overlapping with "Polygon2D.Points[0]" w.r.t. B2World, refer to "https://shimo.im/docs/SmLJJhXm2C8XMzZT" for details.
|
|
||||||
|
|
||||||
-- YFLu
|
|
||||||
*/
|
|
||||||
for _, singleObjInTmxFile := range objGroup.Objects {
|
|
||||||
if nil == singleObjInTmxFile.Gid {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
theGlobalGid := singleObjInTmxFile.Gid
|
|
||||||
theStrToPolygon2DListMap, ok := gidBoundariesMapInB2World[*theGlobalGid]
|
|
||||||
if false == ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
pThePolygon2DList, ok := theStrToPolygon2DListMap[objGroup.Name]
|
|
||||||
if false == ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var pThePolygon2DListToCache *Polygon2DList
|
|
||||||
_, ok = toRetStrToPolygon2DListMap[objGroup.Name]
|
|
||||||
if false == ok {
|
|
||||||
thePolygon2DListToCache := make(Polygon2DList, 0)
|
|
||||||
toRetStrToPolygon2DListMap[objGroup.Name] = &thePolygon2DListToCache
|
|
||||||
pThePolygon2DListToCache = toRetStrToPolygon2DListMap[objGroup.Name]
|
|
||||||
} else {
|
|
||||||
pThePolygon2DListToCache = toRetStrToPolygon2DListMap[objGroup.Name]
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, thePolygon2D := range *pThePolygon2DList {
|
|
||||||
theUntransformedBottomCenterAsAnchor := &Vec2D{
|
|
||||||
X: singleObjInTmxFile.X,
|
|
||||||
Y: singleObjInTmxFile.Y,
|
|
||||||
}
|
|
||||||
|
|
||||||
theTransformedBottomCenterAsAnchor := pTmxMapIns.continuousObjLayerOffsetToContinuousMapNodePos(theUntransformedBottomCenterAsAnchor)
|
|
||||||
|
|
||||||
thePolygon2DInWorld := &Polygon2D{
|
|
||||||
Anchor: &theTransformedBottomCenterAsAnchor,
|
|
||||||
Points: make([]*Vec2D, len(thePolygon2D.Points)),
|
|
||||||
TileWidth: thePolygon2D.TileWidth,
|
|
||||||
TileHeight: thePolygon2D.TileHeight,
|
|
||||||
}
|
|
||||||
if nil != singleObjInTmxFile.Width && nil != singleObjInTmxFile.Height {
|
|
||||||
thePolygon2DInWorld.TmxObjectWidth = *singleObjInTmxFile.Width
|
|
||||||
thePolygon2DInWorld.TmxObjectHeight = *singleObjInTmxFile.Height
|
|
||||||
}
|
|
||||||
for kk, p := range thePolygon2D.Points {
|
|
||||||
// [WARNING] It's intentionally recreating a copy of "Vec2D" here.
|
|
||||||
thePolygon2DInWorld.Points[kk] = &Vec2D{
|
|
||||||
X: p.X,
|
|
||||||
Y: p.Y,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*pThePolygon2DListToCache = append(*pThePolygon2DListToCache, thePolygon2DInWorld)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
package models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/ByteArena/box2d"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Trap struct {
|
|
||||||
Id int32 `json:"id,omitempty"`
|
|
||||||
LocalIdInBattle int32 `json:"localIdInBattle,omitempty"`
|
|
||||||
Type int32 `json:"type,omitempty"`
|
|
||||||
X float64 `json:"x,omitempty"`
|
|
||||||
Y float64 `json:"y,omitempty"`
|
|
||||||
Removed bool `json:"removed,omitempty"`
|
|
||||||
PickupBoundary *Polygon2D `json:"-"`
|
|
||||||
TrapBullets []*Bullet `json:"-"`
|
|
||||||
CollidableBody *box2d.B2Body `json:"-"`
|
|
||||||
RemovedAtFrameId int32 `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type GuardTower struct {
|
|
||||||
Id int32 `json:"id,omitempty"`
|
|
||||||
LocalIdInBattle int32 `json:"localIdInBattle,omitempty"`
|
|
||||||
Type int32 `json:"type,omitempty"`
|
|
||||||
X float64 `json:"x,omitempty"`
|
|
||||||
Y float64 `json:"y,omitempty"`
|
|
||||||
Removed bool `json:"removed,omitempty"`
|
|
||||||
PickupBoundary *Polygon2D `json:"-"`
|
|
||||||
TrapBullets []*Bullet `json:"-"`
|
|
||||||
CollidableBody *box2d.B2Body `json:"-"`
|
|
||||||
RemovedAtFrameId int32 `json:"-"`
|
|
||||||
|
|
||||||
InRangePlayers *InRangePlayerCollection `json:"-"`
|
|
||||||
LastAttackTick int64 `json:"-"`
|
|
||||||
|
|
||||||
TileWidth float64 `json:"-"`
|
|
||||||
TileHeight float64 `json:"-"`
|
|
||||||
WidthInB2World float64 `json:"-"`
|
|
||||||
HeightInB2World float64 `json:"-"`
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
package models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/ByteArena/box2d"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Treasure struct {
|
|
||||||
Id int32 `json:"id,omitempty"`
|
|
||||||
LocalIdInBattle int32 `json:"localIdInBattle,omitempty"`
|
|
||||||
Score int32 `json:"score,omitempty"`
|
|
||||||
X float64 `json:"x,omitempty"`
|
|
||||||
Y float64 `json:"y,omitempty"`
|
|
||||||
Removed bool `json:"removed,omitempty"`
|
|
||||||
Type int32 `json:"type,omitempty"`
|
|
||||||
|
|
||||||
PickupBoundary *Polygon2D `json:"-"`
|
|
||||||
CollidableBody *box2d.B2Body `json:"-"`
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -61,73 +61,13 @@ message PlayerMeta {
|
|||||||
int32 joinIndex = 5;
|
int32 joinIndex = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Treasure {
|
|
||||||
int32 id = 1;
|
|
||||||
int32 localIdInBattle = 2;
|
|
||||||
int32 score = 3;
|
|
||||||
double x = 4;
|
|
||||||
double y = 5;
|
|
||||||
bool removed = 6;
|
|
||||||
int32 type = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Bullet {
|
|
||||||
int32 localIdInBattle = 1;
|
|
||||||
double linearSpeed = 2;
|
|
||||||
double x = 3;
|
|
||||||
double y = 4;
|
|
||||||
bool removed = 5;
|
|
||||||
Vec2D startAtPoint = 6;
|
|
||||||
Vec2D endAtPoint = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Trap {
|
|
||||||
int32 id = 1;
|
|
||||||
int32 localIdInBattle = 2;
|
|
||||||
int32 type = 3;
|
|
||||||
double x = 4;
|
|
||||||
double y = 5;
|
|
||||||
bool removed = 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
message SpeedShoe {
|
|
||||||
int32 id = 1;
|
|
||||||
int32 localIdInBattle = 2;
|
|
||||||
double x = 3;
|
|
||||||
double y = 4;
|
|
||||||
bool removed = 5;
|
|
||||||
int32 type = 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Pumpkin {
|
|
||||||
int32 localIdInBattle = 1;
|
|
||||||
double linearSpeed = 2;
|
|
||||||
double x = 3;
|
|
||||||
double y = 4;
|
|
||||||
bool removed = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
message GuardTower {
|
|
||||||
int32 id = 1;
|
|
||||||
int32 localIdInBattle = 2;
|
|
||||||
int32 type = 3;
|
|
||||||
double x = 4;
|
|
||||||
double y = 5;
|
|
||||||
bool removed = 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
message RoomDownsyncFrame {
|
message RoomDownsyncFrame {
|
||||||
int32 id = 1;
|
int32 id = 1;
|
||||||
int32 refFrameId = 2;
|
int32 refFrameId = 2;
|
||||||
map<int32, Player> players = 3;
|
map<int32, Player> players = 3;
|
||||||
int64 sentAt = 4;
|
int64 sentAt = 4;
|
||||||
int64 countdownNanos = 5;
|
int64 countdownNanos = 5;
|
||||||
map<int32, Treasure> treasures = 6;
|
map<int32, PlayerMeta> playerMetas = 6;
|
||||||
map<int32, Trap> traps = 7;
|
|
||||||
map<int32, Bullet> bullets = 8;
|
|
||||||
map<int32, SpeedShoe> speedShoes = 9;
|
|
||||||
map<int32, GuardTower> guardTowers = 10;
|
|
||||||
map<int32, PlayerMeta> playerMetas = 11;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message InputFrameUpsync {
|
message InputFrameUpsync {
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user