Skip to content

Commit

Permalink
Implement support for multiple player animations
Browse files Browse the repository at this point in the history
Merge pull request #82 from haroldo-ok/multiple-player-animations
This fixes #77 
This fixes #55
  • Loading branch information
haroldo-ok authored Jun 6, 2024
2 parents 2b2fdb8 + 84c1328 commit d56d752
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 40 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vcs-game-maker",
"version": "0.18.1",
"version": "0.19.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
Expand Down
1 change: 1 addition & 0 deletions src/blocks/icon.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export const SCORE_ICON = String.fromCodePoint(0x1F4AF);
export const BACKGROUND_ICON = String.fromCodePoint(0x1F304);
export const DICE_ICON = String.fromCodePoint(0x1F3B2);
export const SOUND_ICON = String.fromCodePoint(0x1F509);
export const ANIMATION_ICON = String.fromCodePoint(0x1F3AC);
3 changes: 2 additions & 1 deletion src/blocks/sprites.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import * as Blockly from 'blockly/core';

import {PLAYER_ICON, MISSILE_ICON, BALL_ICON, COLOR_ICON, HEIGHT_ICON} from './icon';
import {PLAYER_ICON, MISSILE_ICON, BALL_ICON, COLOR_ICON, HEIGHT_ICON, ANIMATION_ICON} from './icon';

const buildPlayerOptions = (name) => [
['\u2195 X', `${name}x`],
['\u2195 Y', `${name}y`],
[COLOR_ICON + ' Color', `${name}realcolor`],
[ANIMATION_ICON + ' Animation', `${name}animation`],
];

