Matter.js for collision detection - javascript

I'm relatively new to asking questions here, so please bear with me. I am trying to create a top down driving game with Matter.js as the primary physics engine. I would like the red car to collide with the green square. However, I am still stuck on knowing how to implement Matter.js onto my game. Any form of response will be greatly appreciated!
<html>
<canvas width=1000 height=500 style='border:1px solid black'>
</canvas>
<body onload='start()'>
<script src='matter.js'>
</script>
<script>
function start() {
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
var x = 100;
var y = 100;
var s = 0;
var rot = 0;
var rightPressed = false;
var leftPressed = false;
var upPressed = false;
var downPressed = false;
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
function keyDownHandler(e) {
if (e.keyCode == 39) {
rightPressed = true;
} else if (e.keyCode == 37) {
leftPressed = true;
} else if (e.keyCode == 38) {
upPressed = true;
} else if (e.keyCode == 40) {
downPressed = true;
}
}
function keyUpHandler(e) {
if (e.keyCode == 39) {
rightPressed = false;
} else if (e.keyCode == 37) {
leftPressed = false;
} else if (e.keyCode == 38) {
upPressed = false;
} else if (e.keyCode == 40) {
downPressed = false;
}
}
function car() {
ctx.fillStyle = 'red';
ctx.fillRect(-20, -20, 40, 40);
ctx.beginPath();
ctx.moveTo(-20, -19);
ctx.lineTo(-20, -20);
ctx.lineTo(0, -30);
ctx.lineTo(20, -20);
ctx.lineTo(20, -19);
ctx.fill();
ctx.closePath();
ctx.fillStyle = 'black';
ctx.fillRect(-25, -20, 5, 10);
ctx.fillRect(-25, 10, 5, 10);
ctx.fillRect(20, -20, 5, 10);
ctx.fillRect(20, 10, 5, 10);
ctx.fillRect(-15, -5, 30, 20);
}
function block() {
ctx.fillStyle = 'green';
ctx.fillRect(200, 100, 50, 50);
}
function draw() {
requestAnimationFrame(draw);
ctx.clearRect(0, 0, 1000, 500);
if (s > 15) {
s = 15;
}
if (s < -15) {
s = -15;
}
if (upPressed) {
s++;
}
if (downPressed) {
s *= .9;
}
if (!upPressed) {
s *= .99;
}
if (leftPressed) {
rot -= s / 3;
}
if (rightPressed) {
rot += s / 3;
}
ctx.fillText(upPressed, 10, 10);
x += s * Math.cos(rot * Math.PI / 180);
y += s * Math.sin(rot * Math.PI / 180);
ctx.save();
ctx.translate(x, y);
ctx.rotate((rot + 90) * Math.PI / 180);
car();
ctx.restore();
block();
}
draw();
}
</script>
</body>
</html>

You would have to redo most of your code, but the movement code CAN be moved over fairly easily.
First you need to make a new engine and run it:
//Create engine - All the game stuff
var Engine = Matter.Engine,
Render = Matter.Render,
Runner = Matter.Runner,
Composites = Matter.Composites,
Common = Matter.Common,
World = Matter.World,
Bodies = Matter.Bodies,
Body = Matter.Body;
// create an engine
var engine = Engine.create(),
world = engine.world;
// create a renderer
var render = Render.create({
canvas: document.getElementById("canv"),
engine: engine,
options: {
width: 500,
height: 500,
wireframes: false,
background: '#6DDA4A'
}
});
engine.world.gravity.y = 0;
Render.run(render);
// create runner
var runner = Runner.create();
Runner.run(runner, engine);
Next, you should make and add a new car object and the block into the world. You can edit these values to whatever you need them to be.
Note: rot is not an actual parameter you need, I'm just using it to set the rotation of the car later.
var car = Bodies.rectangle(100, 100, 50, 80, {
friction: 1,
frictionAir: 0.1,
rot: 0,
restitution: 0,//Makes it so the car won't bounce off of objects
render: {
fillStyle: "#FF0000",
/*sprite: {
//You can use this to apply a background image to the car
texture: "Path/To/Image.png",
xScale: number,
yScale: number
}/**/
}
});
var block = Bodies.rectangle(350, 100, 100, 400, {
isStatic: true,//Makes block unmovable
friction: 1,
frictionAir: 0.1,
rot: 0,
restitution: 0,
render: {
fillStyle: "#0000FF",
/*sprite: {
texture: "Path/To/Image.png",
xScale: number,
yScale: number
}/**/
}
});
World.add(world, [car, block]);
For updating the car, you can either use body.setPosition or body.applyForce. Since it's a car, I would use body.applyForce so that the car keeps rolling after you've stopped pressing a button. Rotation can also be done with body.setAngle or body.rotate. This time, I'm going to use body.setAngle so the turning feels better.
function updateCar() {
//Declare variables for velocity
var speed = 5;
var carRot = car.rot*180/Math.PI;
var velY = speed * Math.cos(carRot * Math.PI / 180);
var velX = speed * Math.sin(carRot * Math.PI / 180)*-1;
var pushRot = 0;
//Update variables
if (upPressed==false&&downPressed==false) {
velY = 0;
velX = 0;
}
else {
//alert(carX+", "+carY);
}
if (downPressed == true) {
velY *= -1;
velX *= -1;
}
if (leftPressed) {
pushRot = -0.1;
}
if (rightPressed) {
pushRot = 0.1;
}
car.rot += pushRot;
//Set position of car
carX += velX;
carY += velY;
Body.applyForce(car, {x:carX,y:carY}, {x:velX/200,y:velY/200});
Body.setAngle(car, car.rot);
requestAnimationFrame(updateCar);
}
window.requestAnimationFrame(updateCar);
Check out a demo here

