A temp broken commit except for OfflineMap - drafted basic cancellable skills.

This commit is contained in:
genxium 2023-01-01 20:18:35 +08:00
parent 8b80117d3d
commit 325dbfb79c
18 changed files with 7682 additions and 399 deletions

File diff suppressed because one or more lines are too long

View File

@ -3,7 +3,7 @@
"_name": "Atk1", "_name": "Atk1",
"_objFlags": 0, "_objFlags": 0,
"_native": "", "_native": "",
"_duration": 0.36666666666666664, "_duration": 0.2833333333333333,
"sample": 60, "sample": 60,
"speed": 1, "speed": 1,
"wrapMode": 1, "wrapMode": 1,
@ -18,25 +18,25 @@
} }
}, },
{ {
"frame": 0.03333333333333333, "frame": 0.05,
"value": { "value": {
"__uuid__": "12b90556-58b9-4311-b5d9-820fb76d659b" "__uuid__": "12b90556-58b9-4311-b5d9-820fb76d659b"
} }
}, },
{ {
"frame": 0.11666666666666667, "frame": 0.1,
"value": { "value": {
"__uuid__": "72bc74a1-6e8c-48bb-9ab2-9b8f502ceffb" "__uuid__": "72bc74a1-6e8c-48bb-9ab2-9b8f502ceffb"
} }
}, },
{ {
"frame": 0.31666666666666665, "frame": 0.25,
"value": { "value": {
"__uuid__": "7e619896-100d-4903-b256-e30ddb5ad397" "__uuid__": "7e619896-100d-4903-b256-e30ddb5ad397"
} }
}, },
{ {
"frame": 0.35, "frame": 0.26666666666666666,
"value": { "value": {
"__uuid__": "4a35e0f5-95c4-445b-8f9b-6514a060a72d" "__uuid__": "4a35e0f5-95c4-445b-8f9b-6514a060a72d"
} }

View File

@ -0,0 +1,79 @@
{
"__type__": "cc.AnimationClip",
"_name": "Atk2",
"_objFlags": 0,
"_native": "",
"_duration": 0.6,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "0e3b6c28-f265-457d-b000-aeea66d05428"
}
},
{
"frame": 0.03333333333333333,
"value": {
"__uuid__": "1d9c010b-3209-4672-9f78-96527d62f4e0"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "1fd3ca4d-ec4d-4858-a3d2-fe274e22d4be"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "b0aaf216-b8d7-4247-be61-df9f3146ce46"
}
},
{
"frame": 0.15,
"value": {
"__uuid__": "f12c5713-540f-4874-a6b0-0162f0ffb544"
}
},
{
"frame": 0.2,
"value": {
"__uuid__": "b9a4cd85-53d1-4280-bc9e-35a8dd482fa4"
}
},
{
"frame": 0.23333333333333334,
"value": {
"__uuid__": "74e9fcd1-11dc-478e-b90a-d4c5cf551aad"
}
},
{
"frame": 0.3,
"value": {
"__uuid__": "e6c3bdcd-9ba8-4c5b-910d-2d93d9068abd"
}
},
{
"frame": 0.5166666666666667,
"value": {
"__uuid__": "c359790f-bbd1-4869-a37b-7f1c0bd91578"
}
},
{
"frame": 0.5833333333333334,
"value": {
"__uuid__": "1b9074dd-d0b0-4129-8d72-8f356bf7f68c"
}
}
]
}
}
},
"events": []
}

View File

@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "e6e1d62a-de7d-4fe7-858c-2d2725b7c2e8",
"subMetas": {}
}

View File

@ -0,0 +1,85 @@
{
"__type__": "cc.AnimationClip",
"_name": "Atk3",
"_objFlags": 0,
"_native": "",
"_duration": 1,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "4e1a3e61-dc3e-4de1-9385-bce2c5f54764"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "39ba4413-6f4a-49a5-a7ca-d11140dfe7dd"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "26b646c7-bdbc-495e-adaf-9d52ef1b5c84"
}
},
{
"frame": 0.21666666666666667,
"value": {
"__uuid__": "5a5208a0-1c29-446f-8375-739aef09fe65"
}
},
{
"frame": 0.3,
"value": {
"__uuid__": "414628f0-13ec-4f01-83a0-b94f6a13fff1"
}
},
{
"frame": 0.43333333333333335,
"value": {
"__uuid__": "c494965a-e7e6-4c99-ac61-60642e6247dc"
}
},
{
"frame": 0.5666666666666667,
"value": {
"__uuid__": "04cafb17-39ab-4f2b-9830-3eaf42cab254"
}
},
{
"frame": 0.7166666666666667,
"value": {
"__uuid__": "fd9c7d8a-1038-4cab-a0e6-699e404701db"
}
},
{
"frame": 0.8333333333333334,
"value": {
"__uuid__": "2447c6b3-292b-43b4-84e5-acc35df0c1f5"
}
},
{
"frame": 0.9333333333333333,
"value": {
"__uuid__": "00275818-b9b6-41ab-a792-f21ff10747fa"
}
},
{
"frame": 0.9833333333333333,
"value": {
"__uuid__": "11a06f33-cdfa-46cf-aae4-41e72a6711c2"
}
}
]
}
}
},
"events": []
}

