Resize rotated shape on HTML5 Canvas - javascript

I want to resize a rotated shape without it drifting away. I'm aware that I need to adjust the shape coordinates depending on the rotation angle, but I can't seem to figure out the formula to do it.
This is what I've managed to do so far (https://jsfiddle.net/9o3vefym/1/)
<!DOCTYPE html>
<html>
<body style="margin: 0">
<canvas
id="canvas"
width="400"
height="400"
style="border: 1px solid #d3d3d3"
></canvas>
<script>
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
const rect = {
x: 100,
y: 100,
width: 50,
height: 50,
angle: 0
};
window.onkeydown = keyDown;
draw();
function keyDown(evt) {
if (evt.key == "ArrowRight") {
rect.width += 5;
}
if (evt.key == "ArrowLeft") {
rect.x -= 5;
rect.width += 5;
}
if (evt.key == "ArrowUp") {
rect.y -= 5;
rect.height += 5;
}
if (evt.key == "ArrowDown") {
rect.height += 5;
}
if (evt.key == "a") {
rect.angle -= (45 * Math.PI) / 180;
}
if (evt.key == "s") {
rect.angle += (45 * Math.PI) / 180;
}
draw();
}
function draw() {
context.setTransform(1, 0, 0, 1, 0, 0);
context.clearRect(0, 0, canvas.width, canvas.height);
const cx = (rect.x * 2 + rect.width) / 2;
const cy = (rect.y * 2 + rect.height) / 2;
context.translate(cx, cy);
context.rotate(rect.angle);
context.translate(-cx, -cy);
context.fillRect(rect.x, rect.y, rect.width, rect.height);
}
</script>
</body>
</html>
It works fine if the shape isn't rotated, but it breaks down if I try to resize a rotated shape.
For example, If I rotate the rectangle by pressing the key "a" or "s" and then resize it using any of the arrow keys, the rectangle will "drift away". What I'm trying to do is to keep the rectangle still while resizing it, as it happens when it isn't rotated.
Also, I'm trying to find a solution that doesn't involve changing draw(), since I can't do that in the codebase I'm trying to fix this problem.
I'd really appreciate some help.

This is not fixable outside of draw(). The problem is that the draw method always assumes the center of the rectangle is the rotation point, but what you want is to be able to shift the point of rotation based on which direction the rectangle is growing in. The only way to avoid drift WITHOUT changing draw() is to always keep the rectangle centered at the same point. See the commented portions of the code snippet.
The reason you can't fix it outside of draw() is because of the transform reset done on the first line. Otherwise, you'd be able to adjust the transform before and after draw() to accommodate.
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
const rect = {
x: 100,
y: 100,
width: 50,
height: 50,
angle: 0
};
window.onkeydown = keyDown;
draw();
function keyDown(evt) {
if (evt.key == "ArrowRight") {
//rect.x -= 2.5;
rect.width += 5;
}
if (evt.key == "ArrowLeft") {
rect.x -= 5; //2.5;
rect.width += 5;
}
if (evt.key == "ArrowUp") {
//rect.y -= 2.5;
rect.height += 5;
}
if (evt.key == "ArrowDown") {
rect.y -= 5; //2.5;
rect.height += 5;
}
if (evt.key == "a") {
rect.angle -= (45 * Math.PI) / 180;
}
if (evt.key == "s") {
rect.angle += (45 * Math.PI) / 180;
}
draw();
}
function draw() {
// The next line is why you can't fix the drift outside of draw().
context.setTransform(1, 0, 0, 1, 0, 0);
context.clearRect(0, 0, canvas.width, canvas.height);
const cx = (rect.x * 2 + rect.width) / 2;
const cy = (rect.y * 2 + rect.height) / 2;
context.translate(cx, cy);
context.rotate(rect.angle);
context.translate(-cx, -cy);
context.fillStyle = "#000";
context.fillRect(rect.x, rect.y, rect.width, rect.height);
context.fillStyle = "#F00";
context.fillRect(cx, cy, 2, 2);
}
<!DOCTYPE html>
<html>
<body style="margin: 0">
<canvas
id="canvas"
width="400"
height="400"
style="border: 1px solid #d3d3d3"
></canvas>
<script>
</script>
</body>
</html>
Here's another snippet with a solution that requires changes inside of draw(). The idea is that you define cx and cy first and keep them fixed.
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
const rect = {
x: 100,
y: 100,
width: 50,
height: 50,
angle: 0
};
rect.cx = rect.x + rect.width / 2;
rect.cy = rect.y + rect.height / 2;
window.onkeydown = keyDown;
draw();
function keyDown(evt) {
if (evt.key == "ArrowRight") {
rect.width += 5;
}
if (evt.key == "ArrowLeft") {
rect.x -= 5;
rect.width += 5;
}
if (evt.key == "ArrowUp") {
rect.y -= 5;
rect.height += 5;
}
if (evt.key == "ArrowDown") {
rect.height += 5;
}
if (evt.key == "a") {
rect.angle -= (45 * Math.PI) / 180;
}
if (evt.key == "s") {
rect.angle += (45 * Math.PI) / 180;
}
draw();
}
function draw() {
context.setTransform(1, 0, 0, 1, 0, 0);
context.clearRect(0, 0, canvas.width, canvas.height);
context.translate(rect.cx, rect.cy);
context.rotate(rect.angle);
context.translate(-rect.cx, -rect.cy);
context.fillStyle = "#000";
context.fillRect(rect.x, rect.y, rect.width, rect.height);
context.fillStyle = "#F00";
context.fillRect(rect.cx, rect.cy, 2, 2);
}
<!DOCTYPE html>
<html>
<body style="margin: 0">
<canvas
id="canvas"
width="400"
height="400"
style="border: 1px solid #d3d3d3"
></canvas>
<script>
</script>
</body>
</html>

Related

I cannot use context.canvas.height when testing against the position of an object

I have made a simple rocket with controls and I want it to stop when it hits the ground but for whatever reason the only number that I can use to test it against is 0. I have tried context.canvas.height - this.size.height because that is what I want it to be, but when I use that in the if statement the code does not work as desired. The goal is to be able to stop all of the rocket's movement when it hits the ground.
Here is my JavaScript code
(function () {
// the canvas constants
const canvas = document.getElementById('game');
const context = canvas.getContext('2d');
// setting the canvas size
context.canvas.width = window.innerWidth;
context.canvas.height = window.innerHeight;
// the game constants
const ROCKET_SIZE = { width: 20, height: 30 };
const ROCKET_POSITION = { x: 200, y: 200 };
const GRAVITY = 2;
const THRUST = 5;
const AFTERBURNER_THRUST = 20;
const INERTIAL_DAMPING = 0.98;
// the rocket ship class
class RocketShip {
constructor(size, position) {
this.color = 'white';
this.size = size;
this.position = position;
this.angle = 0;
this.engineOn = false;
this.afterburner = false;
this.inertialDampeners = false;
this.rotatingLeft = false;
this.rotatingRight = false;
this.velocity = {
x: 0,
y: 0,
};
}
draw() {
// the center of the rocket
const triangleCenterX = this.position.x + 0.5 * this.size.width;
const triangleCenterY = this.position.y + 0.5 * this.size.height;
context.save();
context.translate(triangleCenterX, triangleCenterY);
context.rotate(this.angle);
context.lineWidth = 1;
context.beginPath();
// drawing the delta rocket
context.moveTo(0, -this.size.height / 2);
context.lineTo(-this.size.width / 2, this.size.height / 2);
context.lineTo(this.size.width / 2, this.size.height / 2);
context.closePath();
context.strokeStyle = this.color;
context.stroke();
// drawing the engine if it is active
if (this.engineOn) {
const fireYPos = this.size.height / 2 + 5;
const fireXPos = this.size.width * 0.25;
context.beginPath();
context.moveTo(-fireXPos, fireYPos);
context.lineTo(fireXPos, fireYPos);
context.lineTo(0, fireYPos + Math.random() * 50);
context.lineTo(-fireXPos, fireYPos);
context.closePath();
context.fillStyle = 'orange';
context.fill();
}
// drawing the afterburner if it is active
if (this.afterburner) {
const fireYPos = this.size.height / 2 + 5;
const fireXPos = this.size.width * 0.25;
context.beginPath();
context.moveTo(-fireXPos, fireYPos);
context.lineTo(fireXPos, fireYPos);
context.lineTo(0, fireYPos + Math.random() * 100);
context.lineTo(-fireXPos, fireYPos);
context.closePath();
context.fillStyle = 'red';
context.fill();
}
context.restore();
}
moveRocket() {
// convert angle from degrees to radians
const degToRad = Math.PI / 180;
// changing the position of the rocket
this.position.x += this.velocity.x;
this.position.y += this.velocity.y;
// moving the rocket to the other side of the screen
if (this.position.x > context.canvas.width) {
this.position.x = 0;
}
if (this.position.x < 0) {
this.position.x = context.canvas.width;
}
if (this.position.y > context.canvas.height) {
this.position.y = 0;
}
if (this.position.y < 0) {
this.position.y = context.canvas.height;
}
// stopping the rocket if it hits the ground
if (this.position.y === context.canvas.height - this.size.height) {
this.velocity.y = -GRAVITY / 100;
this.velocity.x = 0;
}
// turning the rocket
if (this.rotatingLeft) {
this.angle -= degToRad;
}
if (this.rotatingRight) {
this.angle += degToRad;
}
// accelerating the rocket if the thrust is on
if (this.engineOn) {
this.velocity.x += (THRUST / 100) * Math.sin(this.angle);
this.velocity.y -= (THRUST / 100) * Math.cos(this.angle);
}
// accelerating the rocket if the afterburner is on
if (this.afterburner) {
this.velocity.x += (AFTERBURNER_THRUST / 100) * Math.sin(this.angle);
this.velocity.y -= (AFTERBURNER_THRUST / 100) * Math.cos(this.angle);
}
// decelerating the rocket if the inertial dampeners are on
if (this.inertialDampeners) {
this.velocity.x *= INERTIAL_DAMPING;
this.velocity.y *= INERTIAL_DAMPING;
}
// updating the rocket's velocity due to gravity
this.velocity.y += GRAVITY / 100;
}
}
const rocket = new RocketShip(ROCKET_SIZE, ROCKET_POSITION);
// handling the keyboard events
function handleKeyInput(event) {
const { keyCode, type } = event;
const isKeyDown = type === 'keydown';
if (keyCode === 37) {
rocket.rotatingLeft = isKeyDown;
}
if (keyCode === 39) {
rocket.rotatingRight = isKeyDown;
}
if (keyCode === 38) {
rocket.engineOn = isKeyDown;
}
if (keyCode === 32) {
rocket.afterburner = isKeyDown;
}
if (keyCode === 40) {
rocket.inertialDampeners = isKeyDown;
}
}
// resizing the screen
function onResize() {
context.canvas.width = window.innerWidth;
context.canvas.height = window.innerHeight;
}
function draw() {
// drawing space
context.fillStyle = '#111';
context.fillRect(0, 0, canvas.width, canvas.height);
rocket.moveRocket();
// drawing the rocket
rocket.draw();
// repeating the draw function
requestAnimationFrame(draw);
}
// adding event listeners to the webpage
document.addEventListener('keydown', handleKeyInput);
document.addEventListener('keyup', handleKeyInput);
document.addEventListener('resize', onResize);
// starting the game
draw();
})();
My HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Rocket</title>
<link rel=stylesheet href="styles/rocket2.css" >
</head>
<body id="body">
<canvas id="game"></canvas>
<script src="pscripts/rocket/rocket.js"></script>
<button class="info-btn">
Hello World
</button>
</body>
</html>
My CSS:
#body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
background-color: #111;
}
#game {
position: relative;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.info-btn {
opacity: 1;
position: absolute;
top: 2vh;
right: 2vw;
color: white;
background-color: dimgrey;
font-family: "Agency FB";
font-size: 2vh;
cursor: pointer;
}
.info-btn:hover {
background-color: #4f4f4f;
color: #c7c7c7;
}
.info {
background-color: #4f4f4f;
padding: 2%;
width: 98%;
height: 98%;
}
The code that I have been trying to use to stop the rocket when it reaches context.canvas.height - this.size.height is:
if (this.position.y === context.canvas.height - this.size.height) {
this.velocity.y = -GRAVITY / 100;
this.velocity.x = 0;
}
I am trying to check if the y position of the rocket is equal to the canvas height - the height of the rocket and if so I set the y velocity to the opposite of gravity over 100 so that it has no movement and I set the x velocity to 0.
Thank you to anyone who reads this and tries to help me.
Because you are using === your code will only work when they are equal which is almost never going to happen in an animation. The object could pass the given point between frames. You should use >=
if (this.position.y >= context.canvas.height - this.size.height) {
this.velocity.y = -GRAVITY / 100;
this.velocity.x = 0;
}

Resolve Collision between a Rectangle and a Circle

I am working on a little platformer game. The player is a circle, and I am going to implement the obstacles as rectangles. Does anyone know how to make sure the player can't go through the obstacle? I have tried some methods, but they come out glitchy.
Here is what I have so far (It is a bit long, so the method that I need is inside the resolveCollision function):
var canvas = document.createElement("CANVAS");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.id = "CANVAS";
document.body.appendChild(canvas);
document.body.style.margin = "0px 0px 0px 0px";
document.body.style.overflow = "hidden";
document.body.style.backgroundColor = "#202020";
var ctx = canvas.getContext("2d");
var objects = [];
var player = {
x: window.innerWidth / 2 - 25,
y: 0,
height: 25,
width: 25,
old: {
x: 0,
y: 0,
},
velocity: {
x: 0,
y: 0,
},
jumping: true,
color: "#ff0000",
};
var obstacle = {
x: 50,
y: 300,
width: 50,
height: 50
}
var control = {
left: false,
right: false,
up: false,
keyListener: function (event) {
var keyState;
if (event.type == "keydown") {
keyState = true;
} else {
keyState = false;
}
switch (event.keyCode) {
case 37:
control.left = keyState;
break;
case 38:
control.up = keyState;
break;
case 39:
control.right = keyState;
break;
}
}
};
var checkCollision = function (object) {
var distX = Math.abs(player.x - object.x - object.width / 2);
var distY = Math.abs(player.y - object.y - object.height / 2);
if (distX > (object.width / 2 + (player.width + player.height) / 2)) { return false; }
if (distY > (object.height / 2 + (player.width + player.height) / 2)) { return false; }
if (distX <= (object.width / 2)) { return true; }
if (distY <= (object.height / 2)) { return true; }
var dx = distX - object.width / 2;
var dy = distY - object.height / 2;
return (dx * dx + dy * dy <= ((player.width + player.height) / 2 * (player.width + player.height) / 2));
}
var resolveCollision = function (object) {
// Add Resolve Collision Code
if (checkCollision(object)) {
throw new SyntaxError("Couldn't resolve collision between player and object!");
}
}
var renderFrame = function () {
if (control.up && player.jumping == false) {
player.velocity.y -= 20;
player.jumping = true;
}
if (control.left) {
player.velocity.x -= 0.5;
}
if (control.right) {
player.velocity.x += 0.5;
}
player.velocity.y += 1.5;
player.x += player.velocity.x;
player.y += player.velocity.y;
player.velocity.x *= 0.95;
player.velocity.y *= 0.95;
player.old.x = player.x - player.velocity.x * 1.2;
player.old.y = player.y - player.velocity.y * 1.2;
if (player.y > window.innerHeight - 25) {
player.jumping = false;
player.y = window.innerHeight - 25;
player.velocity.y = 0;
}
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
ctx.fillStyle = player.color;
ctx.beginPath();
ctx.globalAlpha = 0.5;
ctx.ellipse(player.old.x, player.old.y, player.width, player.height, Math.PI / 4, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.globalAlpha = 1;
ctx.ellipse(player.x, player.y, player.width, player.height, Math.PI / 4, 0, 2 * Math.PI);
ctx.fill();
ctx.fillRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height);
if (checkCollision(obstacle)) {
resolveCollision(obstacle)
}
window.requestAnimationFrame(renderFrame);
};
renderFrame();
window.addEventListener("keydown", control.keyListener);
window.addEventListener("keyup", control.keyListener);
Thanks in advance!
EDIT: I didn't make it clear enough before, but I need a way to resolve collision once they are detected. I have a method to detect collisions already.
You're talking about bounding box and bounding circle calculations.
Here is a real simple explanation of the algorithms for each type of geometry:
https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection
Of course if they're all the same shape that may simplify it, one solution would be to convert the circles to boxes:
https://math.stackexchange.com/questions/2360970/how-to-calculate-a-bounding-box-of-a-circle
Then just use bounding box collision detection.
But I think if you want to support both then the general strategy will be to attempt to detect if the Circle intersects with the box.
Here is a description of that algorithm:
https://www.lazyfoo.net/tutorials/SDL/29_circular_collision_detection/index.php
To check if a box and circle collided we need to find the closest point on the box...
Here we find the closest y position much like we did the x position. If the distance squared between the closest point on the box and the center of the circle is less than the circle's radius squared, then there is a collision.