Related

I am having trouble with my collision code

I am using CodeHs which uses very basic JavaScript. No HTML or Design modes yet and it's only JS Script. My teacher game me this collision code:
function checkCircleCollision (circle1, circle2) {
var dx = circle1.x - circle2.x;
var dy = circle1.y - circle2.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < circle1.radius + circle2.radius) {
return true;
}
return false;
}
Example of how to use collision functions:
The above functions will give back a value of either true or false, so you can use them with an If Statement.
Immediately after moving objects, you can check if two objects are touching:
if (checkCollision(player,enemy))
player.setColor(Color.red);
else
player.setColor(Color.black);.
But when I put it in my program it is saying that x and y that is being used for dx and dy is not defined. Without this, my game can't run. Here is all of my code:
//Variables
var brown = new Color(139 ,69 ,19);
var START_RADIUS = 1;
var DELAY = 100;
var INCREMENT = 1;
var CHANGE_COLORS_AT = 10;
var MAX_RADIUS = 100;
var counter = 0;
var player;
var finishLine;
var RADIUS = 20;
var obstacle;
var obstacle2;
var obstacle3;
var dx = 0;
var dy = 4;
var dx2 = 0;
var dy2 = -4;
var dx3 = 0;
var dy3 = 7;
var x;
var y;
//Start Function
function start(){
var wannaStart = readLine("Do you wanna start playing Impossible Dodgeball? ")
if(wannaStart == "Yes" || wannaStart == "yes" || wannaStart == "Absolutely!"){
startGame();
println("Get to the finish line without getting hit. Enjoy! ");
} else {
println("Enjoy this blank canvas then!");
}
}
//Starts the game if the user responded to correctly to the if statement above
function startGame(){
// checkForCollisions();
drawBackground();
player = drawCircle(20, Color.red, 25, getHeight()/2);
keyDownMethod(move);
drawObstacles();
}
//Draws the background
function drawBackground(){
drawRectangle(getWidth(), 250, 0, 0, Color.blue);
drawSun();
drawRectangle(getWidth(), getHeight()/2, 0, 300, brown);
drawRectangle(getWidth(), 50, 0, 250, Color.green);
finishLine = new Rectangle(10, getHeight());
finishLine.setPosition(350, 0);
finishLine.setColor(Color.white);
add(finishLine);
drawRectangle(10, getHeight(), 360, 0, Color.black);
drawRectangle(10, getHeight(), 370, 0, Color.white);
drawRectangle(10, getHeight(), 380, 0, Color.black);
drawRectangle(10, getHeight(), 390, 0, Color.white);
}
//Draws the rising sun in the background
function drawSun(){
circle = new Circle(START_RADIUS);
circle.setPosition(getWidth()/2, getHeight()/2+10);
add(circle);
setTimer(draw, 50);
}
//Draws all the moving obstacles
function drawObstacles(){
drawObstacle1();
drawObstacle2();
drawObstacle3();
}
//I was unable to get the collision code for the player and the obstacles to work :(
/*function checkForCollisions(){
if(checkCircleCollision(player, obstacle) == true){
println("You lose");
}
}
function checkCircleCollision (circle1, circle2) {
var dx4 = circle1.x - circle2.x;
var dy4 = circle1.y - circle2.y;
var distance = Math.sqrt(dx4 * dx4 + dy4 * dy4);
if (distance < circle1.radius + circle2.radius) {
return true;
}
return false;
}*/
//Draws the first obstacle
function drawObstacle1(){
obstacle = new Circle(RADIUS);
obstacle.setPosition(100, 100);
obstacle.setColor(Randomizer.nextColor());
add(obstacle);
setTimer(draw2, 20);
}
//Draws the second obstacle
function drawObstacle2(){
obstacle2 = new Circle(30);
obstacle2.setPosition(175, 300);
obstacle2.setColor(Randomizer.nextColor());
add(obstacle2);
setTimer(draw3, 20);
}
//Draws the third obstacle
function drawObstacle3(){
obstacle3 = new Circle(10);
obstacle3.setPosition(240, 50);
obstacle3.setColor(Randomizer.nextColor());
add(obstacle3);
setTimer(draw4, 20);
}
//Moves the obstacle
function draw2(){
checkForWalls();
obstacle.move(dx, dy);
}
//Same as above but for obstacle 2
function draw3(){
checkForWalls2();
obstacle2.move(dx2, dy2);
}
//Same as above but for obstacle 3
function draw4(){
checkForWalls3();
obstacle3.move(dx3, dy3);
}
//Bounces obstacle 1 off of the walls
function checkForWalls(){
//bottom wall
if(obstacle.getY() + obstacle.getRadius() > getHeight()){
dy = -dy;
}
//top wall
if(obstacle.getY() - obstacle.getRadius() < 0){
dy = -dy;
}
}
//Bounces obstacle 2 off of the walls
function checkForWalls2(){
//bottom wall
if(obstacle2.getY() + obstacle2.getRadius() > getHeight()){
dy2 = -dy2;
}
//top wall
if(obstacle2.getY() - obstacle2.getRadius() < 0){
dy2 = -dy2;
}
}
//Bounces obstacle 3 off of the walls
function checkForWalls3(){
//bottom wall
if(obstacle3.getY() + obstacle3.getRadius() > getHeight()){
dy3 = -dy3;
}
//top wall
if(obstacle3.getY() - obstacle3.getRadius() < 0){
dy3 = -dy3;
}
}
//Provided by CodeHS
function drawRectangle(width, height, x, y, Color){
var rect = new Rectangle(width, height);
rect.setPosition(x, y);
rect.setColor(Color);
add(rect);
}
//Provided by CodeHS
function drawCircle(radius, Color, x, y){
var circle = new Circle(radius);
circle.setColor(Color);
circle.setPosition(x, y);
add(circle);
return(circle);
}
//Provided by CodeHs
function draw(){
START_RADIUS = START_RADIUS + INCREMENT;
circle.setRadius(START_RADIUS);
circle.setColor(Color.yellow);
counter++;
if(counter == MAX_RADIUS){
counter = 0;
START_RADIUS = 1;
}
}
//Moves the player and if it hits the finish line, spams the message "You win!"
function move(e){
if(e.keyCode == Keyboard.LEFT){
player.move(-5, 0);
setTimer(printWin, DELAY);
}
if(e.keyCode == Keyboard.UP){
player.move(0, -5);
setTimer(printWin, DELAY);
}
if(e.keyCode == Keyboard.DOWN){
player.move(0, 5);
setTimer(printWin, DELAY);
}
if(e.keyCode == Keyboard.RIGHT){
player.move(5, 0);
setTimer(printWin, DELAY);
}
}
//Prints the win message once player wins
function printWin(){
if(player.getX() >= finishLine.getX()) {
var won = true;
}
if(won == true){
println("You win!");
}
}
Please remember that it is very basic code (no HTML or design) and I'm new.
The way to get an object position is to use object.getX() and object.getY(). Anyways, I made it spam you lose when you touch a ball with your collision code. Here is the fixed game:
//Variables
var brown = new Color(139 ,69 ,19);
var START_RADIUS = 1;
var DELAY = 100;
var INCREMENT = 1;
var CHANGE_COLORS_AT = 10;
var MAX_RADIUS = 100;
var counter = 0;
var player;
var circle;
var finishLine;
var RADIUS = 20;
var obstacle;
var obstacle2;
var obstacle3;
var dx = 0;
var dy = 4;
var dx2 = 0;
var dy2 = -4;
var dx3 = 0;
var dy3 = 7;
var x;
var y;
//Start Function
function start(){
var wannaStart = readLine("Do you wanna start playing Impossible Dodgeball? ")
if(wannaStart == "Yes" || wannaStart == "yes" || wannaStart == "Absolutely!"){
startGame();
println("Get to the finish line without getting hit. Enjoy! ");
} else {
println("Enjoy this blank canvas then!");
}
}
//Starts the game if the user responded to correctly to the if statement above
function startGame(){
// checkForCollisions();
drawBackground();
player = drawCircle(20, Color.red, 25, getHeight()/2);
keyDownMethod(move);
drawObstacles();
}
//Draws the background
function drawBackground(){
drawRectangle(getWidth(), 250, 0, 0, Color.blue);
drawSun();
drawRectangle(getWidth(), getHeight()/2, 0, 300, brown);
drawRectangle(getWidth(), 50, 0, 250, Color.green);
finishLine = new Rectangle(10, getHeight());
finishLine.setPosition(350, 0);
finishLine.setColor(Color.white);
add(finishLine);
drawRectangle(10, getHeight(), 360, 0, Color.black);
drawRectangle(10, getHeight(), 370, 0, Color.white);
drawRectangle(10, getHeight(), 380, 0, Color.black);
drawRectangle(10, getHeight(), 390, 0, Color.white);
}
//Draws the rising sun in the background
function drawSun(){
circle = new Circle(START_RADIUS);
circle.setPosition(getWidth()/2, getHeight()/2+10);
add(circle);
setTimer(draw, 50);
}
//Draws all the moving obstacles
function drawObstacles(){
drawObstacle1();
drawObstacle2();
drawObstacle3();
}
//I was unable to get the collision code for the player and the obstacles to work :(
//I fixed it :)
//the fixed code is on line 231
function checkCircleCollision (circle1, circle2) {
var dx4 = circle1.getX() - circle2.getX();
var dy4 = circle1.getY() - circle2.getY();
var distance = Math.sqrt(dx4 * dx4 + dy4 * dy4);
if (distance < circle1.radius + circle2.radius) {
return true;
}
return false;
}
//Draws the first obstacle
function drawObstacle1(){
obstacle = new Circle(RADIUS);
obstacle.setPosition(100, 100);
obstacle.setColor(Randomizer.nextColor());
add(obstacle);
setTimer(draw2, 20);
}
//Draws the second obstacle
function drawObstacle2(){
obstacle2 = new Circle(30);
obstacle2.setPosition(175, 300);
obstacle2.setColor(Randomizer.nextColor());
add(obstacle2);
setTimer(draw3, 20);
}
//Draws the third obstacle
function drawObstacle3(){
obstacle3 = new Circle(10);
obstacle3.setPosition(240, 50);
obstacle3.setColor(Randomizer.nextColor());
add(obstacle3);
setTimer(draw4, 20);
}
//Moves the obstacle
function draw2(){
checkForWalls();
obstacle.move(dx, dy);
}
//Same as above but for obstacle 2
function draw3(){
checkForWalls2();
obstacle2.move(dx2, dy2);
}
//Same as above but for obstacle 3
function draw4(){
checkForWalls3();
obstacle3.move(dx3, dy3);
}
//Bounces obstacle 1 off of the walls
function checkForWalls(){
//bottom wall
if(obstacle.getY() + obstacle.getRadius() > getHeight()){
dy = -dy;
}
//top wall
if(obstacle.getY() - obstacle.getRadius() < 0){
dy = -dy;
}
}
//Bounces obstacle 2 off of the walls
function checkForWalls2(){
//bottom wall
if(obstacle2.getY() + obstacle2.getRadius() > getHeight()){
dy2 = -dy2;
}
//top wall
if(obstacle2.getY() - obstacle2.getRadius() < 0){
dy2 = -dy2;
}
}
//Bounces obstacle 3 off of the walls
function checkForWalls3(){
//bottom wall
if(obstacle3.getY() + obstacle3.getRadius() > getHeight()){
dy3 = -dy3;
}
//top wall
if(obstacle3.getY() - obstacle3.getRadius() < 0){
dy3 = -dy3;
}
}
//Provided by CodeHS
function drawRectangle(width, height, x, y, Color){
var rect = new Rectangle(width, height);
rect.setPosition(x, y);
rect.setColor(Color);
add(rect);
}
//Provided by CodeHS
function drawCircle(radius, Color, x, y){
var circle = new Circle(radius);
circle.setColor(Color);
circle.setPosition(x, y);
add(circle);
return(circle);
}
//Provided by CodeHs
function draw(){
START_RADIUS = START_RADIUS + INCREMENT;
circle.setRadius(START_RADIUS);
circle.setColor(Color.yellow);
counter++;
if(counter == MAX_RADIUS){
counter = 0;
START_RADIUS = 1;
}
}
//Moves the player and if it hits the finish line, spams the message "You win!"
function move(e){
if(e.keyCode == Keyboard.LEFT){
player.move(-5, 0);
setTimer(printWin, DELAY);
}
if(e.keyCode == Keyboard.UP){
player.move(0, -5);
setTimer(printWin, DELAY);
}
if(e.keyCode == Keyboard.DOWN){
player.move(0, 5);
setTimer(printWin, DELAY);
}
if(e.keyCode == Keyboard.RIGHT){
player.move(5, 0);
setTimer(printWin, DELAY);
}
//lose code implements your collision code to detect if player is touching ball
if(checkCircleCollision(player, obstacle) == true || checkCircleCollision(player, obstacle2) == true || checkCircleCollision(player, obstacle3) == true){
setTimer(Fail, DELAY);
}
}
//Prints the win message once player wins
function printWin(){
if(player.getX() >= finishLine.getX()) {
var won = true;
}
if(won == true){
println("You win!");
}
}
function Fail(){
println("You lost!!!");
}

