Add signature unit visuals
This commit is contained in:
@@ -28,8 +28,11 @@ const unitTexture: Record<string, string> = {
|
||||
'liu-bei': 'unit-liu-bei',
|
||||
'guan-yu': 'unit-guan-yu',
|
||||
'zhang-fei': 'unit-zhang-fei',
|
||||
'zhao-yun': 'unit-rebel-cavalry',
|
||||
'zhuge-liang': 'unit-liu-bei',
|
||||
'zhao-yun': 'unit-zhao-yun',
|
||||
'zhuge-liang': 'unit-zhuge-liang',
|
||||
'jiang-wei': 'unit-jiang-wei',
|
||||
'northern-second-officer-jiang-wei': 'unit-jiang-wei',
|
||||
'northern-third-officer-jiang-wei': 'unit-jiang-wei',
|
||||
'ma-liang': 'unit-liu-bei',
|
||||
'yi-ji': 'unit-liu-bei',
|
||||
'gong-zhi': 'unit-guan-yu',
|
||||
@@ -930,6 +933,7 @@ const unitTextureByClass: Partial<Record<UnitClassKey, string>> = {
|
||||
};
|
||||
|
||||
const coreAllyTextureIds = new Set(['liu-bei', 'guan-yu', 'zhang-fei']);
|
||||
const signatureUnitTextureIds = new Set(['zhao-yun', 'zhuge-liang', 'jiang-wei', 'northern-second-officer-jiang-wei', 'northern-third-officer-jiang-wei']);
|
||||
|
||||
const earlyRebelTexturePrefixes = ['rebel-', 'pursuit-'];
|
||||
|
||||
@@ -8185,6 +8189,11 @@ export class BattleScene extends Phaser.Scene {
|
||||
}
|
||||
|
||||
private unitTextureKey(unit: UnitData) {
|
||||
const signatureTexture = this.signatureUnitTextureKey(unit);
|
||||
if (signatureTexture) {
|
||||
return signatureTexture;
|
||||
}
|
||||
|
||||
const factionTexture = this.unitFactionTextureKey(unit);
|
||||
if (factionTexture) {
|
||||
return factionTexture;
|
||||
@@ -8220,6 +8229,16 @@ export class BattleScene extends Phaser.Scene {
|
||||
return unitTexture[unit.id] ?? unitTextureByClass[unit.classKey] ?? 'unit-rebel';
|
||||
}
|
||||
|
||||
private signatureUnitTextureKey(unit: UnitData) {
|
||||
if (unit.id.includes('sima-yi') || unit.name === '사마의') {
|
||||
return 'unit-sima-yi';
|
||||
}
|
||||
if (signatureUnitTextureIds.has(unit.id)) {
|
||||
return unitTexture[unit.id];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private unitFactionTextureKey(unit: UnitData) {
|
||||
if (unit.faction === 'ally') {
|
||||
if (coreAllyTextureIds.has(unit.id)) {
|
||||
|
||||
@@ -24,6 +24,17 @@ import zhangFeiUnitSheetUrl from '../../assets/images/units/unit-zhang-fei.png';
|
||||
import { storyBackgroundAssets } from '../data/storyAssets';
|
||||
|
||||
type UnitDirection = 'south' | 'east' | 'north' | 'west';
|
||||
type UnitSheetDecoration = 'zhaoYun' | 'zhugeLiang' | 'jiangWei' | 'simaYi';
|
||||
|
||||
type GeneratedUnitSheet = {
|
||||
key: string;
|
||||
sourceKey: string;
|
||||
actionKey: string;
|
||||
sourceActionKey: string;
|
||||
tint: number;
|
||||
alpha: number;
|
||||
decoration?: UnitSheetDecoration;
|
||||
};
|
||||
|
||||
const unitWalkFrameCount = 4;
|
||||
const unitSheetFrameSize = 313;
|
||||
@@ -46,18 +57,22 @@ const sourceUnitSheets = [
|
||||
{ key: 'unit-rebel-leader', url: rebelLeaderUnitSheetUrl, actionKey: 'unit-rebel-leader-actions', actionUrl: rebelLeaderActionSheetUrl }
|
||||
];
|
||||
|
||||
const generatedUnitSheets = [
|
||||
const generatedUnitSheets: GeneratedUnitSheet[] = [
|
||||
{ key: 'unit-shu-infantry', sourceKey: 'unit-guan-yu', actionKey: 'unit-shu-infantry-actions', sourceActionKey: 'unit-guan-yu-actions', tint: 0x2f7fba, alpha: 0.32 },
|
||||
{ key: 'unit-shu-spearman', sourceKey: 'unit-zhang-fei', actionKey: 'unit-shu-spearman-actions', sourceActionKey: 'unit-zhang-fei-actions', tint: 0x4aa878, alpha: 0.3 },
|
||||
{ key: 'unit-shu-archer', sourceKey: 'unit-rebel-archer', actionKey: 'unit-shu-archer-actions', sourceActionKey: 'unit-rebel-archer-actions', tint: 0x4b9bd5, alpha: 0.36 },
|
||||
{ key: 'unit-shu-cavalry', sourceKey: 'unit-rebel-cavalry', actionKey: 'unit-shu-cavalry-actions', sourceActionKey: 'unit-rebel-cavalry-actions', tint: 0x488fc4, alpha: 0.36 },
|
||||
{ key: 'unit-shu-strategist', sourceKey: 'unit-liu-bei', actionKey: 'unit-shu-strategist-actions', sourceActionKey: 'unit-liu-bei-actions', tint: 0x75b7d8, alpha: 0.28 },
|
||||
{ key: 'unit-shu-officer', sourceKey: 'unit-guan-yu', actionKey: 'unit-shu-officer-actions', sourceActionKey: 'unit-guan-yu-actions', tint: 0x3f91c8, alpha: 0.36 },
|
||||
{ key: 'unit-zhao-yun', sourceKey: 'unit-rebel-cavalry', actionKey: 'unit-zhao-yun-actions', sourceActionKey: 'unit-rebel-cavalry-actions', tint: 0xd7edf7, alpha: 0.42, decoration: 'zhaoYun' },
|
||||
{ key: 'unit-zhuge-liang', sourceKey: 'unit-liu-bei', actionKey: 'unit-zhuge-liang-actions', sourceActionKey: 'unit-liu-bei-actions', tint: 0xd8efe3, alpha: 0.34, decoration: 'zhugeLiang' },
|
||||
{ key: 'unit-jiang-wei', sourceKey: 'unit-rebel-cavalry', actionKey: 'unit-jiang-wei-actions', sourceActionKey: 'unit-rebel-cavalry-actions', tint: 0x64bfa8, alpha: 0.38, decoration: 'jiangWei' },
|
||||
{ key: 'unit-wei-infantry', sourceKey: 'unit-rebel', actionKey: 'unit-wei-infantry-actions', sourceActionKey: 'unit-rebel-actions', tint: 0x8b3030, alpha: 0.42 },
|
||||
{ key: 'unit-wei-archer', sourceKey: 'unit-rebel-archer', actionKey: 'unit-wei-archer-actions', sourceActionKey: 'unit-rebel-archer-actions', tint: 0x9d3c3c, alpha: 0.4 },
|
||||
{ key: 'unit-wei-cavalry', sourceKey: 'unit-rebel-cavalry', actionKey: 'unit-wei-cavalry-actions', sourceActionKey: 'unit-rebel-cavalry-actions', tint: 0x7a3540, alpha: 0.44 },
|
||||
{ key: 'unit-wei-strategist', sourceKey: 'unit-rebel-archer', actionKey: 'unit-wei-strategist-actions', sourceActionKey: 'unit-rebel-archer-actions', tint: 0x7f5a8e, alpha: 0.38 },
|
||||
{ key: 'unit-wei-officer', sourceKey: 'unit-rebel-leader', actionKey: 'unit-wei-officer-actions', sourceActionKey: 'unit-rebel-leader-actions', tint: 0x8f3940, alpha: 0.44 },
|
||||
{ key: 'unit-sima-yi', sourceKey: 'unit-rebel-leader', actionKey: 'unit-sima-yi-actions', sourceActionKey: 'unit-rebel-leader-actions', tint: 0x1f2638, alpha: 0.58, decoration: 'simaYi' },
|
||||
{ key: 'unit-wu-infantry', sourceKey: 'unit-rebel', actionKey: 'unit-wu-infantry-actions', sourceActionKey: 'unit-rebel-actions', tint: 0x0b8b86, alpha: 0.42 },
|
||||
{ key: 'unit-wu-archer', sourceKey: 'unit-rebel-archer', actionKey: 'unit-wu-archer-actions', sourceActionKey: 'unit-rebel-archer-actions', tint: 0x169b91, alpha: 0.4 },
|
||||
{ key: 'unit-wu-cavalry', sourceKey: 'unit-rebel-cavalry', actionKey: 'unit-wu-cavalry-actions', sourceActionKey: 'unit-rebel-cavalry-actions', tint: 0x087b86, alpha: 0.44 },
|
||||
@@ -368,12 +383,12 @@ export class BootScene extends Phaser.Scene {
|
||||
|
||||
private createGeneratedUnitSheets() {
|
||||
generatedUnitSheets.forEach((sheet) => {
|
||||
this.createTintedUnitSheet(sheet.key, sheet.sourceKey, sheet.tint, sheet.alpha);
|
||||
this.createTintedUnitSheet(sheet.actionKey, sheet.sourceActionKey, sheet.tint, sheet.alpha);
|
||||
this.createTintedUnitSheet(sheet.key, sheet.sourceKey, sheet.tint, sheet.alpha, sheet.decoration);
|
||||
this.createTintedUnitSheet(sheet.actionKey, sheet.sourceActionKey, sheet.tint, sheet.alpha, sheet.decoration);
|
||||
});
|
||||
}
|
||||
|
||||
private createTintedUnitSheet(targetKey: string, sourceKey: string, tint: number, alpha: number) {
|
||||
private createTintedUnitSheet(targetKey: string, sourceKey: string, tint: number, alpha: number, decoration?: UnitSheetDecoration) {
|
||||
if (this.textures.exists(targetKey) || !this.textures.exists(sourceKey)) {
|
||||
return;
|
||||
}
|
||||
@@ -394,12 +409,131 @@ export class BootScene extends Phaser.Scene {
|
||||
context.fillRect(0, 0, canvas.width, canvas.height);
|
||||
context.globalCompositeOperation = 'source-over';
|
||||
context.globalAlpha = 1;
|
||||
if (decoration) {
|
||||
this.decorateUnitSheet(context, decoration, canvas.width, canvas.height);
|
||||
}
|
||||
this.textures.addSpriteSheet(targetKey, canvas as unknown as HTMLImageElement, {
|
||||
frameWidth: unitSheetFrameSize,
|
||||
frameHeight: unitSheetFrameSize
|
||||
});
|
||||
}
|
||||
|
||||
private decorateUnitSheet(context: CanvasRenderingContext2D, decoration: UnitSheetDecoration, width: number, height: number) {
|
||||
const columns = Math.floor(width / unitSheetFrameSize);
|
||||
const rows = Math.floor(height / unitSheetFrameSize);
|
||||
|
||||
for (let row = 0; row < rows; row += 1) {
|
||||
for (let column = 0; column < columns; column += 1) {
|
||||
this.drawUnitDecoration(context, decoration, column * unitSheetFrameSize, row * unitSheetFrameSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private drawUnitDecoration(context: CanvasRenderingContext2D, decoration: UnitSheetDecoration, x: number, y: number) {
|
||||
context.save();
|
||||
context.lineCap = 'round';
|
||||
context.lineJoin = 'round';
|
||||
|
||||
if (decoration === 'zhaoYun') {
|
||||
context.globalAlpha = 0.82;
|
||||
context.fillStyle = '#f4fbff';
|
||||
context.beginPath();
|
||||
context.moveTo(x + 128, y + 106);
|
||||
context.lineTo(x + 86, y + 262);
|
||||
context.lineTo(x + 142, y + 246);
|
||||
context.lineTo(x + 174, y + 112);
|
||||
context.closePath();
|
||||
context.fill();
|
||||
context.strokeStyle = '#d7f2ff';
|
||||
context.lineWidth = 14;
|
||||
context.beginPath();
|
||||
context.moveTo(x + 92, y + 62);
|
||||
context.lineTo(x + 236, y + 266);
|
||||
context.stroke();
|
||||
context.strokeStyle = '#4b87c8';
|
||||
context.lineWidth = 8;
|
||||
context.beginPath();
|
||||
context.moveTo(x + 100, y + 128);
|
||||
context.lineTo(x + 202, y + 242);
|
||||
context.stroke();
|
||||
context.fillStyle = '#f8fbff';
|
||||
context.fillRect(x + 150, y + 38, 12, 42);
|
||||
} else if (decoration === 'zhugeLiang') {
|
||||
context.globalAlpha = 0.82;
|
||||
context.fillStyle = '#eef2df';
|
||||
context.beginPath();
|
||||
context.moveTo(x + 118, y + 112);
|
||||
context.lineTo(x + 96, y + 252);
|
||||
context.lineTo(x + 198, y + 252);
|
||||
context.lineTo(x + 176, y + 112);
|
||||
context.closePath();
|
||||
context.fill();
|
||||
context.strokeStyle = '#d8b15f';
|
||||
context.lineWidth = 8;
|
||||
context.beginPath();
|
||||
context.moveTo(x + 142, y + 88);
|
||||
context.lineTo(x + 190, y + 72);
|
||||
context.stroke();
|
||||
context.strokeStyle = '#f7f0d6';
|
||||
context.lineWidth = 11;
|
||||
for (let index = 0; index < 5; index += 1) {
|
||||
context.beginPath();
|
||||
context.moveTo(x + 206, y + 208);
|
||||
context.lineTo(x + 178 + index * 18, y + 132 + Math.abs(index - 2) * 8);
|
||||
context.stroke();
|
||||
}
|
||||
context.fillStyle = '#f7f0d6';
|
||||
context.beginPath();
|
||||
context.ellipse(x + 206, y + 208, 18, 26, -0.5, 0, Math.PI * 2);
|
||||
context.fill();
|
||||
} else if (decoration === 'jiangWei') {
|
||||
context.globalAlpha = 0.84;
|
||||
context.strokeStyle = '#74f0c8';
|
||||
context.lineWidth = 14;
|
||||
context.beginPath();
|
||||
context.moveTo(x + 92, y + 122);
|
||||
context.lineTo(x + 214, y + 244);
|
||||
context.stroke();
|
||||
context.strokeStyle = '#f1f5e8';
|
||||
context.lineWidth = 10;
|
||||
context.beginPath();
|
||||
context.moveTo(x + 226, y + 60);
|
||||
context.lineTo(x + 118, y + 274);
|
||||
context.stroke();
|
||||
context.fillStyle = '#edf4dc';
|
||||
context.fillRect(x + 194, y + 176, 34, 54);
|
||||
context.strokeStyle = '#2f6e64';
|
||||
context.lineWidth = 5;
|
||||
context.strokeRect(x + 194, y + 176, 34, 54);
|
||||
} else {
|
||||
context.globalAlpha = 0.86;
|
||||
context.fillStyle = '#111522';
|
||||
context.beginPath();
|
||||
context.moveTo(x + 102, y + 102);
|
||||
context.lineTo(x + 70, y + 266);
|
||||
context.lineTo(x + 218, y + 266);
|
||||
context.lineTo(x + 194, y + 102);
|
||||
context.closePath();
|
||||
context.fill();
|
||||
context.strokeStyle = '#d8b15f';
|
||||
context.lineWidth = 8;
|
||||
context.beginPath();
|
||||
context.moveTo(x + 86, y + 118);
|
||||
context.lineTo(x + 214, y + 118);
|
||||
context.stroke();
|
||||
context.strokeStyle = '#9d3c3c';
|
||||
context.lineWidth = 12;
|
||||
context.beginPath();
|
||||
context.moveTo(x + 212, y + 66);
|
||||
context.lineTo(x + 232, y + 238);
|
||||
context.stroke();
|
||||
context.fillStyle = '#71272f';
|
||||
context.fillRect(x + 218, y + 72, 48, 42);
|
||||
}
|
||||
|
||||
context.restore();
|
||||
}
|
||||
|
||||
private createUnitAnimations() {
|
||||
animatedUnitSheets.forEach(({ key }) => {
|
||||
(['south', 'east', 'north', 'west'] as UnitDirection[]).forEach((direction) => {
|
||||
|
||||
Reference in New Issue
Block a user