Simplified bullet handling.

This commit is contained in:
genxium 2023-02-11 12:08:01 +08:00
parent 365177a3af
commit de16e8e8de
7 changed files with 98 additions and 112 deletions

View File

@ -48,13 +48,13 @@
} }
}, },
{ {
"frame": 0.45, "frame": 0.4,
"value": { "value": {
"__uuid__": "487b65c3-44e3-4b0e-9350-e0d1c952785b" "__uuid__": "487b65c3-44e3-4b0e-9350-e0d1c952785b"
} }
}, },
{ {
"frame": 0.5, "frame": 0.4166666666666667,
"value": { "value": {
"__uuid__": "9a5357ae-a160-4198-a6d5-cc9631fde754" "__uuid__": "9a5357ae-a160-4198-a6d5-cc9631fde754"
} }

View File

@ -547,7 +547,7 @@
"array": [ "array": [
0, 0,
0, 0,
216.50635094610968, 216.05530045313827,
0, 0,
0, 0,
0, 0,

View File

@ -1306,7 +1306,7 @@ othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame
} }
for (let k in rdf.MeleeBullets) { for (let k in rdf.MeleeBullets) {
const meleeBullet = rdf.MeleeBullets[k]; const meleeBullet = rdf.MeleeBullets[k];
const isExploding = (window.BULLET_STATE.Exploding == meleeBullet.BlState); const isExploding = (window.BULLET_STATE.Exploding == meleeBullet.BlState && meleeBullet.FramesInBlState < meleeBullet.Bullet.ExplosionFrames);
if (isExploding) { if (isExploding) {
let pqNode = self.cachedFireballs.popAny(meleeBullet.BattleAttr.BulletLocalId); let pqNode = self.cachedFireballs.popAny(meleeBullet.BattleAttr.BulletLocalId);
let speciesName = `MeleeExplosion`; let speciesName = `MeleeExplosion`;

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{ {
"ver": "1.0.5", "ver": "1.0.5",
"uuid": "171e2c96-28b4-4225-bdcc-5e464f07d91a", "uuid": "eeaa56f4-bd6c-4208-bec4-6ab1aa39ca93",
"isPlugin": true, "isPlugin": true,
"loadPluginInWeb": true, "loadPluginInWeb": true,
"loadPluginInNative": true, "loadPluginInNative": true,

View File

@ -716,7 +716,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
} else if stoppingFromWalking { } else if stoppingFromWalking {
thatPlayerInNextFrame.FramesToRecover = chConfig.InertiaFramesToRecover thatPlayerInNextFrame.FramesToRecover = chConfig.InertiaFramesToRecover
} else { } else {
thatPlayerInNextFrame.FramesToRecover = (chConfig.InertiaFramesToRecover >> 1) thatPlayerInNextFrame.FramesToRecover = ((chConfig.InertiaFramesToRecover >> 1) + (chConfig.InertiaFramesToRecover >> 2))
} }
} else { } else {
thatPlayerInNextFrame.CapturedByInertia = false thatPlayerInNextFrame.CapturedByInertia = false
@ -757,8 +757,19 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
if 0 >= thatPlayerInNextFrame.Hp && 0 == thatPlayerInNextFrame.FramesToRecover { if 0 >= thatPlayerInNextFrame.Hp && 0 == thatPlayerInNextFrame.FramesToRecover {
// Revive from Dying // Revive from Dying
newVx, newVy = currPlayerDownsync.RevivalVirtualGridX, currPlayerDownsync.RevivalVirtualGridY newVx, newVy = currPlayerDownsync.RevivalVirtualGridX, currPlayerDownsync.RevivalVirtualGridY
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_IDLE1 thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_GET_UP1
thatPlayerInNextFrame.FramesInChState = ATK_CHARACTER_STATE_GET_UP1
thatPlayerInNextFrame.FramesToRecover = chConfig.GetUpFramesToRecover
thatPlayerInNextFrame.FramesInvinsible = chConfig.GetUpInvinsibleFrames
thatPlayerInNextFrame.Hp = currPlayerDownsync.MaxHp thatPlayerInNextFrame.Hp = currPlayerDownsync.MaxHp
// Hardcoded initial character orientation/facing
if 0 == (thatPlayerInNextFrame.JoinIndex % 2) {
thatPlayerInNextFrame.DirX = -2
thatPlayerInNextFrame.DirY = 0
} else {
thatPlayerInNextFrame.DirX = +2
thatPlayerInNextFrame.DirY = 0
}
} }
if jumpedOrNotList[i] { if jumpedOrNotList[i] {
// We haven't proceeded with "OnWall" calculation for "thatPlayerInNextFrame", thus use "currPlayerDownsync.OnWall" for checking // We haven't proceeded with "OnWall" calculation for "thatPlayerInNextFrame", thus use "currPlayerDownsync.OnWall" for checking
@ -899,8 +910,12 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
if collision := playerCollider.Check(0, 0); nil != collision { if collision := playerCollider.Check(0, 0); nil != collision {
for _, obj := range collision.Objects { for _, obj := range collision.Objects {
isBarrier, isAnotherPlayer, isBullet := false, false, false isBarrier, isAnotherPlayer, isBullet := false, false, false
switch obj.Data.(type) { switch v := obj.Data.(type) {
case *PlayerDownsync: case *PlayerDownsync:
if ATK_CHARACTER_STATE_DYING == v.CharacterState {
// ignore collision with dying player
continue
}
isAnotherPlayer = true isAnotherPlayer = true
case *MeleeBullet, *FireballBullet: case *MeleeBullet, *FireballBullet:
isBullet = true isBullet = true
@ -912,6 +927,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
// ignore bullets for this step // ignore bullets for this step
continue continue
} }
bShape := obj.Shape.(*resolv.ConvexPolygon) bShape := obj.Shape.(*resolv.ConvexPolygon)
overlapped, pushbackX, pushbackY, overlapResult := calcPushbacks(0, 0, playerShape, bShape) overlapped, pushbackX, pushbackY, overlapResult := calcPushbacks(0, 0, playerShape, bShape)
if !overlapped { if !overlapped {
@ -1013,113 +1029,83 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
collision := bulletCollider.Check(0, 0) collision := bulletCollider.Check(0, 0)
bulletCollider.Space.Remove(bulletCollider) // Make sure that the bulletCollider is always removed for each renderFrame bulletCollider.Space.Remove(bulletCollider) // Make sure that the bulletCollider is always removed for each renderFrame
exploded := false exploded := false
if nil != collision { explodedOnAnotherPlayer := false
if nil == collision {
continue
}
var bulletStaticAttr *BulletConfig = nil
var bulletBattleAttr *BulletBattleAttr = nil
switch v := bulletCollider.Data.(type) { switch v := bulletCollider.Data.(type) {
case *MeleeBullet: case *MeleeBullet:
bulletShape := bulletCollider.Shape.(*resolv.ConvexPolygon) bulletStaticAttr = v.Bullet
offender := currRenderFrame.PlayersArr[v.BattleAttr.OffenderJoinIndex-1] bulletBattleAttr = v.BattleAttr
for _, obj := range collision.Objects {
defenderShape := obj.Shape.(*resolv.ConvexPolygon)
switch t := obj.Data.(type) {
case *PlayerDownsync:
if v.BattleAttr.OffenderJoinIndex == t.JoinIndex {
continue
}
overlapped, _, _, _ := calcPushbacks(0, 0, bulletShape, defenderShape)
if !overlapped {
continue
}
exploded = true
if _, existent := invinsibleSet[t.CharacterState]; existent {
continue
}
if 0 < t.FramesInvinsible {
continue
}
xfac := int32(1) // By now, straight Punch offset doesn't respect "y-axis"
if 0 > offender.DirX {
xfac = -xfac
}
atkedPlayerInNextFrame := nextRenderFramePlayers[t.JoinIndex-1]
atkedPlayerInNextFrame.Hp -= v.Bullet.Damage
if 0 >= atkedPlayerInNextFrame.Hp {
// [WARNING] We don't have "dying in air" animation for now, and for better graphical recognition, play the same dying animation even in air
atkedPlayerInNextFrame.Hp = 0
atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_DYING
atkedPlayerInNextFrame.FramesToRecover = DYING_FRAMES_TO_RECOVER
} else {
pushbackVelX, pushbackVelY := xfac*v.Bullet.PushbackVelX, v.Bullet.PushbackVelY
atkedPlayerInNextFrame.VelX = pushbackVelX
atkedPlayerInNextFrame.VelY = pushbackVelY
if v.Bullet.BlowUp {
atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_BLOWN_UP1
} else {
atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_ATKED1
}
oldFramesToRecover := nextRenderFramePlayers[t.JoinIndex-1].FramesToRecover
if v.Bullet.HitStunFrames > oldFramesToRecover {
atkedPlayerInNextFrame.FramesToRecover = v.Bullet.HitStunFrames
}
}
}
}
case *FireballBullet: case *FireballBullet:
bulletStaticAttr = v.Bullet
bulletBattleAttr = v.BattleAttr
}
bulletShape := bulletCollider.Shape.(*resolv.ConvexPolygon) bulletShape := bulletCollider.Shape.(*resolv.ConvexPolygon)
offender := currRenderFrame.PlayersArr[v.BattleAttr.OffenderJoinIndex-1] offender := currRenderFrame.PlayersArr[bulletBattleAttr.OffenderJoinIndex-1]
for _, obj := range collision.Objects { for _, obj := range collision.Objects {
defenderShape := obj.Shape.(*resolv.ConvexPolygon) defenderShape := obj.Shape.(*resolv.ConvexPolygon)
switch t := obj.Data.(type) { switch t := obj.Data.(type) {
case *PlayerDownsync: case *PlayerDownsync:
if v.BattleAttr.OffenderJoinIndex == t.JoinIndex { if bulletBattleAttr.OffenderJoinIndex == t.JoinIndex {
continue continue
} }
overlapped, _, _, _ := calcPushbacks(0, 0, bulletShape, defenderShape) overlapped, _, _, _ := calcPushbacks(0, 0, bulletShape, defenderShape)
if !overlapped { if !overlapped {
continue continue
} }
exploded = true
if _, existent := invinsibleSet[t.CharacterState]; existent { if _, existent := invinsibleSet[t.CharacterState]; existent {
continue continue
} }
if 0 < t.FramesInvinsible { if 0 < t.FramesInvinsible {
continue continue
} }
exploded = true
explodedOnAnotherPlayer = true
xfac := int32(1) // By now, straight Punch offset doesn't respect "y-axis" xfac := int32(1) // By now, straight Punch offset doesn't respect "y-axis"
if 0 > offender.DirX { if 0 > offender.DirX {
xfac = -xfac xfac = -xfac
} }
atkedPlayerInNextFrame := nextRenderFramePlayers[t.JoinIndex-1] atkedPlayerInNextFrame := nextRenderFramePlayers[t.JoinIndex-1]
atkedPlayerInNextFrame.Hp -= v.Bullet.Damage atkedPlayerInNextFrame.Hp -= bulletStaticAttr.Damage
if 0 >= atkedPlayerInNextFrame.Hp { if 0 >= atkedPlayerInNextFrame.Hp {
// [WARNING] We don't have "dying in air" animation for now, and for better graphical recognition, play the same dying animation even in air // [WARNING] We don't have "dying in air" animation for now, and for better graphical recognition, play the same dying animation even in air
atkedPlayerInNextFrame.Hp = 0 atkedPlayerInNextFrame.Hp = 0
atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_DYING atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_DYING
atkedPlayerInNextFrame.FramesToRecover = DYING_FRAMES_TO_RECOVER atkedPlayerInNextFrame.FramesToRecover = DYING_FRAMES_TO_RECOVER
} else { } else {
pushbackVelX, pushbackVelY := xfac*v.Bullet.PushbackVelX, v.Bullet.PushbackVelY pushbackVelX, pushbackVelY := xfac*bulletStaticAttr.PushbackVelX, bulletStaticAttr.PushbackVelY
atkedPlayerInNextFrame.VelX = pushbackVelX atkedPlayerInNextFrame.VelX = pushbackVelX
atkedPlayerInNextFrame.VelY = pushbackVelY atkedPlayerInNextFrame.VelY = pushbackVelY
if v.Bullet.BlowUp { if bulletStaticAttr.BlowUp {
atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_BLOWN_UP1 atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_BLOWN_UP1
} else { } else {
atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_ATKED1 atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_ATKED1
} }
oldFramesToRecover := nextRenderFramePlayers[t.JoinIndex-1].FramesToRecover oldFramesToRecover := nextRenderFramePlayers[t.JoinIndex-1].FramesToRecover
if v.Bullet.HitStunFrames > oldFramesToRecover { if bulletStaticAttr.HitStunFrames > oldFramesToRecover {
atkedPlayerInNextFrame.FramesToRecover = v.Bullet.HitStunFrames atkedPlayerInNextFrame.FramesToRecover = bulletStaticAttr.HitStunFrames
} }
} }
default: default:
exploded = true exploded = true
} }
} }
}
}
if exploded { if exploded {
switch v := bulletCollider.Data.(type) { switch v := bulletCollider.Data.(type) {
case *MeleeBullet: case *MeleeBullet:
v.BlState = BULLET_EXPLODING v.BlState = BULLET_EXPLODING
if explodedOnAnotherPlayer {
v.FramesInBlState = 0 v.FramesInBlState = 0
} else {
// When hitting a barrier, don't play explosion anim
v.FramesInBlState = v.Bullet.ExplosionFrames + 1
}
//fmt.Printf("melee exploded @currRenderFrame.Id=%d, bulletLocalId=%d, blState=%d\n", currRenderFrame.Id, v.BattleAttr.BulletLocalId, v.BlState) //fmt.Printf("melee exploded @currRenderFrame.Id=%d, bulletLocalId=%d, blState=%d\n", currRenderFrame.Id, v.BattleAttr.BulletLocalId, v.BlState)
case *FireballBullet: case *FireballBullet:
v.BlState = BULLET_EXPLODING v.BlState = BULLET_EXPLODING

View File

@ -538,7 +538,7 @@ var skills = map[int]*Skill{
HitboxSizeX: int32(float64(64) * WORLD_TO_VIRTUAL_GRID_RATIO), HitboxSizeX: int32(float64(64) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxSizeY: int32(float64(48) * WORLD_TO_VIRTUAL_GRID_RATIO), HitboxSizeY: int32(float64(48) * WORLD_TO_VIRTUAL_GRID_RATIO),
BlowUp: false, BlowUp: false,
ExplosionFrames: 10, ExplosionFrames: 30,
SpeciesId: int32(1), SpeciesId: int32(1),
}, },
}, },
@ -781,10 +781,10 @@ var skills = map[int]*Skill{
Hits: []interface{}{ Hits: []interface{}{
&MeleeBullet{ &MeleeBullet{
Bullet: &BulletConfig{ Bullet: &BulletConfig{
StartupFrames: int32(3), StartupFrames: int32(4),
ActiveFrames: int32(20), ActiveFrames: int32(20),
HitStunFrames: int32(18), HitStunFrames: int32(9),
BlockStunFrames: int32(9), BlockStunFrames: int32(5),
Damage: int32(5), Damage: int32(5),
SelfLockVelX: NO_LOCK_VEL, SelfLockVelX: NO_LOCK_VEL,
SelfLockVelY: NO_LOCK_VEL, SelfLockVelY: NO_LOCK_VEL,