can not rotate a rectangular shape in canvas

I am new in HTML5 canvas. I am trying to build game area using HTML canvas where someone can drive around a car inside
Canvas area like if I press the left arrow key the car will turn to the left and if press the right arrow key the car will turn to the right side. And up and down arrow keys are responsible for moving the car upward or downward. And the car must stay within the canvas area. Here, I use rotate method to turn the car right or left. But it is not working, actually the car is getting away from the canvas and behaving like a crap.
Anyone has any idea to solve the problem? I am totally stuck here. Thanks in advance.
Initially I am displaying a rectangle instead of car.
My js file is given below.
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
canvas.width = innerWidth - 100;
canvas.height = innerHeight - 100;
const canvasW = canvas.width;
const canvasH = canvas.height;
let upPressed = false,
downPressed = false,
rightPressed = false,
leftPressed = false;
class PlayerCar {
constructor(carX, carY, carWidth, carHeight) {
this.carX = carX;
this.carY = carY;
this.carWidth = carWidth;
this.carHeight = carHeight;
}
draw() {
ctx.fillStyle = "blue";
ctx.beginPath();
ctx.rect(this.carX, this.carY, this.carWidth, this.carHeight);
ctx.fill();
ctx.closePath();
}
}
const playerCar = new PlayerCar(100, 100, 40, 60);
playerCar.draw();
function navigation() {
const handleKeyDown = (e) => {
if (e.key === "ArrowUp") {
upPressed = true;
}
if (e.key === "ArrowDown") {
downPressed = true;
}
if (e.key === "ArrowRight") {
rightPressed = true;
}
if (e.key === "ArrowLeft") {
leftPressed = true;
}
};
const handleKeyUp = (e) => {
if (e.key === "ArrowUp") {
upPressed = false;
}
if (e.key === "ArrowDown") {
downPressed = false;
}
if (e.key === "ArrowRight") {
rightPressed = false;
}
if (e.key === "ArrowLeft") {
leftPressed = false;
}
};
document.addEventListener("keydown", handleKeyDown);
document.addEventListener("keyup", handleKeyUp);
}
function animate() {
requestAnimationFrame(animate);
ctx.clearRect(0, 0, canvasW, canvasH);
if (upPressed) {
playerCar.carY -= 5;
}
if (downPressed) {
playerCar.carY += 5;
}
if (leftPressed) {
ctx.save();
ctx.translate(
playerCar.carX + playerCar.width / 2,
playerCar.carY + playerCar.height / 2
);
ctx.rotate((Math.PI / 180) * 0.2);
playerCar.carX -= 5;
ctx.restore();
}
if (rightPressed) {
ctx.save();
ctx.translate(
playerCar.carX + playerCar.width / 2,
playerCar.carY + playerCar.height / 2
);
ctx.rotate((Math.PI / 180) * -0.2);
playerCar.carX += 5;
ctx.restore();
}
if (playerCar.carX < 0) playerCar.carX = 0;
if (playerCar.carX > canvasW - playerCar.carWidth)
playerCar.carX = canvasW - playerCar.carWidth;
if (playerCar.carY < 0) playerCar.carY = 0;
if (playerCar.carY > canvasH - playerCar.carHeight)
playerCar.carY = canvasH - playerCar.carHeight;
playerCar.draw();
}
function startGame() {
animate();
}
startGame();
navigation();
I would first move all of the update info to a method in the car class vice doing it in the animate loop.
This is where cos and sin come in and getting familiar with angles. You also must understand the canvas relation the the object it draws is always at (x, y) of (0, 0) unless you translate it to the center. To do that draw your object in this manner:
ctx.fillStyle = "blue";
ctx.save();
ctx.beginPath();
ctx.translate(this.carX, this.carY)
ctx.rotate(this.angle)
ctx.rect(-this.carWidth/2, -this.carHeight/2, this.carWidth, this.carHeight);
ctx.fill();
ctx.closePath();
ctx.restore();
Use of save() and restore() are a must unless you want to translate and rotate you object back to its original. It's the same ting but simpler. So now I am translating the car around the canvas and the car itself is drawn at negative half the width and height to ensure the canvas (0, 0) corner is in the center of the car. This is because canvas always rotates from the top-left corner.
Now create a method called update() and put you control logic in there:
update() {
if (rightPressed) {
this.angle += this.rot
} else if (leftPressed) {
this.angle -= this.rot
}
if (upPressed) {
this.carX += Math.cos(this.angle+toRadians(-90)) * 5;
this.carY += Math.sin(this.angle+toRadians(-90)) * 5;
}
}
Be aware I added angle and rot to the constructor also. What this is doing is when you press left or right the car rotate accordingly. As for pressing up we are going to translate it by the rotation. Since this would normally make the car drive to the right we have to also add -90 degrees to the current angle to ensure the car drives forwards. Just remove +toRadians(-90) and see what happens.
Multiplying it by 5 is an arbitrary number for speed. You can even make it part of the constructor and set it there. i.e. this.speed = 5
Doing the same thing for downPressed but instead use +toRadians(90)
toRadians() is just a simple function added to your code to convert degrees to radians.
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
canvas.width = 600;
canvas.height = 600;
const canvasW = canvas.width;
const canvasH = canvas.height;
let upPressed = false,
downPressed = false,
rightPressed = false,
leftPressed = false;
class PlayerCar {
constructor(carX, carY, carWidth, carHeight) {
this.carX = carX;
this.carY = carY;
this.carWidth = carWidth;
this.carHeight = carHeight;
this.angle = 0;
this.rot = 0.1; //control how fast it turns
}
draw() {
ctx.fillStyle = "blue";
ctx.save();
ctx.beginPath();
ctx.translate(this.carX, this.carY)
ctx.rotate(this.angle)
ctx.rect(-this.carWidth/2, -this.carHeight/2, this.carWidth, this.carHeight);
ctx.fill();
ctx.closePath();
ctx.restore();
}
update() {
if (rightPressed) {
this.angle += this.rot
} else if (leftPressed) {
this.angle -= this.rot
}
if (upPressed) {
this.carX += Math.cos(this.angle+toRadians(-90)) * 5;
this.carY += Math.sin(this.angle+toRadians(-90)) * 5;
}
if (downPressed) {
this.carX += Math.cos(this.angle+toRadians(90)) * 5;
this.carY += Math.sin(this.angle+toRadians(90)) * 5;
}
}
}
function toRadians(deg) {
return (deg * Math.PI) / 180;
}
const playerCar = new PlayerCar(100, 100, 40, 60);
playerCar.draw();
function navigation() {
const handleKeyDown = (e) => {
if (e.key === "ArrowUp") {
upPressed = true;
}
if (e.key === "ArrowDown") {
downPressed = true;
}
if (e.key === "ArrowRight") {
rightPressed = true;
}
if (e.key === "ArrowLeft") {
leftPressed = true;
}
};
const handleKeyUp = (e) => {
if (e.key === "ArrowUp") {
upPressed = false;
}
if (e.key === "ArrowDown") {
downPressed = false;
}
if (e.key === "ArrowRight") {
rightPressed = false;
}
if (e.key === "ArrowLeft") {
leftPressed = false;
}
};
document.addEventListener("keydown", handleKeyDown);
document.addEventListener("keyup", handleKeyUp);
}
function animate() {
requestAnimationFrame(animate);
ctx.clearRect(0, 0, canvasW, canvasH);
if (playerCar.carX < 0) playerCar.carX = 0;
if (playerCar.carX > canvasW - playerCar.carWidth)
playerCar.carX = canvasW - playerCar.carWidth;
if (playerCar.carY < 0) playerCar.carY = 0;
if (playerCar.carY > canvasH - playerCar.carHeight)
playerCar.carY = canvasH - playerCar.carHeight;
playerCar.draw();
playerCar.update();
}
function startGame() {
animate();
}
startGame();
navigation();
<canvas></canvas>
To be clear on why your code is not doing what you expect think about this. You are trying to translate and rotate the context without ever accessing the object. If you were to add ctx.fillRect() to your animate loop would you think it's going to just know that you want to change the car? Same goes for translate and rotate. Try adding a fillStyle and fillRect to your rightPressed
if (rightPressed) {
ctx.save();
playerCar.carX += 5;
ctx.translate(
playerCar.carX + playerCar.width / 2,
playerCar.carY + playerCar.height / 2
);
ctx.rotate(45);
ctx.fillStyle = 'grey'
ctx.fillRect(0, 0, canvas.width, canvas.height)
ctx.restore();
}
You will see when you press right the context does what you want just not the context of the object. This is why adding it directly top the class should be done. Now you are specifically targeting the object you want.

Game not iterating, not sure why

I'm trying to make a browser game with pure javascript. I was using codesandbox.io for writing it at first, but the I decided I was done for the day and needed to check if it works in a browser. Lo and behold, it does not. I genuinely have no idea why it's not working.
All the code is supposed to do, is make a square jump. which it does do, however right when you let go of the up key, the page hangs, it won't even refresh. Doesn't crash the browser though. Anyways, here's my code.
class player {
constructor(gameW, gameH) {
this.gameH = gameH;
this.width = 50;
this.heigth = 50;
this.maxUpV = 5;
this.currV = 0;
this.gravConst = 50;
this.position = {
x: 50,
y: 150
};
}
jumpUp() {
this.currV = -this.maxUpV;
}
fall(falling) {
while (this.position.y < 150) {
this.currV = this.maxUpV;
}
return (falling = false);
}
draw(ctx) {
ctx.fillStyle = "#F00";
ctx.fillRect(this.position.x, this.position.y, this.width, this.heigth);
}
update(deltaTime) {
if (!deltaTime) {
return;
}
this.position.y += this.currV;
if (this.position.y + this.heigth > 200) {
this.position.y = 150;
}
}
}
class input {
constructor(Player) {
this.falling = false;
document.addEventListener("keydown", event => {
if (event.keyCode === 38) {
if (!Player.fall(this.falling)) {
Player.jumpUp();
}
}
});
document.addEventListener("keyup", event => {
if (event.keyCode === 38) {
this.falling = true;
Player.fall(this.falling);
}
});
}
}
const GAME_WIDTH = 800;
const GAME_HEIGHT = 300;
var canvas = document.getElementById("gameScreen");
var ctx = canvas.getContext("2d");
var Player = new player(GAME_WIDTH, GAME_HEIGHT);
ctx.clearRect(0, 0, 800, 300);
ctx.fillRect(0, 200, 800, 200);
ctx.fillRect(400, 100, 50, 1);
Player.draw(ctx);
new input(Player);
var lastTime = 0;
function gameLoop(timeStamp) {
var deltaTime = timeStamp - lastTime;
lastTime = timeStamp;
ctx.clearRect(0, 0, 800, 200);
Player.update(deltaTime);
Player.draw(ctx);
requestAnimationFrame(gameLoop);
}
gameLoop();
Oh and also, when I was writing it in codesandbox.io, the classes were separate files that I imported into the main .js file. That gave me an error in the browser, so I just put everything in one file. I tried both Vivaldi and Firefox, to no avail.
I originally misread the question. Your code is locking up in your fall function. Once you hit the max height you were getting stuck in a loop waiting for the fall but never returning control to anywhere that could generate a fall. I'm having some difficulty understanding your max height validation.
The fall function will always return false.
fall(falling) {
while (this.position.y < 150) {
this.currV = this.maxUpV;
}
return (falling = false);
}
The return value of an assignment is the value assigned, so in this case your return value will always be false
I also had to modify the logic for the end button press
if (!Player.fall(this.falling)) {
Player.jumpUp();
}
The conditional was basically always returning true and could be simplified.
I hope this helps!
class player {
constructor(gameW, gameH) {
this.gameH = gameH;
this.width = 50;
this.height = 50;
this.maxUpV = 5;
this.currV = 0;
this.gravConst = 50;
this.position = {
x: 50,
y: 150
};
}
jumpUp() {
this.currV = -this.maxUpV;
}
fall(falling) {
if (this.position.y <150) {
this.currV = this.maxUpV;
return true
}
return false;
}
draw(ctx) {
ctx.fillStyle = "#F00";
ctx.fillRect(this.position.x, this.position.y, this.width, this.height);
}
update(deltaTime) {
if (!deltaTime) {
return;
}
this.position.y += this.currV;
if (this.position.y + this.height > 200) {
this.position.y = 150;
}
}
}
class input {
constructor(Player) {
this.falling = false;
document.addEventListener("keydown", event => {
if (event.keyCode === 38) {
if (!this.falling) {
Player.jumpUp();
}
}
});
document.addEventListener("keyup", event => {
if (event.keyCode === 38) {
this.falling = true;
this.falling = Player.fall();
}
});
}
}
const GAME_WIDTH = 800;
const GAME_HEIGHT = 300;
var canvas = document.getElementById("gameScreen");
var ctx = canvas.getContext("2d");
var Player = new player(GAME_WIDTH, GAME_HEIGHT);
ctx.clearRect(0, 0, 800, 300);
ctx.fillRect(0, 200, 800, 200);
ctx.fillRect(400, 100, 50, 1);
Player.draw(ctx);
new input(Player);
var lastTime = 0;
function gameLoop(timeStamp) {
var deltaTime = timeStamp - lastTime;
lastTime = timeStamp;
ctx.clearRect(0, 0, 800, 200);
Player.update(deltaTime);
Player.draw(ctx);
requestAnimationFrame(gameLoop);
}
gameLoop();
<canvas id="gameScreen" width=400 height=400></canvas>

