Skip to content

Instantly share code, notes, and snippets.

@spd789562
Last active November 11, 2023 23:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save spd789562/d521bd370b931cee4b40101d8c6a0bfb to your computer and use it in GitHub Desktop.
Save spd789562/d521bd370b931cee4b40101d8c6a0bfb to your computer and use it in GitHub Desktop.
Maplestory.js with PIXI.js 7 AnimatedSprite
export enum CharacterAction {
Stand1 = 'stand1',
Walk1 = 'walk1',
Alert = 'alert',
}
import MapleStoryBuilder from 'maplestory/dist/bundle';
import type { IRenderRequest } from 'maplestory/dist/Character/IRenderRequest';
import type { AnimatedRenderPlan } from 'maplestory/dist/Character/AnimatedRenderPlan';
import type { RenderPlan } from 'maplestory/dist/Character/RenderPlan';
import * as PIXI from 'pixi.js';
import { CharacterAction } from './action';
import { characterData } from './characterData'
const MapleStory = new MapleStoryBuilder({
Endpoint: 'https://store.maplestory.io/api',
});
class Character {
plan?: AnimatedRenderPlan;
frames: { canvas: HTMLCanvasElement; delay: number; frame: RenderPlan }[] = [];
sprite: PIXI.AnimatedSprite;
constructor(public data: IRenderRequest) {
this.sprite = new PIXI.AnimatedSprite([PIXI.Texture.EMPTY]);
this.sprite.onFrameChange = this.onFrameChange.bind(this);
}
async prepare() {
this.plan = await MapleStory.CharacterRenderer.GenerateAnimatedRenderPlan(this.data);
const allFrames = await Promise.all(this.plan!.frames.map((frame) => frame.Render()));
this.frames = allFrames.map((frame, index) => ({
canvas: frame,
delay: this.plan!.frames[index]!.minimumDelay,
frame: this.plan!.frames[index]!,
}));
this.sprite.textures = this.getTexures();
this.onFrameChange(0);
this.sprite.gotoAndPlay(0);
}
getTexures(): PIXI.FrameObject[] {
return this.frames.map((frame) => {
const texture = new PIXI.Texture(new PIXI.BaseTexture(frame.canvas));
return { texture, time: frame.delay };
});
}
getCurrentOffset(frame: number) {
const currentFrame = this.frames[frame];
return {
x: currentFrame.frame.feetCenter.x - this.plan!.MaxFeetPosition.x,
y: currentFrame.frame.feetCenter.y - this.plan!.MaxFeetPosition.y,
};
}
/* update offset preframe */
onFrameChange(frame: number) {
const offset = this.getCurrentOffset(frame);
this.sprite!.pivot.set(offset.x, offset.y);
}
updateAction(action: CharacterAction) {
this.data.action = action;
this.prepare();
}
}
class App {
app: PIXI.Application;
characters: Character[] = [];
charactersData: IRenderRequest[] = [];
constructor(private canvas: HTMLCanvasElement) {
this.app = new PIXI.Application({
view: canvas,
width: canvas.width,
height: canvas.height,
resolution: window.devicePixelRatio,
autoDensity: true,
});
this.charactersData.push(characterData);
}
async init() {
this.characters = this.charactersData.map((data) => new Character({ ...data }));
await Promise.all(this.characters.map((character) => character.prepare()));
this.characters.forEach((character) => {
this.app.stage.addChild(character.sprite!);
character.sprite!.play();
});
}
}
const canvas = document.querySelector('canvas')!;
const app = new App(canvas);
app.init();
function createUpdateCharacterButton(action: CharacterAction) {
const button = document.createElement('button');
button.innerText = action;
button.onclick = () => {
app.characters.map((ch) => {
ch.updateAction(action);
});
};
return button;
}
const actions = [CharacterAction.Stand1, CharacterAction.Walk1, CharacterAction.Alert];
actions.forEach((action) => {
document.body.appendChild(createUpdateCharacterButton(action));
});
const characterData: IRenderRequest = {
type: 'character',
action: 'stabO2',
emotion: 'default',
skin: 2000,
zoom: 1,
frame: 0,
selectedItems: {
Body: {
name: 'Blushing Rose Hue (Body)',
id: 2016,
region: 'GMS',
version: '217',
typeInfo: {
overallCategory: 'Character',
category: 'Character',
subCategory: 'Body',
lowItemId: 2000,
highItemId: 2999,
},
},
Head: {
name: 'Blushing Rose Hue (Head)',
id: 12016,
region: 'GMS',
version: '217',
typeInfo: {
overallCategory: 'Character',
category: 'Character',
subCategory: 'Head',
lowItemId: 12000,
highItemId: 12999,
},
},
Face: {
name: 'Perplexed Stare (Black)',
id: 20001,
typeInfo: {
overallCategory: 'Equip',
category: 'Character',
subCategory: 'Face',
lowItemId: 20000,
highItemId: 29999,
},
region: 'GMS',
version: '217',
visible: false,
},
Overall: {
name: 'Black Dragon Robe',
id: 1050011,
typeInfo: {
overallCategory: 'Equip',
category: 'Armor',
subCategory: 'Overall',
lowItemId: 1050000,
highItemId: 1060000,
},
region: 'GMS',
version: '217',
},
Hair: {
name: 'Twisty Pufftails Hair',
id: 47046,
typeInfo: {
overallCategory: 'Equip',
category: 'Character',
subCategory: 'Hair',
lowItemId: 30000,
highItemId: 49999,
},
region: 'GMS',
version: '217',
hue: 0,
},
},
visible: true,
position: {
x: 0,
y: 0,
},
fhSnap: true,
flipX: false,
name: '',
includeBackground: true,
id: 1693302570930,
hairDye: {
colorId: 1,
percentile: 0.49,
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment