Actors
Actors are how we add entities into the world that can perform actions, which means
that for each iteration of the game loop it is offered the chance to update itself.
This is different, of course, to the terrain which the world is made from. This
tutorial will cover adding an Actor into a world and enabling it to move around.
Movement
We could just add a single sprite to represent our actor, a robot of sorts, but we're
going to add a sprite for each of the directions that it can face, four, and we'll
collect these together using a 'DirectionalGraphicComponent'. This is a structure
which holds sprites for supported directions (the way the sprite is facing) and a
variable to hold the current direction.
async function createDroid(context, position) {
const graphicsDescriptor = {
spriteSheetName: "demos/graphics/png/levitate-droid",
spriteWidth: 58,
spriteHeight: 107,
columnDirections: [
WT.Direction.West,
WT.Direction.South,
WT.Direction.East,
WT.Direction.North,
],
numFrames: 1,
};
const graphics = await WT.createDirectionalGraphics(graphicsDescriptor, context);
const dimensions = WT.TwoByOneIsometric.getDimensions(
graphicsDescriptor.spriteWidth, graphicsDescriptor.spriteHeight,
);
const droid = new WT.Actor(
context, position, dimensions, graphics
);
// As the droid changes direction, an event will be triggered, so listen to it
// and update the graphical direction to match.
droid.addEventListener(
WT.EntityEvent.FaceDirection,
() => graphics.direction = droid.direction,
);
const moveRandomDirection = () => {
let dx = Math.round(Math.random() * 2) - 1;
let dy = 0;
let dz = 0;
// Move along either the x or y axis.
// Choose values between: -1, 0, 1
if (dx == 0) {
dy = Math.round(Math.random() * 2) - 1;
}
if (dx == 0 && dy == 0) {
dy = 1;
}
const moveVector = new WT.Vector3D(dx, dy, dz);
droid.direction = WT.Navigation.getDirectionFromVector(moveVector);
droid.action = new WT.MoveDirection(droid, moveVector, context.bounds);
};
// Choose another direction when it can't move anymore.
droid.addEventListener(WT.EntityEvent.EndMove, moveRandomDirection);
// Initialise movement.
moveRandomDirection();
return droid;
}
So the code above demostrates all that is needed to get some actors into a
world: setup some graphics, add some event listener logic and then it's core
decision logic. Now, the only extra step to take is to place the droid somewhere
in our world and create a camera to follow it.
window.onload = async (event) => {
const context = await WT.createWorld(worldDescriptor);
const canvas = document.getElementById(worldDescriptor.canvasName);
// Place the droid in the middle(ish) of the map.
const x = 4;
const y = 4;
// We add 1 to the height location, so the droid is slightly on top of the
// terrain.
const droidPosition =
context.grid.getSurfaceLocationAt(x, y).add(new WT.Vector3D(0, 0, 1));
const droid = await createDroid(context, droidPosition);
// The TrackerCamera will centre the view of whatever entity it is passed.
const camera = new WT.TrackerCamera(
context.scene,
canvas.width,
canvas.height,
droid,
);
const update = function() {
if (document.hasFocus()) {
context.update(camera);
}
window.requestAnimationFrame(update);
};
window.requestAnimationFrame(update);
};
The code is running in the canva below (if your screen is big enough).