-
Notifications
You must be signed in to change notification settings - Fork 16
Intermediary Movement
In the basic tutorial, we created the basic movement logic. That simple logic just considers one key to move the player. In this step we will improve that logic to make the movement function to consider multiple keys to move the player simultaneously. This step is easy and simple to understand.
The logic for this is a little different then the other movement logic we use. Here, we will use two events: keyup
and keydown
. Both events will control the key activation. When the user press some key (keydown
event), this key will be marked as actived and the movement function will move the player. When this same key stops to be pressed (keyup
event), this key will be marked as not activated so, the movement function will not move the player. We will work with boolean
controlling in this step for the keys.
The first thing to do is add the boolean property to controll the activation of the key in the key
attribute. We will made this like the code below:
// Data
let data = {
// ...
key: {
up: {
code: "KeyW",
active: false
},
down: {
code: "KeyS",
active: false
},
left: {
code: "KeyA",
active: false
},
right: {
code: "KeyD",
active: false
}
}
// ...
}
After define the attributes, we will change the logic of our keydown
event function. This event will just active the pressed key. Note that we will change the if
instruction to not consider else
.
/**
* Key down check
*/
document.addEventListener('keydown', (event) => {
let keyCode = event.code;
if(keyCode === data.key.up.code) {
data.key.up.active = true;
}
if(keyCode === data.key.down.code) {
data.key.down.active = true;
}
if(keyCode === data.key.left.code) {
data.key.left.active = true;
}
if(keyCode === data.key.right.code) {
data.key.right.active = true;
}
});
Now, we will do the same for the kayup
event, but instead of active the key, this step will inactive the released key.
/**
* Key up check
*/
document.addEventListener('keyup', (event) => {
let keyCode = event.code;
if(keyCode === data.key.up.code) {
data.key.up.active = false;
}
if(keyCode === data.key.down.code) {
data.key.down.active = false;
}
if(keyCode === data.key.left.code) {
data.key.left.active = false;
}
if(keyCode === data.key.right.code) {
data.key.right.active = false;
}
});
So now, we have to create the movement logic again. For this, we will create a new function called movePlayer()
. This function will check the activated keys and make the player coordinates changes. In this function we will not use the else
keyword because the movement needs to be simultaneous.
/**
* Movement
*/
function movePlayer() {
if(data.key.up.active) {
let playerCos = Math.cos(degreeToRadians(data.player.angle)) * data.player.speed.movement;
let playerSin = Math.sin(degreeToRadians(data.player.angle)) * data.player.speed.movement;
let newX = data.player.x + playerCos;
let newY = data.player.y + playerSin;
// Collision test
if(data.map[Math.floor(newY)][Math.floor(newX)] == 0) {
data.player.x = newX;
data.player.y = newY;
}
}
if(data.key.down.active) {
let playerCos = Math.cos(degreeToRadians(data.player.angle)) * data.player.speed.movement;
let playerSin = Math.sin(degreeToRadians(data.player.angle)) * data.player.speed.movement;
let newX = data.player.x - playerCos;
let newY = data.player.y - playerSin;
// Collision test
if(data.map[Math.floor(newY)][Math.floor(newX)] == 0) {
data.player.x = newX;
data.player.y = newY;
}
}
if(data.key.left.active) {
data.player.angle -= data.player.speed.rotation;
}
if(data.key.right.active) {
data.player.angle += data.player.speed.rotation;
}
}
A new correction we will do in this function is validate the player angle interval. The angle in degrees has a fixed interval from 1 to 360. This needs to be checked in the left or right movements. When the angle overflows tha angle interval it needs to be corrected. To keep the value inside the interval we will use the module (%) operator.
// ...
if(data.key.left.active) {
data.player.angle -= data.player.speed.rotation;
data.player.angle %= 360;
}
if(data.key.right.active) {
data.player.angle += data.player.speed.rotation;
data.player.angle %= 360;
}
// ...
This function will be called in the main loop of our application before the RayCasting render function. This will update the player coordinates for every loop cicle.
/**
* Main loop
*/
function main() {
setInterval(function() {
clearProjection();
movePlayer();
rayCasting();
}, data.render.delay);
}
If we test the application now, we will discover that the player will be moved so fast! It is because for every loop interation we are processing the player movement. It is not just in the event time. To change it, we will just change the player speed.
// Data
let data = {
// ...
player: {
// ...
speed: {
movement: 0.05,
rotation: 3.0
}
}
// ...
}
Now, we can test the application. We will check that we can move the player so better.
This is the full code of this tutorial step:
/**
* Key down check
*/
document.addEventListener('keydown', (event) => {
let keyCode = event.code;
if(keyCode === data.key.up.code) {
data.key.up.active = true;
}
if(keyCode === data.key.down.code) {
data.key.down.active = true;
}
if(keyCode === data.key.left.code) {
data.key.left.active = true;
}
if(keyCode === data.key.right.code) {
data.key.right.active = true;
}
});
/**
* Key up check
*/
document.addEventListener('keyup', (event) => {
let keyCode = event.code;
if(keyCode === data.key.up.code) {
data.key.up.active = false;
}
if(keyCode === data.key.down.code) {
data.key.down.active = false;
}
if(keyCode === data.key.left.code) {
data.key.left.active = false;
}
if(keyCode === data.key.right.code) {
data.key.right.active = false;
}
});
/**
* Movement
*/
function movePlayer() {
if(data.key.up.active) {
let playerCos = Math.cos(degreeToRadians(data.player.angle)) * data.player.speed.movement;
let playerSin = Math.sin(degreeToRadians(data.player.angle)) * data.player.speed.movement;
let newX = data.player.x + playerCos;
let newY = data.player.y + playerSin;
// Collision test
if(data.map[Math.floor(newY)][Math.floor(newX)] == 0) {
data.player.x = newX;
data.player.y = newY;
}
}
if(data.key.down.active) {
let playerCos = Math.cos(degreeToRadians(data.player.angle)) * data.player.speed.movement;
let playerSin = Math.sin(degreeToRadians(data.player.angle)) * data.player.speed.movement;
let newX = data.player.x - playerCos;
let newY = data.player.y - playerSin;
// Collision test
if(data.map[Math.floor(newY)][Math.floor(newX)] == 0) {
data.player.x = newX;
data.player.y = newY;
}
}
if(data.key.left.active) {
data.player.angle -= data.player.speed.rotation;
data.player.angle %= 360;
}
if(data.key.right.active) {
data.player.angle += data.player.speed.rotation;
data.player.angle %= 360;
}
}
/**
* Main loop
*/
function main() {
setInterval(function() {
clearProjection();
movePlayer();
rayCasting();
}, data.render.delay);
}
Let's go to the next tutorial!
- Next: Intermediary Collision Detection
- Previous: Textures
Copyright © 2018 Vinícius Reif Biavatti
- Home
- RayTrancing
- Examples
- Basic Tutorial
- Intermediary Tutorial
- Advanced Tutorial