Rework unit animations as frame-by-frame sheets
This commit is contained in:
@@ -4,7 +4,13 @@ import { battleMapAssets } from '../data/battleMapAssets';
|
||||
import { type BattleBond, type UnitData, type UnitStats } from '../data/scenario';
|
||||
import { defaultBattleScenario, getBattleScenario, type BattleObjectiveDefinition, type BattleScenarioDefinition } from '../data/battles';
|
||||
import { getTerrainRule, getUnitClass, type TerrainType, type UnitClassKey } from '../data/battleRules';
|
||||
import { ensureUnitAnimations, loadUnitSheets, unitTextureVariantKeys as unitAssetTextureVariantKeys } from '../data/unitAssets';
|
||||
import {
|
||||
ensureUnitAnimations,
|
||||
loadUnitSheets,
|
||||
unitBaseFramesPerDirection,
|
||||
unitTextureVariantKeys as unitAssetTextureVariantKeys,
|
||||
type UnitDirection
|
||||
} from '../data/unitAssets';
|
||||
import {
|
||||
equipmentExpToNext,
|
||||
equipmentSlotLabels,
|
||||
@@ -1013,15 +1019,21 @@ const unitFrameRows: Record<UnitDirection, number> = {
|
||||
west: 3
|
||||
};
|
||||
|
||||
const unitActionColumns: Record<UnitActionPose, number> = {
|
||||
attack: 0,
|
||||
strategy: 1,
|
||||
item: 2,
|
||||
hurt: 3,
|
||||
celebrate: 4
|
||||
const unitActionFrameCounts: Record<UnitActionPose, number> = {
|
||||
attack: 10,
|
||||
strategy: 8,
|
||||
item: 8,
|
||||
hurt: 4,
|
||||
celebrate: 6
|
||||
};
|
||||
const unitActionFrameCount = 4;
|
||||
const unitActionPoseCount = 5;
|
||||
const unitActionColumnOffsets: Record<UnitActionPose, number> = {
|
||||
attack: 0,
|
||||
strategy: 10,
|
||||
item: 18,
|
||||
hurt: 26,
|
||||
celebrate: 30
|
||||
};
|
||||
const unitActionFramesPerDirection = Object.values(unitActionFrameCounts).reduce((sum, count) => sum + count, 0);
|
||||
|
||||
type BattleLayout = {
|
||||
mapX: number;
|
||||
@@ -1068,7 +1080,6 @@ type UnitView = {
|
||||
idleTween?: Phaser.Tweens.Tween;
|
||||
};
|
||||
|
||||
type UnitDirection = 'south' | 'east' | 'north' | 'west';
|
||||
type UnitActionPose = 'attack' | 'strategy' | 'item' | 'hurt' | 'celebrate';
|
||||
|
||||
const levelUpCelebrationStepOffsets = [0, -7, -2, -9, 0, -6, -3, -8];
|
||||
@@ -5408,7 +5419,8 @@ export class BattleScene extends Phaser.Scene {
|
||||
const baseX = sprite.x;
|
||||
const baseAngle = sprite.angle;
|
||||
const pose = this.celebrationPose(unit);
|
||||
const frames = Array.from({ length: unitActionFrameCount * 2 }, (_, index) => index % unitActionFrameCount);
|
||||
const frameCount = unitActionFrameCounts[pose];
|
||||
const frames = Array.from({ length: frameCount * 2 }, (_, index) => index % frameCount);
|
||||
return new Promise<void>((resolve) => {
|
||||
frames.forEach((frame, index) => {
|
||||
this.time.delayedCall(index * 105, () => {
|
||||
@@ -7870,7 +7882,7 @@ export class BattleScene extends Phaser.Scene {
|
||||
await this.delay(mounted ? 170 : 205);
|
||||
|
||||
soundDirector.playMeleeSwing(result.hit, result.critical);
|
||||
this.setUnitActionFrame(attackerSprite, result.attacker, 'east', 'attack', 2);
|
||||
this.setUnitActionFrame(attackerSprite, result.attacker, 'east', 'attack', this.unitActionImpactFrame('attack'));
|
||||
this.createSlashArc(defenderX - direction * 68, groundY - 48, direction, depth + 2, result.critical);
|
||||
|
||||
if (result.hit) {
|
||||
@@ -9148,7 +9160,7 @@ export class BattleScene extends Phaser.Scene {
|
||||
}
|
||||
|
||||
private unitFrameIndex(direction: UnitDirection, frame = 0) {
|
||||
return unitFrameRows[direction] * 4 + frame;
|
||||
return unitFrameRows[direction] * unitBaseFramesPerDirection + frame;
|
||||
}
|
||||
|
||||
private unitTextureKey(unit: UnitData) {
|
||||
@@ -9304,8 +9316,13 @@ export class BattleScene extends Phaser.Scene {
|
||||
}
|
||||
|
||||
private unitActionFrameIndex(direction: UnitDirection, pose: UnitActionPose, frame = 0) {
|
||||
const safeFrame = Phaser.Math.Clamp(frame, 0, unitActionFrameCount - 1);
|
||||
return unitFrameRows[direction] * unitActionPoseCount * unitActionFrameCount + unitActionColumns[pose] * unitActionFrameCount + safeFrame;
|
||||
const frameCount = unitActionFrameCounts[pose];
|
||||
const safeFrame = Phaser.Math.Clamp(frame, 0, frameCount - 1);
|
||||
return unitFrameRows[direction] * unitActionFramesPerDirection + unitActionColumnOffsets[pose] + safeFrame;
|
||||
}
|
||||
|
||||
private unitActionImpactFrame(pose: UnitActionPose) {
|
||||
return Math.max(0, Math.floor(unitActionFrameCounts[pose] * 0.55));
|
||||
}
|
||||
|
||||
private setUnitActionFrame(sprite: Phaser.GameObjects.Sprite, unit: UnitData, direction: UnitDirection, pose: UnitActionPose, frame = 0) {
|
||||
@@ -9320,12 +9337,13 @@ export class BattleScene extends Phaser.Scene {
|
||||
frameDuration = 86,
|
||||
loops = 1
|
||||
) {
|
||||
const totalFrames = unitActionFrameCount * Math.max(1, loops);
|
||||
const frameCount = unitActionFrameCounts[pose];
|
||||
const totalFrames = frameCount * Math.max(1, loops);
|
||||
return new Promise<void>((resolve) => {
|
||||
for (let index = 0; index < totalFrames; index += 1) {
|
||||
this.time.delayedCall(index * frameDuration, () => {
|
||||
if (sprite.active) {
|
||||
this.setUnitActionFrame(sprite, unit, direction, pose, index % unitActionFrameCount);
|
||||
this.setUnitActionFrame(sprite, unit, direction, pose, index % frameCount);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user