View File

@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "e8247e2a-1b5b-4618-86f8-224b25246b55",
"subMetas": {}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 93 KiB

View File

@ -9,10 +9,10 @@
</data> </data>
</layer> </layer>
<objectgroup id="1" name="PlayerStartingPos"> <objectgroup id="1" name="PlayerStartingPos">
<object id="135" x="901" y="1579"> <object id="135" x="865" y="1447">
<point/> <point/>
</object> </object>
<object id="137" x="861" y="1540"> <object id="137" x="909" y="1447">
<point/> <point/>
</object> </object>
</objectgroup> </objectgroup>

View File

@ -933,7 +933,7 @@
"__id__": 11 "__id__": 11
}, },
"_children": [], "_children": [],
"_active": false, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 23 "__id__": 23
@ -1034,6 +1034,12 @@
}, },
{ {
"__uuid__": "7cb4d395-c68f-4643-9e2e-8cb8e200d3a5" "__uuid__": "7cb4d395-c68f-4643-9e2e-8cb8e200d3a5"
},
{
"__uuid__": "e6e1d62a-de7d-4fe7-858c-2d2725b7c2e8"
},
{
"__uuid__": "e8247e2a-1b5b-4618-86f8-224b25246b55"
} }
], ],
"playOnLoad": false, "playOnLoad": false,

View File

@ -12,6 +12,8 @@ window.ATK_CHARACTER_STATE = {
BlownUp1: [8, "BlownUp1"], BlownUp1: [8, "BlownUp1"],
LayDown1: [9, "LayDown1"], LayDown1: [9, "LayDown1"],
GetUp1: [10, "GetUp1"], GetUp1: [10, "GetUp1"],
Atk2: [11, "Atk2"],
Atk3: [12, "Atk3"],
}; };
window.ATK_CHARACTER_STATE_ARR = []; window.ATK_CHARACTER_STATE_ARR = [];

View File

