Week 7 and 8, Adding physics and render the level in html5 games
back to topTwo weeks have been necessary to add all these functionalities to the html5 game.
- Add physics : done
- Add tilemap rendering : done
- Collision management : done
- Rendering with different viewport dimensions: done
Adding physics
Adding physics was the first step, I added acceleration to the player, including gravity which is a negative y acceleration. This follow the github tutorial which was really well explained. It was not so difficult to transform it to javascript as below :
First input for jumping, the loop checks if you are pressing the jump button, the more you press it the higher is your jump :
if(8===(input & 8)) {//1000 JUMP
jumpPressedTime++;
if (PlayerState.JUMPING!=state) {
jumpingPressed = true;
jumpPressedTime = 0;
state = PlayerState.JUMPING;
entity.dy = MAX_JUMP_SPEED;
entity.grounded = false;
} else {
if (jumpingPressed && jumpPressedTime >= LONG_JUMP_PRESS) {
jumpingPressed = false;
} else {
if (jumpingPressed) {
entity.dy = MAX_JUMP_SPEED;
}
}
}
}
Then we check the left/right actions to add positive or negative acceleration :
if(2===(input & 2)) {//0010 LEFT
facingLeft=true;
if (PlayerState.JUMPING!=state) {
state = PlayerState.WALKING;
}
accX = -entity.accel;
} else if(1===(input & 1)) {//0001 RIGHT
// right is pressed
facingLeft=false;
if (PlayerState.JUMPING!=state) {
state = PlayerState.WALKING;
}
accX = entity.accel;
} else {
if (PlayerState.JUMPING!=state) {
state = PlayerState.IDLE;
}
accX = 0;
}
After we manage inputs, we add gravity and change the velocity
// Setting initial vertical acceleration
accY = entity.gravity ;
// apply acceleration to change velocity
entity.dx += accX;
entity.dy += accY;
This is it, the gravity and ths user inputs have been added in the player update loop.
Adding tilemap rendering
Tilemap was not a big deal to render, the difficulty was to adapt it to different viewports.
The Tilemap was done with Tiled software, and exported in JSON file description. The file was then loaded with an XHtmlRequest
as we did for adding audio
for(y = 0 ; y < MAP.th ; y++) {
for(x = 0 ; x < MAP.tw ; x++) {
cell = tcell(x, y);
if (cell) {
// context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
context.drawImage( lvl_img, lvl_json.tilewidth*(cell-1) , 0, lvl_json.tilewidth, lvl_json.tileheight,
(x*TILE-cam.getPos().x)*ScreenRatio,(RefGameHeight+(y-MAP.th)*TILE-cam.getPos().y)*ScreenRatio,TILE*ScreenRatio , TILE*ScreenRatio);
}
}
}
As you can see, the cells are rendered in a postiion which depend of the ScreenRatio
value and also of the cam.getPos()
.
All rendering is based on a camera class which represent a square around the player.
The camera claas tracks the player position to update its position, the dimensions of the camera are also related to ScreenRatio
value...
Collision management
Collision has not yet been improved, yet it's basically a check of intersection between a boundary rectangle around the player, and a boundary rectangle around all other entities.
All entities have an associated rectangle :
collisionRect= {
x: MovableEntities[x].bounds.x,
y: MovableEntities[x].bounds.y,
width: MovableEntities[x].bounds.width,
height: MovableEntities[x].bounds.height
};
Then all rectangle checks if it intersects with others :
function intersect(a, b) {
return !(a.x > b.x+b.width ||
a.x+a.width < b.x ||
a.y+a.height < b.y ||
a.y > b.y+b.height);
}
It's a lot of calculation which can be reduced by not checking the intersections with the rectangles which obviously cannot collide with the player.
Rendering with different viewport dimensions
As JS stay a nightmare in terms of floating calculation, I decided to fix the ratio between the reference height and the user height.
for(ratio = 0.1;ratio<2;ratio+=0.1) {
if(gameheight>=RefGameHeight*ratio)
ScreenRatio=ratio.toFixed(2);
}
That helped a lot as all positions and dimensions for rendering are related to ScreenRatio
value.
Next week, I'm going to include all the game mechanics like death, gameover, and reset so ...