Rework unit animations as frame-by-frame sheets

This commit is contained in:
2026-06-29 01:04:54 +09:00
parent d1a9dcd37c
commit e4f2754b08
185 changed files with 216 additions and 62 deletions

View File

@@ -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);
}
});
}