Queue Directions Movement
Press and release the arrow keys (repeatedly) to enqueue directions to the movement queue. This example shows how to enqueue directions to the movement queue of a character. You will see the enqueued directions at the top of the screen. Use the settings section to experiment with some configurations.
Code
📖 How to execute examples locally
js
const game = new Phaser.Game(config(preload, create, update));
let queueText;
let strategy = 'STOP';
let waitTimeout = 1000;
let prevWaitTimeout = 1000;
function preload() {
this.load.image("tiles", "../../assets/cloud_tileset.png");
this.load.tilemapTiledJSON(
"cloud-city-map",
"../../assets/cloud_city.json"
);
this.load.spritesheet("player", "../../assets/characters.png", {
frameWidth: 52,
frameHeight: 72,
});
}
function create() {
const cloudCityTilemap = this.make.tilemap({ key: "cloud-city-map" });
cloudCityTilemap.addTilesetImage("Cloud City", "tiles");
for (let i = 0; i < cloudCityTilemap.layers.length; i++) {
const layer = cloudCityTilemap.createLayer(i, "Cloud City", 0, 0);
layer.scale = 3;
}
const playerSprite = this.add.sprite(0, 0, "player");
playerSprite.scale = 1.5;
this.cameras.main.startFollow(playerSprite, true);
this.cameras.main.setFollowOffset(
-playerSprite.width,
-playerSprite.height
);
const gridEngineConfig = {
characters: [
{
id: "player",
sprite: playerSprite,
walkingAnimationMapping: 6,
startPosition: { x: 3, y: 3 },
speed: 2,
},
],
};
queueText = this.add.text(20, 50, "", { fontSize: '45px' });
queueText.setScrollFactor(0, 0);
queueText.depth = 10000;
queueText.setColor("#000000");
this.gridEngine.create(cloudCityTilemap, gridEngineConfig);
strategyChanged();
settingsToConf();
}
function update() {
const cursors = this.input.keyboard.createCursorKeys();
if (Phaser.Input.Keyboard.JustDown(cursors.left)) {
addQueueMovement(this.gridEngine, 'left');
} else if (Phaser.Input.Keyboard.JustDown(cursors.right)) {
addQueueMovement(this.gridEngine, 'right');
} else if (Phaser.Input.Keyboard.JustDown(cursors.up)) {
addQueueMovement(this.gridEngine, 'up');
} else if (Phaser.Input.Keyboard.JustDown(cursors.down)) {
addQueueMovement(this.gridEngine, 'down');
}
let queue = [];
if (this.gridEngine.isMoving('player')) {
queue = [this.gridEngine.getFacingDirection('player')];
}
const enqueuedMovements = this.gridEngine.getEnqueuedMovements('player')
.map(e => e.command);
queue = [...queue, ...enqueuedMovements];
queueText.setText(queue.map(dirToIcon).join(' '));
}
function dirToIcon(dir) {
switch (dir) {
case 'left':
return '⬅️';
case 'right':
return '️➡️';
case 'up':
return '⬆️';
case 'down':
return '⬇️';
}
return '?';
}
function addQueueMovement(gridEngine, direction) {
gridEngine.addQueueMovements('player', [direction], {
pathBlockedStrategy: strategy,
pathBlockedWaitTimeoutMs: waitTimeout,
});
}
function applySettings() {
strategy = document.getElementById("path-blocked-strategy").value;
waitTimeout = Number(document.getElementById("wait-timeout").value);
settingsToConf();
}
function strategyChanged() {
strategy = document.getElementById("path-blocked-strategy").value;
const checkboxEl = document.getElementById("wait-timeout-infinite");
const waitTimeoutEl = document.getElementById("wait-timeout");
const waitTimeoutGroup = document.getElementsByClassName(
"wait-timeout-group"
)[0];
const waitTimeoutGroupLabel = document.querySelector(
"label[for='wait-timeout']"
);
if (strategy != 'WAIT') {
checkboxEl.disabled = true;
waitTimeoutEl.disabled = true;
waitTimeoutGroup.classList.add("disabled");
waitTimeoutGroupLabel.classList.add("disabled");
} else {
checkboxEl.disabled = false;
waitTimeoutEl.disabled = false;
waitTimeoutGroup.classList.remove("disabled");
waitTimeoutGroupLabel.classList.remove("disabled");
}
}
function infiniteCheckboxChanged(event) {
const checkboxVal = document.getElementById(
"wait-timeout-infinite"
).checked;
const waitTimeoutEl = document.getElementById("wait-timeout");
waitTimeoutEl.disabled = checkboxVal;
if (checkboxVal) {
prevWaitTimeout = Number(waitTimeoutEl.value);
waitTimeoutEl.value = -1;
} else {
waitTimeoutEl.value = prevWaitTimeout;
}
}
function settingsToConf() {
let text = '';
if (strategy == 'WAIT') {
text = JSON.stringify({
pathBlockedStrategy: strategy,
pathBlockedWaitTimeoutMs: waitTimeout,
}, null, 2);
} else {
text = JSON.stringify({
pathBlockedStrategy: strategy,
}, null, 2);
}
document.getElementById(
"json-config"
).innerHTML = `<pre>${text}</pre>`;
}
html
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="../styles.css" />
<script src="../../js/phaser-3.80.1.min.js"></script>
<script src="../../js/grid-engine-2.44.3.min.js"></script>
<script src="../../js/examplePhaserConfig.js"></script>
<script src="code.js"></script>
<meta name="color-scheme" content="dark light" />
</head>
<body>
<div class="settings">
<h2>Settings:</h2>
<label for="path-blocked-strategy">pathBlockedStrategy:</label>
<select
name="path-blocked-strategy"
id="path-blocked-strategy"
onchange="strategyChanged()"
>
<option value="STOP">STOP</option>
<option value="SKIP">SKIP</option>
<option value="WAIT">WAIT</option>
</select>
<label for="wait-timeout">pathBlockedWaitTimeoutMs:</label>
<div class="wait-timeout-group">
<input
type="number"
id="wait-timeout"
name="wait-timeout"
value="1000"
/>
<input
type="checkbox"
id="wait-timeout-infinite"
name="wait-timeout-infinite"
value="true"
onchange="infiniteCheckboxChanged(event)"
/>
<label for="wait-timeout-infinite">Infinite</label>
</div>
<button class="apply" onclick="applySettings()">Apply settings</button>
<h3>QueueMovementConfig:</h3>
<div id="json-config"></div>
</div>
<div id="game" scrolling="no"></div>
</body>
</html>
js
function config(preload, create, update) {
return {
title: "GridEngineExample",
render: {
antialias: false,
},
type: Phaser.AUTO,
plugins: {
scene: [
{
key: "gridEngine",
plugin: GridEngine,
mapping: "gridEngine",
},
],
},
scale: {
width: 700,
height: 528,
},
scene: {
preload: preload,
create: create,
update: update,
},
parent: "game",
backgroundColor: "#48C4F8",
input: {
mouse: {
preventDefaultWheel: false
},
touch: {
capture: false
}
}
};
}
css
body {
margin: 0;
padding: 0;
background: #1e1e20;
font-family: Inter,-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
color: #cacaca;
}
.settings {
margin-top: 20px;
display: flex;
flex-direction: column;
/* border: 1px solid white; */
background: #282828;
margin-bottom: 20px;
width: 640px;
padding: 0 30px;
}
label {
font-weight: bold;
margin-top: 30px;
margin-bottom: 10px;
}
select {
width: 100px;
}
input {
width: 100px;
}
button {
width: 120px;
margin-top: 30px;
margin-bottom: 20px;
}
.wait-timeout-group {
display: flex;
align-items: center;
justify-content: flex-start;
}
.wait-timeout-group input {
width: auto;
margin-right: 10px;
}
.wait-timeout-group label {
margin:0;
}
#json-config {
margin-bottom: 10px;
}
#json-config pre {
font-family: "Consolas", monospace;
}
.disabled {
display: none;
}