Skip to content

Instantly share code, notes, and snippets.

@john-diaz
Last active September 9, 2021 17:45
Show Gist options
  • Save john-diaz/7417d3edec69c903ab61dae09f760edc to your computer and use it in GitHub Desktop.
Save john-diaz/7417d3edec69c903ab61dae09f760edc to your computer and use it in GitHub Desktop.
/*
Game loop for my game "GrandQuest"
Written by John S. Diaz 2019
*/
update() {
const scene: Scene = game.scene.scenes[0];
if (!global.gameInitialized) {
return;
}
const networkGameState = store.state.combatGame.gameState;
/*
GAME LOGIC
*/
global.gameState.queuedEvents = [...networkGameState.queuedEvents];
/* Level updating / rendering */
// if we are on a different level than on the network
if (global.gameState.level !== networkGameState.level && networkGameState.level !== -1) {
// update the level locally
global.gameState.level = networkGameState.level;
// despawn all the characters
_.forEach({...global.gameState.players, ...global.gameState.enemies}, (c) => {
actions.despawnCharacter(c.id);
});
// load the scene
actions.startLevel(global.gameState.level);
}
// generate user placing line
if (networkGameState.maxPlayers !== Object.keys(global.playerPlacingLine).length) {
// reset players on local state
global.gameState.players = {};
// generate empty placing line withing range
global.playerPlacingLine = _.reduce(_.range(1, networkGameState.maxPlayers + 1), (memo: object, index: number) => ({
...memo,
[String(index)]: {
get character() {
return null;
},
nextIndex: index >= networkGameState.maxPlayers ? 1 : index + 1,
index,
prevIndex: index === 1 ? networkGameState.maxPlayers : index - 1,
},
}), {});
}
// generate enemy placing line
if (Object.keys(networkGameState.enemies).length !== Object.keys(global.enemyPlacingLine).length) {
// despawn any players that could be on it
global.gameState.enemies = {};
// generate empty placing line withing range
global.enemyPlacingLine = _.reduce(_.range(1, Object.keys(networkGameState.enemies).length + 1), (memo: object, index: number) => ({
...memo,
[String(index)]: {
get character() {
return null;
},
nextIndex: index >= Object.keys(networkGameState.enemies).length ? 1 : index + 1,
index,
prevIndex: index === 1 ? Object.keys(networkGameState.enemies).length : index - 1,
},
}), {});
}
// Despawn Characters
const charactersOnLocal = {...global.gameState.players, ...global.gameState.enemies};
_.forEach(charactersOnLocal, ({ id }) => {
const characterOnNetwork = networkGameState.enemies.hasOwnProperty(id) || networkGameState.players.hasOwnProperty(id);
if (!characterOnNetwork) {
actions.despawnCharacter(id);
}
});
// Update Characters States
_.forEach({...global.gameState.players, ...global.gameState.enemies}, (characterOnLocal) => {
const id: string = String(characterOnLocal.id);
const characterOnNetwork = characterOnLocal.enemy
? networkGameState.enemies[id]
: networkGameState.players[id];
if (characterOnLocal.enemy) {
global.gameState.enemies = {
...global.gameState.enemies,
[id]: {...characterOnLocal, ...characterOnNetwork},
};
} else {
global.gameState.players = {
...global.gameState.players,
[id]: {...characterOnLocal, ...characterOnNetwork},
};
}
});
// IF the network is at a different turn
if (global.gameState.turn !== networkGameState.turn && !global.isAnimating) {
// IF we have NOT just joined the match
const appliedEvents = networkGameState.turnEvents[global.gameState.turn];
if (appliedEvents && global.gameState.turn !== -1) {
if (!appliedEvents.length) {
store.commit('SET_COMBAT_GAME_SELECTION_MODE', 'ACTION');
} else {
actions.animateEvents(appliedEvents);
}
}
global.gameState.turn = networkGameState.turn;
}
// play state updating
if (!global.isAnimating && networkGameState.playState !== global.gameState.playState) {
global.gameState.levelRecord = networkGameState.levelRecord;
global.gameState.playState = networkGameState.playState;
return;
}
/*
SCENE RENDERING
*/
// Cloud animation
if (global._gameClouds) {
global._gameClouds.tilePositionX += 0.072;
}
// Create & Update Characters Graphics
_.forEach({...networkGameState.players, ...networkGameState.enemies}, (characterOnNetwork) => {
const id: string = String(characterOnNetwork.id);
let characterOnLocal = characterOnNetwork.enemy
? global.gameState.enemies[id]
: global.gameState.players[id];
// user does not exist locally, spawn them if game is NOT animating
if (!characterOnLocal && !global.isAnimating) {
characterOnLocal = actions.spawnCharacter(characterOnNetwork);
} else if (!characterOnLocal) {
return;
}
// if game is NOT animating, update their position
if (!global.isAnimating) {
const coordinates = actions.coordinatesForEntity(characterOnLocal);
characterOnLocal.sprite.x = coordinates.x;
characterOnLocal.sprite.y = coordinates.y;
}
// name tag
if (!characterOnLocal._nameTag) {
characterOnLocal._nameTag = scene.add.text(
0, 0,
characterOnLocal.username,
{
fontSize: '17px',
fill: '#fff',
backgroundColor: '#0008',
align: 'center',
},
)
.setOrigin(0.5, 0)
.setDepth(characterOnLocal.sprite.depth);
}
characterOnLocal._nameTag.x = characterOnLocal.sprite.x;
characterOnLocal._nameTag.y = characterOnLocal.sprite.y - (characterOnLocal.sprite.height * 1.75);
characterOnLocal._nameTag.setDepth(characterOnLocal.sprite.depth);
// health bar background
if (!characterOnLocal._healthBarBackground) {
characterOnLocal._healthBarBackground = scene.add.rectangle(0, 0, 0, 0, 0xBEBEBE)
.setDepth(characterOnLocal.sprite.depth)
.setOrigin(0, 0);
} else if (characterOnLocal._healthBarBackground.visible) {
characterOnLocal._healthBarBackground.setSize(characterOnLocal._nameTag.width, 9);
characterOnLocal._healthBarBackground.x = characterOnLocal._nameTag.x - (characterOnLocal._nameTag.width / 2);
characterOnLocal._healthBarBackground.y = characterOnLocal._nameTag.y + characterOnLocal._nameTag.height;
}
// health bar
if (!characterOnLocal._healthBar) {
const width = characterOnLocal.entity.health / characterOnLocal.entity.maxHealth * (characterOnLocal._nameTag.displayWidth);
characterOnLocal._healthBar = scene
.add.rectangle(0, 0, width, 0, 0x56F33E)
.setOrigin(0, 0);
} else if (characterOnLocal._healthBar.visible) {
if (!global.isAnimating) {
const width = characterOnLocal.entity.health / characterOnLocal.entity.maxHealth * (characterOnLocal._nameTag.displayWidth);
characterOnLocal._healthBar.setSize(width, 10);
}
characterOnLocal._healthBar.x = characterOnLocal._nameTag.x - (characterOnLocal._nameTag.width / 2);
characterOnLocal._healthBar.y = characterOnLocal._nameTag.y + characterOnLocal._nameTag.height;
characterOnLocal._healthBar.setDepth(characterOnLocal.sprite.depth + 1);
}
// health text
if (!characterOnLocal._healthText) {
characterOnLocal._healthText = scene.add.text(
0, 0, '',
{
fontSize: '8px',
fill: '#fff',
backgroundColor: '#0000',
align: 'center',
baselineY: 0.5,
},
)
.setOrigin(0.5, 0.5);
} else if (characterOnLocal._healthText.visible) {
const currentDisplayedHealth = characterOnLocal.entity.maxHealth * (characterOnLocal._healthBar.width / characterOnLocal._nameTag.displayWidth);
characterOnLocal._healthText.text = `${Math.round(currentDisplayedHealth / 10) * 10}/${characterOnLocal.entity.maxHealth}`;
characterOnLocal._healthText.x = characterOnLocal._healthBarBackground.getCenter().x;
characterOnLocal._healthText.y = characterOnLocal._healthBarBackground.getCenter().y + 2;
characterOnLocal._healthText.setDepth(characterOnLocal.sprite.depth + 2);
}
// grave marker
if (!characterOnLocal._healthBar.width) {
characterOnLocal._healthBar.visible = false;
characterOnLocal._healthBarBackground.visible = false;
characterOnLocal._healthText.visible = false;
characterOnLocal.sprite.play('grave-marker');
if (characterOnLocal.enemy) {
characterOnLocal.sprite.scaleX = -Math.abs(characterOnLocal.sprite.scaleX);
}
}
});
// target selection hand
if (global.targetHand) {
const currentPlayer = store.state.user.id ? global.gameState.players[store.state.user.id] : null;
// remove the target hand if game is animating or the user already selected the target & action
if (currentPlayer && currentPlayer.selectionStatus === 1 || global.isAnimating || store.state.combatGame.selectionMode !== 'TARGET') {
actions.removeTargetHand();
} else {
// update selection hand coordinates
const placingLine = global.currentTargetSide === 0
? global.playerPlacingLine
: global.enemyPlacingLine;
const character = placingLine[global.currentTargetIndex].character;
if (character && character.sprite.depth === 15) {
global.targetHand.x = character.sprite.getCenter().x;
global.targetHand.y = character._nameTag.y - 15;
global.targetHand.setDepth(character.sprite.depth);
} else {
actions.removeTargetHand();
}
}
} else if (store.state.combatGame.selectionMode === 'TARGET' && !global.isAnimating) {
actions.addTargetHand();
}
// update fadeScreen size
if (global._fadeScreen) {
const currentPlayer = _.find(networkGameState.players, p => p.id === store.state.user.id);
if (global.isAnimating || (currentPlayer && currentPlayer.entity.health === 0)) {
global.highlightCharacters(false);
global._fadeScreen.destroy();
global._fadeScreen = null;
} else {
global._fadeScreen
.setSize(scene.game.canvas.offsetWidth, scene.game.canvas.offsetHeight);
}
}
},
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment