Skip to content

Commit e3510cb

Browse files
authored
Implement player sprite editor
Merge pull request #49 from haroldo-ok/player-sprite Partial implementation of #41
2 parents 1673522 + 480c332 commit e3510cb

File tree

4 files changed

+104
-5
lines changed

4 files changed

+104
-5
lines changed
13.2 KB
Loading

assets/player sprite.png

2 KB
Loading

dom-util.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,37 @@
4242
const newInput = (type, attributes) => h('input', { type, ...attributes });
4343
const newCheckbox = attributes => newInput('checkbox', { ...attributes });
4444
const newButton = (text, attributes) => h('button', { ...attributes }, text);
45+
46+
const newImageFileInput = (attributes = {}) => {
47+
let img, fileInput, file;
48+
49+
const handleImageLoad = e => {
50+
const target = getEventTarget(e);
51+
attributes['@loadimage'] && attributes['@loadimage']({ event: e, target, img, file });
52+
}
53+
54+
const handleFileChange = () => {
55+
if (!fileInput.files.length) return;
56+
57+
file = fileInput.files[0];
58+
59+
const fr = new FileReader();
60+
fr.onload = function () {
61+
img.src = fr.result;
62+
}
63+
fr.readAsDataURL(file);
64+
}
65+
66+
img = h('img', { '@load': handleImageLoad });
67+
68+
fileInput = newInput('file', {
69+
accept: 'image/*',
70+
'@change': handleFileChange,
71+
...attributes
72+
});
73+
74+
return fileInput;
75+
}
4576

4677
const newDataInput = (object, attrName, type, attributes = {}) => {
4778
const handleChange = e => {
@@ -95,6 +126,7 @@
95126
newDiv, newLabel,
96127
newInput, newCheckbox, newButton,
97128
newDataInput, newDataCheckbox,
129+
newImageFileInput,
98130
populateModalDialog
99131
};
100132
})();

tileEditor.js

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ var tinyMapEditor = (function() {
1919
sprite = new Image(),
2020
tileSetForSms,
2121
tileSetName,
22+
playerSprite,
2223
mapName,
2324
mapId,
2425
tiles,
@@ -673,16 +674,75 @@ var tinyMapEditor = (function() {
673674

674675
populateModalDialog(tileCombinationsDialog, 'Tile Combinations', table);
675676
},
676-
677+
678+
loadPlayerSprite : function() {
679+
playerSprite = storage.get('playerSprite');
680+
console.log('playerSprite', playerSprite);
681+
},
682+
677683
showPlayerSpritePopup : function() {
678-
const { h, newTr, newTd, newTh, newInput, newDataCheckbox, populateModalDialog } = DomUtil;
684+
const { h, newTr, newTd, newTh, newDiv, newImageFileInput, newDataCheckbox, populateModalDialog } = DomUtil;
685+
686+
const SPRITE_DIRECTION_COUNT = 4;
687+
const SPRITE_WIDTH = 16;
688+
const SPRITE_HEIGHT = 32;
689+
690+
const spriteCanvas = h('canvas', { 'class': 'zoomable' });
691+
692+
const drawPlayerSpriteFromImage = (img) => {
693+
spriteCanvas.width = Math.floor(img.width / SPRITE_WIDTH) * SPRITE_WIDTH;
694+
spriteCanvas.height = SPRITE_DIRECTION_COUNT * SPRITE_HEIGHT;
695+
spriteCanvas.style.zoom = tileZoom;
696+
697+
const sourceSpriteHeight = Math.floor(img.height / SPRITE_DIRECTION_COUNT);
698+
699+
const ctx = spriteCanvas.getContext('2d');
700+
ctx.clearRect(0, 0, spriteCanvas.width, spriteCanvas.height);
701+
for (let directionNumber = 0, sy = 0, dy = SPRITE_HEIGHT - sourceSpriteHeight; directionNumber < SPRITE_DIRECTION_COUNT; directionNumber++, sy += sourceSpriteHeight, dy += SPRITE_HEIGHT) {
702+
ctx.drawImage(img,
703+
0, sy, img.width, sourceSpriteHeight,
704+
0, dy, img.width, sourceSpriteHeight);
705+
}
706+
}
707+
708+
const handlePlayerSpriteLoad = (fileName, img) => {
709+
drawPlayerSpriteFromImage(img);
710+
711+
const forMasterSystem = this.convertToUnoptimizedTileMap(spriteCanvas, { colors: 8 });
712+
playerSprite = {
713+
name: fileName,
714+
src: img.src,
715+
animations: {
716+
frameCount: Math.floor(spriteCanvas.width / SPRITE_WIDTH),
717+
directionCount: SPRITE_DIRECTION_COUNT,
718+
},
719+
forMasterSystem
720+
};
721+
722+
storage.put('playerSprite', playerSprite);
723+
};
724+
725+
const loadCurrentSprite = () => {
726+
if (!playerSprite || !playerSprite.src) return;
727+
728+
const img = new Image();
729+
img.onload = () => drawPlayerSpriteFromImage(img);
730+
img.src = playerSprite.src;
731+
}
732+
733+
const spriteInput = newImageFileInput({
734+
'@loadimage': ({ file, img }) => handlePlayerSpriteLoad(file.name, img)
735+
});
679736

680-
populateModalDialog(playerSpriteDialog, 'Player Sprite',
737+
populateModalDialog(playerSpriteDialog, 'Player Sprite',
738+
newDiv(spriteCanvas),
681739
h('label', {},
682740
'Player sprite to load:',
683-
newInput('file', { accept: 'image/*' })
741+
spriteInput
684742
)
685743
);
744+
745+
loadCurrentSprite();
686746
},
687747

688748
prepareProjectInfoStructure : function() {
@@ -742,7 +802,8 @@ var tinyMapEditor = (function() {
742802
attributes: tileAttrs,
743803
combinations: this.getTileCombinationsObject(),
744804
forMasterSystem: tileSetForSms
745-
}
805+
},
806+
playerSprite
746807
};
747808
},
748809

@@ -786,6 +847,11 @@ var tinyMapEditor = (function() {
786847
projectInfo = project.projectInfo;
787848
this.prepareProjectInfoStructure();
788849
this.saveProjectInfo();
850+
851+
if (project.playerSprite) {
852+
playerSprite = project.playerSprite;
853+
storage.put('playerSprite', playerSprite);
854+
}
789855

790856
this.destroy();
791857
this.init();
@@ -981,6 +1047,7 @@ var tinyMapEditor = (function() {
9811047
this.loadTileAttrs();
9821048
this.loadProjectInfo();
9831049
this.loadTileCombinations();
1050+
this.loadPlayerSprite();
9841051

9851052
let storedSrc = storedTileSet && storedTileSet.src || 'assets/default_tilemap.png';
9861053
if (storedSrc.startsWith('http:') || storedSrc.startsWith('https:')) {

0 commit comments

Comments
 (0)