@ -586,13 +586,13 @@ cc.Class({
const jsPlayersArr = new Array().fill(null); const jsPlayersArr = new Array().fill(null);
for (let k in pbRdf.playersArr) { for (let k in pbRdf.playersArr) {
const pbPlayer = pbRdf.playersArr[k]; const pbPlayer = pbRdf.playersArr[k];
const jsPlayer = gopkgs.NewPlayerDownsyncJs(pbPlayer.id, pbPlayer.virtualGridX, pbPlayer.virtualGridY, pbPlayer.dirX, pbPlayer.dirY, pbPlayer.velX, pbPlayer.velY, pbPlayer.framesToRecover, pbPlayer.framesInChState, pbPlayer.speed, pbPlayer.battleState, pbPlayer.characterState, pbPlayer.joinIndex, pbPlayer.hp, pbPlayer.maxHp, pbPlayer.inAir, pbPlayer.colliderRadius); const jsPlayer = gopkgs.NewPlayerDownsyncJs(pbPlayer.id, pbPlayer.virtualGridX, pbPlayer.virtualGridY, pbPlayer.dirX, pbPlayer.dirY, pbPlayer.velX, pbPlayer.velY, pbPlayer.framesToRecover, pbPlayer.framesInChState, pbPlayer.speed, pbPlayer.battleState, pbPlayer.characterState, pbPlayer.joinIndex, pbPlayer.hp, pbPlayer.maxHp, pbPlayer.colliderRadius, pbPlayer.inAir);
jsPlayersArr[k] = jsPlayer; jsPlayersArr[k] = jsPlayer;
} }
const jsMeleeBulletsArr = []; const jsMeleeBulletsArr = [];
for (let k in pbRdf.meleeBullets) { for (let k in pbRdf.meleeBullets) {
const pbBullet = pbRdf.meleeBullets[k]; const pbBullet = pbRdf.meleeBullets[k];
const jsBullet = gopkgs.NewMeleeBulletJs(pbBullet.originatedRenderFrameId, pbBullet.offenderJoinIndex, pbBullet.startupFrames, pbBullet.cancellableStFrame, pbBullet.cancellableEdFrame, pbBullet.activeFrames, pbBullet.hitStunFrames, pbBullet.blockStunFrames, pbBullet.pushbackX, pbBullet.pushbackY, pbBullet.damage, pbBullet.selfLockVelX, pbBullet.selfLockVelY, pbBullet.hitboxOffsetX, pbBullet.hitboxOffsetY, pbBullet.hitboxSizeX, pbBullet.hitboxSizeY, pbBullet.blowUp); const jsBullet = gopkgs.NewMeleeBulletJs(pbBullet.originatedRenderFrameId, pbBullet.offenderJoinIndex, pbBullet.startupFrames, pbBullet.cancellableStFrame, pbBullet.cancellableEdFrame, pbBullet.activeFrames, pbBullet.hitStunFrames, pbBullet.blockStunFrames, pbBullet.pushbackVelX, pbBullet.pushbackVelY, pbBullet.damage, pbBullet.selfLockVelX, pbBullet.selfLockVelY, pbBullet.hitboxOffsetX, pbBullet.hitboxOffsetY, pbBullet.hitboxSizeX, pbBullet.hitboxSizeY, pbBullet.blowUp);
jsMeleeBulletsArr.push(jsBullet); jsMeleeBulletsArr.push(jsBullet);
} }
@ -832,12 +832,17 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
const chConfig = self.chConfigsOrderedByJoinIndex[joinIndex - 1]; const chConfig = self.chConfigsOrderedByJoinIndex[joinIndex - 1];
playerScriptIns.setSpecies(chConfig.SpeciesName); playerScriptIns.setSpecies(chConfig.SpeciesName);
if (1 == joinIndex) {
newPlayerNode.color = cc.Color.RED;
} else {
newPlayerNode.color = cc.Color.BLUE;
}
const [wx, wy] = gopkgs.VirtualGridToWorldPos(vx, vy); const [wx, wy] = gopkgs.VirtualGridToWorldPos(vx, vy);
newPlayerNode.setPosition(wx, wy); newPlayerNode.setPosition(wx, wy);
playerScriptIns.mapNode = self.node; playerScriptIns.mapNode = self.node;
const colliderRadius = playerDownsyncInfo.ColliderRadius; const colliderRadius = playerDownsyncInfo.ColliderRadius;
const halfColliderWidth = colliderRadius, const [halfColliderWidth, halfColliderHeight] = gopkgs.VirtualGridToWorldPos(colliderRadius, colliderRadius + colliderRadius); // avoid multiplying
halfColliderHeight = colliderRadius + colliderRadius; // avoid multiplying
const colliderWidth = halfColliderWidth + halfColliderWidth, const colliderWidth = halfColliderWidth + halfColliderWidth,
colliderHeight = halfColliderHeight + halfColliderHeight; // avoid multiplying colliderHeight = halfColliderHeight + halfColliderHeight; // avoid multiplying
@ -846,7 +851,7 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex; const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex;
self.gopkgsCollisionSysMap[collisionPlayerIndex] = newPlayerCollider; self.gopkgsCollisionSysMap[collisionPlayerIndex] = newPlayerCollider;
console.log(`Created new player collider: joinIndex=${joinIndex}, colliderRadius=${playerDownsyncInfo.ColliderRadius}`); console.log(`Created new player collider: joinIndex=${joinIndex}`);
safelyAddChild(self.node, newPlayerNode); safelyAddChild(self.node, newPlayerNode);
setLocalZOrder(newPlayerNode, 5); setLocalZOrder(newPlayerNode, 5);

View File

@ -123,7 +123,9 @@ cc.Class({
} }
const p1Vpos = gopkgs.WorldToVirtualGridPos(boundaryObjs.playerStartingPositions[0].x, boundaryObjs.playerStartingPositions[0].y); const p1Vpos = gopkgs.WorldToVirtualGridPos(boundaryObjs.playerStartingPositions[0].x, boundaryObjs.playerStartingPositions[0].y);
const p2Vpos = gopkgs.WorldToVirtualGridPos(boundaryObjs.playerStartingPositions[1].x, boundaryObjs.playerStartingPositions[1].y);
const speedV = gopkgs.WorldToVirtualGridPos(1.0, 0); const speedV = gopkgs.WorldToVirtualGridPos(1.0, 0);
const colliderRadiusV = gopkgs.WorldToVirtualGridPos(12.0, 0);
const startRdf = window.pb.protos.RoomDownsyncFrame.create({ const startRdf = window.pb.protos.RoomDownsyncFrame.create({
id: window.MAGIC_ROOM_DOWNSYNC_FRAME_ID.BATTLE_START, id: window.MAGIC_ROOM_DOWNSYNC_FRAME_ID.BATTLE_START,
@ -134,17 +136,32 @@ cc.Class({
virtualGridX: p1Vpos[0], virtualGridX: p1Vpos[0],
virtualGridY: p1Vpos[1], virtualGridY: p1Vpos[1],
speed: speedV[0], speed: speedV[0],
colliderRadius: 12, colliderRadius: colliderRadiusV[0],
characterState: window.ATK_CHARACTER_STATE.InAirIdle1NoJump[0], characterState: window.ATK_CHARACTER_STATE.InAirIdle1NoJump[0],
framesToRecover: 0, framesToRecover: 0,
dirX: 0, dirX: +2,
dirY: 0,
velX: 0,
velY: 0,
inAir: true,
}),
window.pb.protos.PlayerDownsync.create({
id: 11,
joinIndex: 2,
virtualGridX: p2Vpos[0],
virtualGridY: p2Vpos[1],
speed: speedV[0],
colliderRadius: colliderRadiusV[0],
characterState: window.ATK_CHARACTER_STATE.InAirIdle1NoJump[0],
framesToRecover: 0,
dirX: -2,
dirY: 0, dirY: 0,
velX: 0, velX: 0,
velY: 0, velY: 0,
inAir: true, inAir: true,
}), }),
], ],
speciesIdList: [0], speciesIdList: [0, 0],
}); });
self.selfPlayerInfo = { self.selfPlayerInfo = {

View File

@ -7,6 +7,7 @@ import (
const ( const (
MAX_FLOAT64 = 1.7e+308 MAX_FLOAT64 = 1.7e+308
MAX_INT32 = int32(999999999)
COLLISION_PLAYER_INDEX_PREFIX = (1 << 17) COLLISION_PLAYER_INDEX_PREFIX = (1 << 17)
COLLISION_BARRIER_INDEX_PREFIX = (1 << 16) COLLISION_BARRIER_INDEX_PREFIX = (1 << 16)
COLLISION_BULLET_INDEX_PREFIX = (1 << 15) COLLISION_BULLET_INDEX_PREFIX = (1 << 15)
@ -26,6 +27,9 @@ const (
SNAP_INTO_PLATFORM_OVERLAP = float64(0.1) SNAP_INTO_PLATFORM_OVERLAP = float64(0.1)
SNAP_INTO_PLATFORM_THRESHOLD = float64(0.5) SNAP_INTO_PLATFORM_THRESHOLD = float64(0.5)
NO_SKILL = int32(-1)
NO_SKILL_HIT = int32(-1)
) )
// These directions are chosen such that when speed is changed to "(speedX+delta, speedY+delta)" for any of them, the direction is unchanged. // These directions are chosen such that when speed is changed to "(speedX+delta, speedY+delta)" for any of them, the direction is unchanged.
@ -53,6 +57,9 @@ const (
ATK_CHARACTER_STATE_BLOWN_UP1 = int32(8) ATK_CHARACTER_STATE_BLOWN_UP1 = int32(8)
ATK_CHARACTER_STATE_LAY_DOWN1 = int32(9) ATK_CHARACTER_STATE_LAY_DOWN1 = int32(9)
ATK_CHARACTER_STATE_GET_UP1 = int32(10) ATK_CHARACTER_STATE_GET_UP1 = int32(10)
ATK_CHARACTER_STATE_ATK2 = int32(11)
ATK_CHARACTER_STATE_ATK3 = int32(12)
) )
var inAirSet = map[int32]bool{ var inAirSet = map[int32]bool{
@ -63,6 +70,22 @@ var inAirSet = map[int32]bool{
ATK_CHARACTER_STATE_BLOWN_UP1: true, ATK_CHARACTER_STATE_BLOWN_UP1: true,
} }
var noOpSet = map[int32]bool{
ATK_CHARACTER_STATE_ATKED1: true,
ATK_CHARACTER_STATE_INAIR_ATKED1: true,
ATK_CHARACTER_STATE_BLOWN_UP1: true,
ATK_CHARACTER_STATE_LAY_DOWN1: true,
// During the invinsible frames of GET_UP1, the player is allowed to take any action
}
var invinsibleSet = map[int32]bool{
ATK_CHARACTER_STATE_BLOWN_UP1: true,
ATK_CHARACTER_STATE_LAY_DOWN1: true,
ATK_CHARACTER_STATE_GET_UP1: true,
}
var nonAttackingSet = map[int32]bool{}
func ConvertToInputFrameId(renderFrameId int32, inputDelayFrames int32, inputScaleFrames uint32) int32 { func ConvertToInputFrameId(renderFrameId int32, inputDelayFrames int32, inputScaleFrames uint32) int32 {
if renderFrameId < inputDelayFrames { if renderFrameId < inputDelayFrames {
return 0 return 0
@ -329,6 +352,10 @@ func deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame *PlayerDownsync,
return PATTERN_ID_UNABLE_TO_OP, false, 0, 0 return PATTERN_ID_UNABLE_TO_OP, false, 0, 0
} }
if _, existent := noOpSet[currPlayerDownsync.CharacterState]; existent {
return PATTERN_ID_UNABLE_TO_OP, false, 0, 0
}
delayedInputList := inputsBuffer.GetByFrameId(delayedInputFrameId).(*InputFrameDownsync).InputList delayedInputList := inputsBuffer.GetByFrameId(delayedInputFrameId).(*InputFrameDownsync).InputList
var delayedInputListForPrevRdf []uint64 = nil var delayedInputListForPrevRdf []uint64 = nil
if 0 < delayedInputFrameIdForPrevRdf { if 0 < delayedInputFrameIdForPrevRdf {
@ -337,11 +364,8 @@ func deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame *PlayerDownsync,
jumpedOrNot := false jumpedOrNot := false
joinIndex := currPlayerDownsync.JoinIndex joinIndex := currPlayerDownsync.JoinIndex
if 0 < currPlayerDownsync.FramesToRecover {
return PATTERN_ID_UNABLE_TO_OP, false, 0, 0
}
decodedInput := decodeInput(delayedInputList[joinIndex-1]) decodedInput := decodeInput(delayedInputList[joinIndex-1])
effDx, effDy := decodedInput.Dx, decodedInput.Dy effDx, effDy := int32(0), int32(0)
prevBtnALevel, prevBtnBLevel := int32(0), int32(0) prevBtnALevel, prevBtnBLevel := int32(0), int32(0)
if nil != delayedInputListForPrevRdf { if nil != delayedInputListForPrevRdf {
prevDecodedInput := decodeInput(delayedInputListForPrevRdf[joinIndex-1]) prevDecodedInput := decodeInput(delayedInputListForPrevRdf[joinIndex-1])
@ -349,20 +373,40 @@ func deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame *PlayerDownsync,
prevBtnBLevel = prevDecodedInput.BtnBLevel prevBtnBLevel = prevDecodedInput.BtnBLevel
} }
if decodedInput.BtnBLevel > prevBtnBLevel { if 0 == currPlayerDownsync.FramesToRecover {
if _, existent := inAirSet[currPlayerDownsync.CharacterState]; !existent { // Jumping and moving are only allowed here
jumpedOrNot = true effDx, effDy = decodedInput.Dx, decodedInput.Dy
if decodedInput.BtnBLevel > prevBtnBLevel {
if _, existent := inAirSet[currPlayerDownsync.CharacterState]; !existent {
jumpedOrNot = true
}
} }
} }
/*
As long as the current "CharacterState" is not in "noOpSet", we have 2 cases where attacking is allowed:
1. it happens when the player is IDLE or Walking, i.e. "0 == currPlayerDownsync.FramesToRecover", which is just the normal case
2. it happens when the player is having non-empty "ActiveSkillId" which might be cancellable
*/
patternId := PATTERN_ID_NO_OP patternId := PATTERN_ID_NO_OP
if decodedInput.BtnALevel > prevBtnALevel { if decodedInput.BtnALevel > prevBtnALevel {
if currPlayerDownsync.InAir { if currPlayerDownsync.InAir {
patternId = 1 patternId = 255
} else { } else {
patternId = 0 patternId = 1
}
}
if PATTERN_ID_NO_OP != patternId && 0 < currPlayerDownsync.FramesToRecover {
// [WARN] Handle skill cancellation
patternId = PATTERN_ID_NO_OP // First, reset the patternId to no-op as it should be by default not cancelling anything
skillConfig := skills[int(currPlayerDownsync.ActiveSkillId)]
switch v := skillConfig.Hits[currPlayerDownsync.ActiveSkillHit].(type) {
case *MeleeBullet:
if v.CancellableStFrame <= currPlayerDownsync.FramesInChState && currPlayerDownsync.FramesInChState < v.CancellableEdFrame {
patternId = int(currPlayerDownsync.ActiveSkillId + 1) // if "currPlayerDownsync.InAir", it won't map to a valid skill in the next step and thus act as PATTERN_ID_NO_OP
}
} }
effDx, effDy = 0, 0 // Most patterns/skills should not allow simultaneous movement
} }
return patternId, jumpedOrNot, effDx, effDy return patternId, jumpedOrNot, effDx, effDy
@ -394,6 +438,8 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
MaxHp: currPlayerDownsync.MaxHp, MaxHp: currPlayerDownsync.MaxHp,
FramesToRecover: currPlayerDownsync.FramesToRecover - 1, FramesToRecover: currPlayerDownsync.FramesToRecover - 1,
FramesInChState: currPlayerDownsync.FramesInChState + 1, FramesInChState: currPlayerDownsync.FramesInChState + 1,
ActiveSkillId: currPlayerDownsync.ActiveSkillId,
ActiveSkillHit: currPlayerDownsync.ActiveSkillHit,
} }
if nextRenderFramePlayers[i].FramesToRecover < 0 { if nextRenderFramePlayers[i].FramesToRecover < 0 {
nextRenderFramePlayers[i].FramesToRecover = 0 nextRenderFramePlayers[i].FramesToRecover = 0
@ -411,9 +457,6 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
chConfig := chConfigsOrderedByJoinIndex[i] chConfig := chConfigsOrderedByJoinIndex[i]
thatPlayerInNextFrame := nextRenderFramePlayers[i] thatPlayerInNextFrame := nextRenderFramePlayers[i]
patternId, jumpedOrNot, effDx, effDy := deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame, currRenderFrame, inputsBuffer, INPUT_DELAY_FRAMES, INPUT_SCALE_FRAMES) patternId, jumpedOrNot, effDx, effDy := deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame, currRenderFrame, inputsBuffer, INPUT_DELAY_FRAMES, INPUT_SCALE_FRAMES)
if PATTERN_ID_UNABLE_TO_OP == patternId {
continue
}
if jumpedOrNot { if jumpedOrNot {
thatPlayerInNextFrame.VelY = int32(chConfig.JumpingInitVelY) thatPlayerInNextFrame.VelY = int32(chConfig.JumpingInitVelY)
@ -423,8 +466,13 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
if PATTERN_ID_NO_OP != patternId { if PATTERN_ID_NO_OP != patternId {
if skillId, existent := chConfig.PatternIdToSkillId[patternId]; existent { if skillId, existent := chConfig.PatternIdToSkillId[patternId]; existent {
skillConfig := skills[skillId] skillConfig := skills[skillId]
thatPlayerInNextFrame.ActiveSkillId = int32(skillId)
thatPlayerInNextFrame.ActiveSkillHit = 0
// TODO: Respect non-zero "selfLockVel"
// Hardcoded to use only the first hit for now // Hardcoded to use only the first hit for now
switch v := skillConfig.Hits[0].(type) { switch v := skillConfig.Hits[thatPlayerInNextFrame.ActiveSkillHit].(type) {
case *MeleeBullet: case *MeleeBullet:
var newBullet MeleeBullet = *v // Copied primitive fields into an onstack variable var newBullet MeleeBullet = *v // Copied primitive fields into an onstack variable
newBullet.OriginatedRenderFrameId = currRenderFrame.Id newBullet.OriginatedRenderFrameId = currRenderFrame.Id
@ -432,21 +480,32 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
nextRenderFrameMeleeBullets = append(nextRenderFrameMeleeBullets, &newBullet) nextRenderFrameMeleeBullets = append(nextRenderFrameMeleeBullets, &newBullet)
thatPlayerInNextFrame.FramesToRecover = skillConfig.RecoveryFrames thatPlayerInNextFrame.FramesToRecover = skillConfig.RecoveryFrames
} }
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_ATK1
// TODO: How to differentiate skill cancellable among different characters, e.g. some characters might be allowed to have 4-cancellation-combo or more?
switch skillId {
case 1:
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_ATK1
case 2:
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_ATK2
case 3:
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_ATK3
}
if false == currPlayerDownsync.InAir { if false == currPlayerDownsync.InAir {
thatPlayerInNextFrame.VelX = 0 thatPlayerInNextFrame.VelX = 0
} }
continue // Don't allow movement if skill is used
} }
continue
} }
if 0 != effDx || 0 != effDy { if 0 == currPlayerDownsync.FramesToRecover {
thatPlayerInNextFrame.DirX, thatPlayerInNextFrame.DirY = effDx, effDy if 0 != effDx || 0 != effDy {
thatPlayerInNextFrame.VelX = effDx * currPlayerDownsync.Speed thatPlayerInNextFrame.DirX, thatPlayerInNextFrame.DirY = effDx, effDy
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_WALKING thatPlayerInNextFrame.VelX = effDx * currPlayerDownsync.Speed
} else { thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_WALKING
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_IDLE1 } else {
thatPlayerInNextFrame.VelX = 0 thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_IDLE1
thatPlayerInNextFrame.VelX = 0
}
} }
} }
@ -597,29 +656,21 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
if v.OffenderJoinIndex == t.JoinIndex { if v.OffenderJoinIndex == t.JoinIndex {
continue continue
} }
if _, existent := invinsibleSet[t.CharacterState]; existent {
continue
}
overlapped, _, _, _ := CalcPushbacks(0, 0, bulletShape, defenderShape) overlapped, _, _, _ := CalcPushbacks(0, 0, bulletShape, defenderShape)
if !overlapped { if !overlapped {
continue continue
} }
joinIndex := t.JoinIndex
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
} }
pushbackX, pushbackY := VirtualGridToWorldPos(-xfac*v.PushbackX, v.PushbackY) pushbackVelX, pushbackVelY := xfac*v.PushbackVelX, v.PushbackVelY
for _, hardPushbackNorm := range *hardPushbackNorms[joinIndex-1] {
projectedMagnitude := pushbackX*hardPushbackNorm.X + pushbackY*hardPushbackNorm.Y
if 0 > projectedMagnitude {
//fmt.Printf("defenderPlayerId=%d, joinIndex=%d reducing bullet pushback={%.3f, %.3f} by {%.3f, %.3f} where hardPushbackNorm={%.3f, %.3f}, projectedMagnitude=%.3f at renderFrame.id=%d", t.Id, joinIndex, pushbackX, pushbackY, projectedMagnitude*hardPushbackNorm.X, projectedMagnitude*hardPushbackNorm.Y, hardPushbackNorm.X, hardPushbackNorm.Y, projectedMagnitude, currRenderFrame.Id)
pushbackX -= projectedMagnitude * hardPushbackNorm.X
pushbackY -= projectedMagnitude * hardPushbackNorm.Y
}
}
effPushbacks[joinIndex-1].X += pushbackX
effPushbacks[joinIndex-1].Y += pushbackY
atkedPlayerInNextFrame := nextRenderFramePlayers[t.JoinIndex-1] atkedPlayerInNextFrame := nextRenderFramePlayers[t.JoinIndex-1]
atkedPlayerInNextFrame.VelX = pushbackVelX
atkedPlayerInNextFrame.VelY = pushbackVelY
if v.BlowUp { if v.BlowUp {
atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_BLOWN_UP1 atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_BLOWN_UP1
} else { } else {
@ -656,13 +707,22 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
} }
case ATK_CHARACTER_STATE_ATK1: case ATK_CHARACTER_STATE_ATK1:
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_ATK1 thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_ATK1
// No inAir transition for ATK2/ATK3 for now
case ATK_CHARACTER_STATE_ATKED1: case ATK_CHARACTER_STATE_ATKED1:
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_ATKED1 thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_ATKED1
} }
} }
// Reset "FramesInChState" if "CharacterState" is changed
if thatPlayerInNextFrame.CharacterState != currPlayerDownsync.CharacterState { if thatPlayerInNextFrame.CharacterState != currPlayerDownsync.CharacterState {
thatPlayerInNextFrame.FramesInChState = 0 thatPlayerInNextFrame.FramesInChState = 0
} }
// Remove any active skill if not attacking
if _, existent := nonAttackingSet[thatPlayerInNextFrame.CharacterState]; existent {
thatPlayerInNextFrame.ActiveSkillId = NO_SKILL
thatPlayerInNextFrame.ActiveSkillHit = NO_SKILL_HIT
}
} }
return &RoomDownsyncFrame{ return &RoomDownsyncFrame{

View File

@ -35,37 +35,91 @@ var Characters = map[int]*CharacterConfig{
JumpingInitVelY: int32(float64(8) * WORLD_TO_VIRTUAL_GRID_RATIO), JumpingInitVelY: int32(float64(8) * WORLD_TO_VIRTUAL_GRID_RATIO),
PatternIdToSkillId: map[int]int{ PatternIdToSkillId: map[int]int{
0: 1, // Atk1 1: 1, // Atk1
1: 2, // InAirAtk1 2: 2, // Atk2
3: 3, // Atk3
255: 255, // InAirAtk1
}, },
}, },
} }
var skills = map[int]*Skill{ var skills = map[int]*Skill{
1: &Skill{ 1: &Skill{
RecoveryFrames: int32(34), RecoveryFrames: int32(20),
RecoveryFramesOnBlock: int32(34), RecoveryFramesOnBlock: int32(20),
RecoveryFramesOnHit: int32(34), RecoveryFramesOnHit: int32(20),
ReleaseTriggerType: int32(1), ReleaseTriggerType: int32(1),
Hits: []interface{}{ Hits: []interface{}{
&MeleeBullet{ &MeleeBullet{
Bullet: Bullet{ Bullet: Bullet{
StartupFrames: int32(5), StartupFrames: int32(5),
ActiveFrames: int32(10), ActiveFrames: int32(10),
HitStunFrames: int32(18), HitStunFrames: int32(13),
BlockStunFrames: int32(9), BlockStunFrames: int32(9),
Damage: int32(5), Damage: int32(5),
PushbackX: int32(float64(8) * WORLD_TO_VIRTUAL_GRID_RATIO), PushbackVelX: int32(float64(0.5) * WORLD_TO_VIRTUAL_GRID_RATIO),
PushbackY: int32(0), PushbackVelY: int32(0),
HitboxOffsetX: int32(float64(12) * WORLD_TO_VIRTUAL_GRID_RATIO), HitboxOffsetX: int32(float64(12) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxOffsetY: int32(0), HitboxOffsetY: int32(0),
HitboxSizeX: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO), HitboxSizeX: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO), HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
CancellableStFrame: int32(8),
CancellableEdFrame: int32(20),
// TODO: Use non-zero "selfLockVel"
}, },
}, },
}, },
}, },
2: &Skill{ 2: &Skill{
RecoveryFrames: int32(36),
RecoveryFramesOnBlock: int32(36),
RecoveryFramesOnHit: int32(36),
ReleaseTriggerType: int32(1),
Hits: []interface{}{
&MeleeBullet{
Bullet: Bullet{
StartupFrames: int32(3),
ActiveFrames: int32(20),
HitStunFrames: int32(18),
BlockStunFrames: int32(9),
Damage: int32(5),
PushbackVelX: int32(float64(0.5) * WORLD_TO_VIRTUAL_GRID_RATIO),
PushbackVelY: int32(0),
HitboxOffsetX: int32(float64(18) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxOffsetY: int32(0),
HitboxSizeX: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
CancellableStFrame: int32(18),
CancellableEdFrame: int32(36),
},
},
},
},
3: &Skill{
RecoveryFrames: int32(60),
RecoveryFramesOnBlock: int32(60),
RecoveryFramesOnHit: int32(60),
ReleaseTriggerType: int32(1),
Hits: []interface{}{
&MeleeBullet{
Bullet: Bullet{
StartupFrames: int32(1),
ActiveFrames: int32(30),
HitStunFrames: MAX_INT32,
BlockStunFrames: int32(9),
Damage: int32(10),
PushbackVelX: int32(float64(1) * WORLD_TO_VIRTUAL_GRID_RATIO),
PushbackVelY: int32(float64(4) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxOffsetX: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxOffsetY: int32(0),
HitboxSizeX: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
BlowUp: true,
},
},
},
},
255: &Skill{
RecoveryFrames: int32(34), RecoveryFrames: int32(34),
RecoveryFramesOnBlock: int32(34), RecoveryFramesOnBlock: int32(34),
RecoveryFramesOnHit: int32(34), RecoveryFramesOnHit: int32(34),
@ -78,8 +132,8 @@ var skills = map[int]*Skill{
HitStunFrames: int32(18), HitStunFrames: int32(18),
BlockStunFrames: int32(9), BlockStunFrames: int32(9),
Damage: int32(5), Damage: int32(5),
PushbackX: int32(float64(6) * WORLD_TO_VIRTUAL_GRID_RATIO), PushbackVelX: int32(float64(0.5) * WORLD_TO_VIRTUAL_GRID_RATIO),
PushbackY: int32(0), PushbackVelY: int32(0),
HitboxOffsetX: int32(float64(12) * WORLD_TO_VIRTUAL_GRID_RATIO), HitboxOffsetX: int32(float64(12) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxOffsetY: int32(0), HitboxOffsetY: int32(0),
HitboxSizeX: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO), HitboxSizeX: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),

View File

@ -23,7 +23,7 @@ type PlayerDownsync struct {
Speed int32 Speed int32
BattleState int32 BattleState int32
JoinIndex int32 JoinIndex int32
ColliderRadius float64 ColliderRadius int32
Removed bool Removed bool
Score int32 Score int32
LastMoveGmtMillis int32 LastMoveGmtMillis int32
@ -33,6 +33,9 @@ type PlayerDownsync struct {
MaxHp int32 MaxHp int32
CharacterState int32 CharacterState int32
InAir bool InAir bool
ActiveSkillId int32
ActiveSkillHit int32
} }
type InputFrameDecoded struct { type InputFrameDecoded struct {
@ -63,8 +66,8 @@ type Bullet struct {
// for defender // for defender
HitStunFrames int32 HitStunFrames int32
BlockStunFrames int32 BlockStunFrames int32
PushbackX int32 PushbackVelX int32
PushbackY int32 PushbackVelY int32
Damage int32 Damage int32
SelfLockVelX int32 SelfLockVelX int32

View File

@ -42,7 +42,7 @@ func NewBarrierJs(boundary *Polygon2D) *js.Object {
}) })
} }
func NewPlayerDownsyncJs(id, virtualGridX, virtualGridY, dirX, dirY, velX, velY, framesToRecover, framesInChState, speed, battleState, characterState, joinIndex, hp, maxHp int32, inAir bool, colliderRadius float64) *js.Object { func NewPlayerDownsyncJs(id, virtualGridX, virtualGridY, dirX, dirY, velX, velY, framesToRecover, framesInChState, speed, battleState, characterState, joinIndex, hp, maxHp, colliderRadius int32, inAir bool) *js.Object {
return js.MakeWrapper(&PlayerDownsync{ return js.MakeWrapper(&PlayerDownsync{
Id: id, Id: id,
VirtualGridX: virtualGridX, VirtualGridX: virtualGridX,
@ -64,7 +64,7 @@ func NewPlayerDownsyncJs(id, virtualGridX, virtualGridY, dirX, dirY, velX, velY,
}) })
} }
func NewMeleeBulletJs(originatedRenderFrameId, offenderJoinIndex, startupFrames, cancellableStFrame, cancellableEdFrame, activeFrames, hitStunFrames, blockStunFrames, pushbackX, pushbackY, damage, selfLockVelX, selfLockVelY, hitboxOffsetX, hitboxOffsetY, hitboxSizeX, hitboxSizeY int32, blowUp bool) *js.Object { func NewMeleeBulletJs(originatedRenderFrameId, offenderJoinIndex, startupFrames, cancellableStFrame, cancellableEdFrame, activeFrames, hitStunFrames, blockStunFrames, pushbackVelX, pushbackVelY, damage, selfLockVelX, selfLockVelY, hitboxOffsetX, hitboxOffsetY, hitboxSizeX, hitboxSizeY int32, blowUp bool) *js.Object {
return js.MakeWrapper(&MeleeBullet{ return js.MakeWrapper(&MeleeBullet{
Bullet: Bullet{ Bullet: Bullet{
OriginatedRenderFrameId: originatedRenderFrameId, OriginatedRenderFrameId: originatedRenderFrameId,
@ -77,8 +77,8 @@ func NewMeleeBulletJs(originatedRenderFrameId, offenderJoinIndex, startupFrames,
HitStunFrames: hitStunFrames, HitStunFrames: hitStunFrames,
BlockStunFrames: blockStunFrames, BlockStunFrames: blockStunFrames,
PushbackX: pushbackX, PushbackVelX: pushbackVelX,
PushbackY: pushbackY, PushbackVelY: pushbackVelY,
Damage: damage, Damage: damage,
SelfLockVelX: selfLockVelX, SelfLockVelX: selfLockVelX,