const buildMissileOptions = (name) => [
Expand Down
125 changes: 107 additions & 18 deletions src/components/PlayerEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,46 @@
<v-list-item-content>
<v-list-item-title>
<v-text-field label="Animation name" v-model="animation.name" />

<v-menu
top
v-if="state.animations.length > 1"
>
<template v-slot:activator="{ on, attrs }">
<v-btn
color="red"
title="Delete this animation"
fab
small
absolute
top
right
v-bind="attrs"
v-on="on"
>
<v-icon>mdi-delete</v-icon>
</v-btn>
</template>

<v-card>
<v-card-title>Delete this animation?</v-card-title>
<v-list>
<v-list-item @click="handleDeleteAnimation(animation)">
<v-list-item-icon>
<v-icon>mdi-check</v-icon>
</v-list-item-icon>
<v-list-item-title>Yes, delete</v-list-item-title>
</v-list-item>
<v-list-item>
<v-list-item-icon>
<v-icon>mdi-cancel</v-icon>
</v-list-item-icon>
<v-list-item-title>No, don't delete</v-list-item-title>
</v-list-item>
</v-list>
</v-card>
</v-menu>

</v-list-item-title>
<v-list>
<v-list-item
Expand All @@ -18,6 +58,7 @@
<div class="pixel-editor-container">
<v-menu
top
v-if="animation.frames.length > 1"
>
<template v-slot:activator="{ on, attrs }">
<v-btn
Expand Down Expand Up @@ -71,25 +112,39 @@
</div>
</v-list-item>
</v-list>
<v-btn
class="add-frame-buttom"
color="primary"
title="Add animation frame"
dark
absolute
right
rounded
@click="handleAddFrame(animation, frame)"
>
<v-icon>mdi-plus</v-icon>
<div>Add frame</div>
</v-btn>
</v-list-item-content>
</v-list-item>
</v-list>

<v-btn
color="secondary"
title="Add animation"
dark
absolute
right
rounded
@click="handleAddAnimation"
>
<v-icon>mdi-plus</v-icon>
<div>Add animation</div>
</v-btn>
</v-card-text>
</v-card>


<v-btn
class="add-frame-buttom"
color="primary"
title="Add animation frame"
dark
absolute
right
fab
@click="handleAddFrame"
>
<v-icon>mdi-plus</v-icon>
</v-btn>
</div>
</template>
<script>
Expand All @@ -104,11 +159,23 @@ export default defineComponent({
components: {PixelEditor},
props: ['storageFactory', 'title', 'fgColor'],
setup(props) {
const getMaxId = (elements) => {
return max(elements.map((o) => o.id))||0;
};
const playerStorage = props.storageFactory();
const state = computed({
get() {
try {
return processPlayerStorageDefaults(playerStorage);
const player = processPlayerStorageDefaults(playerStorage);
let nextId = getMaxId(player.animations);
for (const animation of player.animations) {
if (!animation.id) {
animation.id = nextId;
nextId++;
}
}
return player;
} catch (e) {
console.error('Error loading player 0 from local storage', e);
return DEFAULT_SPRITES;
Expand All @@ -125,9 +192,10 @@ export default defineComponent({
};
const instance = getCurrentInstance();
const handleAddFrame = () => {
const frames = state.value.animations[0].frames;
const maxId = max(frames.map((o) => o.id)) || 0;
const handleAddFrame = (animation, frame) => {
const frames = animation.frames;
const maxId = getMaxId(frames);
const newFrame = {
id: maxId+1,
duration: 10,
Expand All @@ -142,7 +210,7 @@ export default defineComponent({
'........'),
};
state.value.animations[0].frames.push(newFrame);
animation.frames.push(newFrame);
handleChildChange();
instance.proxy.$forceUpdate();
Expand All @@ -155,7 +223,28 @@ export default defineComponent({
instance.proxy.$forceUpdate();
};
return {state, handleChildChange, handleAddFrame, handleDeleteFrame, props};
const handleAddAnimation = () => {
const newAnimation = structuredClone(state.value.animations[state.value.animations.length-1]);
state.value.animations.push({
...newAnimation,
id: getMaxId(state.value.animations) + 1,
});
handleChildChange();
instance.proxy.$forceUpdate();
};
const handleDeleteAnimation = (animation) => {
state.value.animations = state.value.animations.filter(({id}) => id != animation.id);
console.info('Deleted ', animation);
handleChildChange();
instance.proxy.$forceUpdate();
};
return {state, handleChildChange,
handleAddFrame, handleDeleteFrame,
handleAddAnimation, handleDeleteAnimation,
props};
},
});
</script>
Expand Down
5 changes: 4 additions & 1 deletion src/generators/bbasic.bb.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ end
dim player1size = s
dim player0realcolor = r
dim player1realcolor = q

dim player0animation = p
dim player1animation = o

newbackground = 1

player0x = 75 : player0y = 75
Expand All @@ -58,6 +60,7 @@ end
player0size = $30
COLUBK = $C4
COLUPF = $0E
player0animation = 1

rem **************************************************************************
rem Main loop:
Expand Down
57 changes: 38 additions & 19 deletions src/generators/bbasic.js
Original file line number Diff line number Diff line change
Expand Up @@ -370,49 +370,68 @@ Blockly.BBasic.generateBackgrounds = function() {
};

Blockly.BBasic.generateAnimations = function() {
const processAnimation = (name, playerStorage) => {
let playerData = null;
try {
playerData = processPlayerStorageDefaults(playerStorage);
} catch (e) {
console.error(`Failed to load ${name} data`, e);
}

if (!playerData) {
return '';
}

const animation = playerData.animations[0];
const processAnimation = (name, animation, animationIndex) => {
if (!animation) {
return '';
}

const animationLabel = `${name}animation${animationIndex}`;
const totalDuration = sumBy(animation.frames, (frame) => frame.duration || 0);

let frameLimit = 0;
const stateMachine = animation.frames.map((frame, frameIndex) => {
frameLimit += frame.duration || 0;
const pixelSource = frame.pixels.slice().reverse().map((row) => ' %' + row.join(''));
const endLabel = `${name}frame${frameIndex}End`;
const endLabel = `${animationLabel}frame${frameIndex}End`;
const skipCondition = ` if ${name}frame > ${frameLimit} then goto ${endLabel}\n`;

return skipCondition +
` ${name}:\n` +
pixelSource.join('\n') +
'\nend\n' +
` goto ${name}animationEnd\n` +
` goto ${animationLabel}animationEnd\n` +
endLabel;
});

return ` rem Animation ${animation.name}:\n` +
return ` rem Animation ${animationIndex} ${animation.name} for ${name}:\n\n` +
` ${name}frame = ${name}frame + 1\n` +
` if ${name}frame = ${totalDuration} then ${name}frame = 0\n\n` +
stateMachine.join('\n\n') +
`\n\n${name}animationEnd`;
`\n\n${animationLabel}animationEnd`;
};

const processAnimations = (name, playerStorage) => {
let playerData = null;
try {
playerData = processPlayerStorageDefaults(playerStorage);
} catch (e) {
console.error(`Failed to load ${name} data`, e);
}

if (!playerData) {
return '';
}

const animationsLabel = `${name}animations`;
const animationsEndLabel = `${animationsLabel}End`;
const getAnimationStartLabel = (animationIndex) => `${name}animation${animationIndex}Start`;

return ` rem Animations for ${name}:\n` +
playerData.animations.map((animation, animationIndex) => {
if (!animationIndex) return '';
return ` if ${name}animation = ${animationIndex} then goto ${getAnimationStartLabel(animationIndex)}`;
}).join('\n') +
'\n\n' +
playerData.animations.map((animation, animationIndex) => {
return `${getAnimationStartLabel(animationIndex)}\n\n` +
processAnimation(name, animation, animationIndex) +
`\n goto ${animationsEndLabel}`;
}).join('\n\n') +
`\n\n${animationsEndLabel}`;
};

const player0Code = processAnimation('player0', usePlayer0Storage());
const player1Code = processAnimation('player1', usePlayer1Storage());
const player0Code = processAnimations('player0', usePlayer0Storage());
const player1Code = processAnimations('player1', usePlayer1Storage());
return player0Code + '\n\n\n' + player1Code;
};
import background from './bbasic/background';
Expand Down

0 comments on commit d56d752

Please sign in to comment.