Ball in cavas leaves a trace on animation and overdraws other objects on canvas

I'm making a small game in js where I move a ball on device orientation change. When the ball moves it leaves a trace, I tried to do it with clearRect() but it was overdrawing the rest of things in the canvas. Because of this problem functions checkForWinningHole() and checkForLosingHole() don't work.
Is there any way to make the ball move and don't leave a trace behind?
// event listeners
document.querySelector('.start').addEventListener('click', startGame);
window.addEventListener('deviceorientation', onDeviceOrientationChange, true);
// properties and objects
let canvas = document.querySelector('.canvas');
let ctx = canvas.getContext('2d');
let speedX = 0;
let speedY = 0;
let minute = 0;
let second = 0;
const holes = [];
let gameIsOn = false;
let cw = canvas.width;
let ch = canvas.height;
const score = document.querySelectorAll('.score');
let color;
const ball = {
x: 20,
y: 20,
r: 10,
speedX: 0,
speedY: 0
};
const hole = {
x: 0,
y: 0,
r: 25
};
// functions
function startGame(){
gameIsOn = true;
drawHoles();
drawWinningHole();
function play(){
drawBall();
checkForWinnningHole();
checkForLosingHole();
}
setInterval(play, 16);
}
function drawBall(){
ctx.beginPath();
ctx.fillStyle = ' rgb(206, 36, 6)';
ctx.arc(
ball.x,
ball.y,
ball.r,
0,
2 * Math.PI,
false
);
ctx.fill();
ctx.closePath();
moveBall();
}
function drawHoles(){
color = 'rgb(84, 93, 139)';
for (let i = 1; i < canvas.width/80; i++) {
let hx = Math.floor(Math.random() * (canvas.width - hole.r * 2 + 1)) ;
let hy = Math.floor(Math.random() * (canvas.height - hole.r * 2 +1));
ctx.beginPath();
ctx.arc(
hx,
hy,
hole.r,
0,
2 * Math.PI,
false
);
ctx.fillStyle = color;
ctx.fill();
ctx.closePath();
holes.push({
h: ctx,
c: color
});
}
}
function drawWinningHole(){
color = 'rgb(255, 255, 0)';
ctx.beginPath();
ctx.arc(
Math.floor(Math.random() * (canvas.width - hole.r * 2 + 1)),
Math.floor(Math.random() * (canvas.height - hole.r * 2 +1)),
hole.r,
0,
2 * Math.PI,
false
);
ctx.fillStyle = 'rgb(255, 255, 0)';
ctx.fill();
ctx.closePath();
holes.push({
h: ctx,
c: color
});
console.log(holes);
}
function moveBall(){
if(ball.x + speedX < cw - 30 && ball.x + speedX > 20){
ball.x += speedX;
}
if(ball.y + speedY < ch - 30 && ball.y + speedY > 20){
ball.y += speedY;
}
}
function onDeviceOrientationChange(ev){
speedX = ev.gamma/35;
speedY = ev.beta/35;
}
function checkForWinnningHole(){
holes.forEach(({
ctx,
color
}) => {
if (color === 'rgb(255, 255, 0)' && ball.x >= ctx.x && ball.y >= ctx.y
&& ball.y <= ctx.y + hole.r * 2 && ball.x <= ctx.x + hole.r * 2)
{
gameIsOn = false;
ball.speedX = 0;
ball.speedY = 0;
ball.x = 0;
score.innerHTML = '1';
}
});
}
function checkForLosingHole(){
holes.forEach(({
ctx,
color
}) => {
if (color === 'rgb(84, 93, 139)' && ball.x >= ctx.x && ball.y >= ctx.y && ball.y <= ctx.y + hole.r * 2 && ball.x <= ctx.x + hole.r * 2)
{
gameIsOn = false;
ball.speedX = 0;
ball.speedY = 0;
ball.x = 0;
ball.y = 0;
}
});
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ball in the hole</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas class="canvas" width="700" height="700" ></canvas>
<div class="info">
<button class="start">START GAME</button>
<span>SCORE:</span>
<span class="score">0</span>
</div>
<script src="main.js" ></script>
</body>
</html>
You are painting background once and the multiple times ball, so the 'old' ball shape is never removed, all you need to chanage:
function startGame(){
gameIsOn = true;
function play(){
ctx.clearRect(0, 0, canvas.width, canvas.height); //clear canvas
drawHoles();
drawWinningHole(); // redraw holes
drawBall(); // draw ball with new position
checkForWinnningHole();
checkForLosingHole();
}
setInterval(play, 16);
}
Now all you holes are every 10 ms draw in new positions, sou you have to calculate holes positions once at the begging of the game (it is important), and draw them with the same positions every time.
So for winning hole calculate position on top on you file:
const winingHoleX = Math.floor(Math.random() * (canvas.width - hole.r * 2 + 1))
const winingHoleY = Math.floor(Math.random() * (canvas.height - hole.r * 2 +1))
And draw function:
function drawWinningHole(){
color = 'rgb(255, 255, 0)';
ctx.beginPath();
ctx.arc(
winingHoleX,
winingHoleY,
hole.r,
0,
2 * Math.PI,
false
);
ctx.fillStyle = 'rgb(255, 255, 0)';
ctx.fill();
ctx.closePath();
holes.push({
h: ctx,
c: color
});
console.log(holes);
}
For other holes it should looks similar :)
I hope I helped!