2D platformer game, make player camera view in html5

I want to modify the platformer game that I find in codepen.
http://codepen.io/loktar00/pen/JEdqD
the original is like the below image.
I want to change it to be:
I want to zoom in the viewport to player and making a camera-like view where I could scroll a level within a canvas element.
Like this game http://www.html5quintus.com/quintus/examples/platformer_full/
The viewport and camera is tracking the player.
This is my code:
(function () {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 100,
height = 100,
player = {
x: width / 2,
y: height - 15,
width: 5,
height: 5,
speed: 3,
velX: 0,
velY: 0,
jumping: false,
grounded: false
},
keys = [],
friction = 0.8,
gravity = 0.3;
var boxes = [];
// player's position
var playerX = 20;
var playerY = 20;
// how far offset the canvas is
var offsetX = 0;
var offsetY = 0;
// dimensions
boxes.push({
x: 0,
y: 0,
width: 10,
height: height
});
boxes.push({
x: 0,
y: height - 2,
width: width,
height: 50
});
boxes.push({
x: width - 10,
y: 0,
width: 50,
height: height
});
boxes.push({
x: 120,
y: 10,
width: 80,
height: 80
});
boxes.push({
x: 170,
y: 50,
width: 80,
height: 80
});
boxes.push({
x: 220,
y: 100,
width: 80,
height: 80
});
boxes.push({
x: 270,
y: 150,
width: 40,
height: 40
});
canvas.width = width;
canvas.height = height;
function update() {
// check keys
if (keys[38] || keys[32] || keys[87]) {
// up arrow or space
if (!player.jumping && player.grounded) {
player.jumping = true;
player.grounded = false;
player.velY = -player.speed * 2;
}
}
if (keys[39] || keys[68]) {
// right arrow
if (player.velX < player.speed) {
player.velX++;
offsetX--;
}
}
if (keys[37] || keys[65]) {
// left arrow
if (player.velX > -player.speed) {
player.velX--;
offsetX++;
}
}
player.velX *= friction;
player.velY += gravity;
ctx.clearRect(0, 0, width, height);
ctx.fillStyle = "black";
ctx.beginPath();
player.grounded = false;
for (var i = 0; i < boxes.length; i++) {
ctx.rect(boxes[i].x, boxes[i].y, boxes[i].width, boxes[i].height);
var dir = colCheck(player, boxes[i]);
if (dir === "l" || dir === "r") {
player.velX = 0;
player.jumping = false;
} else if (dir === "b") {
player.grounded = true;
player.jumping = false;
} else if (dir === "t") {
player.velY *= -1;
}
}
if(player.grounded){
player.velY = 0;
}
player.x += player.velX;
player.y += player.velY;
ctx.save();
ctx.translate(offsetX, offsetY);
// clear the viewport
ctx.clearRect(-offsetX, -offsetY, 100,100);
ctx.fill();
ctx.fillStyle = "red";
ctx.fillRect(player.x, player.y, player.width, player.height);
ctx.fillRect(playerX-offsetX, playerY-offsetY, 8, 8);
// draw the other stuff
var l = boxes.length;
for (var i = 0; i < l; i++) {
// we should really only draw the things that intersect the viewport!
// but I am lazy so we are drawing everything here
var x = boxes[i][0];
var y = boxes[i][1];
ctx.fillStyle = 'lightblue';
ctx.fillRect(x, y, 8, 8);
ctx.fillStyle = 'black';
ctx.fillText(x + ', ' + y, x, y) // just to show where we are drawing these things
}
ctx.restore();
requestAnimationFrame(update);
}
function colCheck(shapeA, shapeB) {
// get the vectors to check against
var vX = (shapeA.x + (shapeA.width / 2)) - (shapeB.x + (shapeB.width / 2)),
vY = (shapeA.y + (shapeA.height / 2)) - (shapeB.y + (shapeB.height / 2)),
// add the half widths and half heights of the objects
hWidths = (shapeA.width / 2) + (shapeB.width / 2),
hHeights = (shapeA.height / 2) + (shapeB.height / 2),
colDir = null;
// if the x and y vector are less than the half width or half height, they we must be inside the object, causing a collision
if (Math.abs(vX) < hWidths && Math.abs(vY) < hHeights) {
// figures out on which side we are colliding (top, bottom, left, or right)
var oX = hWidths - Math.abs(vX),
oY = hHeights - Math.abs(vY);
if (oX >= oY) {
if (vY > 0) {
colDir = "t";
shapeA.y += oY;
} else {
colDir = "b";
shapeA.y -= oY;
}
} else {
if (vX > 0) {
colDir = "l";
shapeA.x += oX;
} else {
colDir = "r";
shapeA.x -= oX;
}
}
}
return colDir;
}
document.body.addEventListener("keydown", function (e) {
keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function (e) {
keys[e.keyCode] = false;
});
window.addEventListener("load", function () {
update();
});
<h3>A, D or Arrow keys to move, W or space to jump</h3>
<canvas id="canvas"></canvas>
But this does not work.
You can use the same code that you had in the codepen, but add a couple lines in the load event, before the first update().
Let's say something like:
window.addEventListener("load", function () {
ctx.scale(2,2);
ctx.translate(-100,-100);
update();
});
This will zoom by two times and center on new coordinates, BUT keep in mind that you have to do it yourself if you want to re-center when the player is going out of the view.
As a partial way of doing this, you can check if the player moved and translate the canvas using the opposite values of player.velX and player.velY. Something like:
var playerMoved = false;
if (keys[38] || keys[32] || keys[87]) {
playerMoved = true;
//...Other stuff
}
if (keys[39] || keys[68]) {
playerMoved = true;
//...Other stuff
}
if (keys[37] || keys[65]) {
playerMoved = true;
//...Other stuff
}
if (playerMoved) {
// You still need to check quite a few things, like
// the player being out of bounds, the view not translating
// when x less than or bigger then a specific value, and so on
ctx.translate(-player.velX, -player.velY);
}
This is not a complete solution because that would require quite some code, but it should get you started.

Moving group of objects at the same time in canvas

My problem is that I have no idea how to implement group of objects, in my situation, group of rectangles moving all at the same time. Well, I implemented easily moving one rectangle with specific direction which you can see below from my code. Also I tried to add an array with group of rectangles. So again my question is how to implement group of rectangles (3 rows 3 columns, 9 of them, for instance) to move the same way how my one rectangle is moving in the code below????? So basically very right side of group and very left side of the group will hit the border while column in the middle of 3X3 will stay moving between two columns of 3X3.....Any help will appreciated. Thank you...
<html>
<head>
<title>Spaceman Invaders</title>
<script>
window.onload = function() {
var canvas = document.getElementById("screen");
context = canvas.getContext("2d");
context.fillStyle="black";
context.fillRect(0,0,canvas.width, canvas.height);
context.fillStyle = "red";
context.fillRect(30, 100, 20 , 20);
var posx = 27;
var posy = 100;
var go_right = true;
var go_down = false;
if (canvas.getContext) {
/* var array = [];
array.push(new Shape(20, 0, 50, 50, "red"));
array.push(new Shape(20, 60, 50, 50, "red"));
array.push(new Shape(20, 120, 50, 50, "red"));
array.push(new Shape(80, 0, 50, 50, "red"));
array.push(new Shape(80, 60, 50, 50, "red"));
array.push(new Shape(80, 120, 50, 50, "red"));
array.push(new Shape(140, 0, 50, 50, "red"));
array.push(new Shape(140, 60, 50, 50, "red"));
array.push(new Shape(140, 120, 50, 50, "red"));*/
setInterval( function() {
if (!go_down) {
if(posx < 250 && go_right) {
posx += 3;
} else if(posx < 30) {
go_right = true;
go_down = true;
} else if(!go_right) {
posx -= 3;
}else {
go_right = false;
go_down = true;
}
} else {
//if(posy <= 30)
posy += 5;
go_down = false;
}
context.fillStyle="black";
context.fillRect(0,0,canvas.width, canvas.height);
context.fillStyle = "red";
context.beginPath();
context.fillRect(posx, posy, 20 , 20);
context.fill();
}
, 20);
}
</script>
</head>
<body>
<canvas id="screen" width="300" height="500"/>
</body>
</html>
You will have to store the x,y position of each rectangle. You may create an new class for this. I've made you an example:
var Alien = function(x, y) {
this.x = x;
this.y = y;
this.posx = 30 + x*30;
this.posy = 90 + y*30;
this.go_right = true;
this.go_down = false;
this.perrow = 3;
}
Alien.prototype.move = function() {
if (!this.go_down) {
if(this.posx + (this.perrow-1-this.x) * 30 < 250 && this.go_right) {
this.posx += 3;
} else if(this.posx < 30 + this.x*30) {
this.go_right = true;
this.go_down = true;
} else if(!this.go_right) {
this.posx -= 3;
} else {
this.go_right = false;
this.go_down = true;
}
} else {
//if(posy <= 30)
this.posy += 30;
this.go_down = false;
}
}
Alien.prototype.draw = function(context) {
if(this.x == 0) {
context.fillStyle = "red";
} else if(this.x == 1) {
context.fillStyle = "yellow";
} else {
context.fillStyle = "blue";
}
context.beginPath();
context.fillRect(this.posx, this.posy, 20 , 20);
context.fill();
}
Then you can update the position and draw each object separately in a loop inside of your intervall callback.
EDIT:
Now the objects move downwards all at once.
You can test it here:
http://jsfiddle.net/Z6F4d/3/

Categories