If condition is not behaving like it should be

I'm fairly new to game programming, and made a simple platformer game with JS.
(function() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
player = {
x: 0,
y: canvas.height - 25,
velX: 0,
velY: 0,
speed: 5,
width: 25,
height: 25,
friction: 0.9,
gravity: 0.2,
jumping: false
},
keys = [];
document.body.addEventListener("keydown", function(e) {
keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function(e) {
keys[e.keyCode] = false;
});
function rect(x, y, width, height, color) {
ctx.fillStyle = color;
ctx.fillRect(x, y, width, height);
ctx.fillStyle = 'black';
}
function update() {
if (keys[87]) {
if (!player.jumping) {
player.jumping = true;
player.velY = -player.speed * 2;
}
}
if (keys[68]) {
if (player.velX < player.speed) {
player.velX++;
}
}
if (keys[65]) {
if (player.velX > -player.speed) {
player.velX--;
}
}
if (player.x >= canvas.width - player.width) {
player.x = canvas.width - player.width;
} else if (player.x <= 0) {
player.x = 0;
}
if (player.y >= canvas.height - player.height) {
player.y = canvas.height - player.height;
player.jumping = false;
}
player.x += player.velX;
player.y += player.velY;
player.velX *= player.friction;
player.velY += player.gravity;
ctx.clearRect(0, 0, canvas.width, canvas.height);
rect(player.x, player.y, player.width, player.height, 'black');
requestAnimationFrame(update);
}
requestAnimationFrame(update);
<!doctype html>
<html>
<head>
<title>Platformy stuff</title>
</head>
<body>
<canvas id="canvas" style="border:1px solid #000" width=1339 height=619></canvas>
<script src='game.js'></script>
</body>
</html>
This is the problem. I made this condition:
if (player.y >= canvas.height - player.height) {
player.y -= canvas.height - player.height;
player.jumping = false;
}
So as you can see, this was suppose to prevent the player from falling out of the canvas. So If the player got push out by the gravity player.y += gravity, the condition would set it back to the bottom of the canvas. However, It doesn't really work out. I would be glad if someone could help me with this, thanks.
I cant seem to edit or do not see an edit link/button so here is another answer:
To fix this just put your check code for the payer below canvas above your check for the keypress of key 87 and set velocity to 0.
In other words put the test for the "player is below canvas" as first check in update function. This will work and is tested. Although you may want to gradually nudge the player back up instead of abruptly moving to the edge. And set the velocity to 0. Now to nudge him you could gradually set to 0 based on how far down the payer is. Ill leave that to you.
function update() {
if (player.y >= canvas.height - player.height) {
player.jumping = false;
player.y = canvas.height - player.height;
player.velY = 0;
}
if (keys[87]) {...
}
Looks like you subtracting the canvas height combined with the player height and you want it to be set to it instead to keep it at the edge. Simply remove the - from -=.
player.y = canvas.height - player.height;

Simple HTML and JS code won't work?

I'm trying to make a racing game, and my first step was to try out making the car and getting it to move a bit. Unfortunately, it isn't working, as nothing is showing up on the canvas, not the rectangle nor the car. Any ideas (of course you have ideas)? Sorry if the code isn't formatted correctly, I joined this site today.
HTML:
<!doctype html>
<html lang="en">
<head>
<title>Ball</title>
<script src="http://code.jquery.com/jquery-git2.js"></script>
</head>
<body>
<center>
<canvas id="gameCanvas" width="500" height="500" style="border:5px solid green"></canvas>
<script src="js/Game.js"></script>
</center>
</body>
</html>
JS:
window.onload = function() {
var x = 0;
var y = 0;
var speed = 5;
var angle = 0;
var mod = 0;
var canvas = $('#gameCanvas')[0].getContext('2d');
var context = gameCanvas.getContext('2d');
var car = new Image();
car.src = "Gamecar.png";
window.addEventListener("keydown", keypress_handler, false);
window.addEventListener("keyup", keypress_handler, false);
var moveInterval = setInterval(function() {
draw();
}, 30);
};
function render() {
context.clearRect(0, 0, width, height);
context.fillStyle = "rgb(200, 100, 220)";
context.fillRect(50, 50, 100, 100);
x += (speed * mod) * Math.cos(Math.PI / 180 * angle);
y += (speed * mod) * Math.sin(Math.PI / 180 * angle);
context.save();
context.translate(x, y);
context.rotate(Math.PI / 180 * angle);
context.drawImage(car, -(car.width / 2), -(car.height / 2));
context.restore();
}
function keyup_handler(event) {
if (event.keyCode == 87 || event.keyCode == 83) {
mod = 0;
}
}
function keypress_handler(event) {
console.log(event.keyCode);
if (event.keyCode == 87) {
mod = 1;
}
if (event.keyCode == 83) {
mod = -1;
}
if (event.keyCode == 65) {
angle -= 5;
}
if (event.keyCode == 68) {
angle += 5;
}
}
This is what you need for a start:
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.fillStyle = "rgb(200, 100, 220)";
context.fillRect(50, 50, 100, 100);
x += (speed * mod) * Math.cos(Math.PI / 180 * angle);
y += (speed * mod) * Math.sin(Math.PI / 180 * angle);
context.save();
context.translate(x, y);
context.rotate(Math.PI / 180 * angle);
context.drawImage(car, -(car.width / 2), -(car.height / 2));
context.restore();
}
That is the original render function, but you use it as draw. Also, there were invalid width and height references inside, so I used canvas.width and canvas.height.
This is the progress so far: http://jsfiddle.net/qf47mb4k/
Added an existing car image here, so no more errors in the console: http://jsfiddle.net/qf47mb4k/2/
WASD keys are now working, but you need to clear the canvas on every frame to get what you expected.
After fixing your canvas and context objects (also removed jQuery):
var canvas = document.getElementById('gameCanvas');
var context = canvas.getContext('2d');
To get the brakes working, you need to fix your keyup handler:
window.addEventListener("keyup", keyup_handler, false);
Everything seems fine now: http://jsfiddle.net/qf47mb4k/4/. Enjoy driving the car!
Full Code / Working Example
var x = 0;
var y = 0;
var speed = 5;
var angle = 0;
var mod = 0;
var canvas = document.getElementById('gameCanvas');
var context = canvas.getContext('2d');
var car = new Image();
car.src = "http://images.clipartpanda.com/car-top-view-clipart-red-racing-car-top-view-fe3a.png";
window.addEventListener("keydown", keypress_handler, false);
window.addEventListener("keyup", keyup_handler, false);
var moveInterval = setInterval(function () {
draw();
}, 30);
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.fillStyle = "rgb(200, 100, 220)";
context.fillRect(50, 50, 100, 100);
x += (speed * mod) * Math.cos(Math.PI / 180 * angle);
y += (speed * mod) * Math.sin(Math.PI / 180 * angle);
context.save();
context.translate(x, y);
context.rotate(Math.PI / 180 * angle);
context.drawImage(car, -(car.width / 2), -(car.height / 2));
context.restore();
}
function keyup_handler(event) {
if (event.keyCode == 87 || event.keyCode == 83) {
mod = 0;
}
}
function keypress_handler(event) {
console.log(event.keyCode);
if (event.keyCode == 87) {
mod = 1;
}
if (event.keyCode == 83) {
mod = -1;
}
if (event.keyCode == 65) {
angle -= 5;
}
if (event.keyCode == 68) {
angle += 5;
}
}
<canvas id="gameCanvas" width="500" height="500" style="border:5px solid green"></canvas>

Categories