I've looked at several threads, and I cannot for the life of me get my image to properly rotate to the position of my mouse cursor. I can get the image to translate to the position of my mouse cursor, I know I'm close, I just don't know exactly where I am off at... below is what I have so far. The image needs to rotate at its current position and face the mouse cursor if that makes more sense... PS I am new to coding!
var myGamePiece;
function startGame() {
myGamePiece = new component(50, 50, "Assets/PNG/Soldier 1/soldier1_gun.png", 10, 120, "image"); //size, source, starting location
myGameArea.start();
}
var myGameArea = {
canvas : document.createElement("canvas"),
start : function() {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.frameNo = 0;
this.interval = setInterval(updateGameArea, 1);
},
clear : function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop : function() {
clearInterval(this.interval);
}
}
function component(width, height, color, x, y, type) {
this.type = type;
if (type == "image") {
this.image = new Image();
this.image.src = color;
}
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.update = function() {
this.width = window.innerWidth/20; //update width based on window size
this.height = window.innerHeight/20; //update height based on window size
ctx = myGameArea.context;
if (type == "image") {
document.onmousemove = function(e) {
dx = e.pageX;
dy = e.pageY;
console.log(e.pageX, e.pageY);
theta = Math.atan2(dy - this.y, dx - this.x);
theta = theta * (180/Math.PI);
}
//console.log(theta);
ctx.save();
ctx.translate(this.image.width/2,this.image.height/2); // updates the image origin upon rotating
ctx.rotate(theta); // rotates the image to specified position
ctx.drawImage(this.image,
this.x,
this.y,
this.width, this.height);
ctx.restore();
} else {
console.log("failed");
}
}
this.newPos = function() {
this.x += this.speedX;
this.y += this.speedY;
}
}
function updateGameArea() {
myGameArea.clear();
myGamePiece.newPos();
myGamePiece.update();
}
function moveup() {
myGamePiece.speedY = -1;
}
function movedown() {
myGamePiece.speedY = 1;
}
function moveleft() {
myGamePiece.speedX = -1;
}
function moveright() {
myGamePiece.speedX = 1;
}
function clearmove() {
myGamePiece.speedX = 0;
myGamePiece.speedY = 0;
}
var keys;
setInterval(mainLoop, 50);
function mainLoop(){
document.addEventListener("keydown", function (e) {
keys = (keys || []);
keys[e.keyCode]=true;
if (keys[37]){ // left
moveleft();
}
if (keys[38]){ // up
moveup();
}
if (keys[39]){ // right
moveright();
}
if (keys[40]){ // down
movedown();
}
} , false);
document.addEventListener("keyup", function (e) {
keys[e.keyCode]=false;
stop();
clearmove();
if (keys[37]){ // left
moveleft();
}
if (keys[38]){ // up
moveup();
}
if (keys[39]){ // right
moveright();
}
if (keys[40]){ // down
movedown();
}
}, false);
}
Related
I am unable to figure out what is wrong with my code. I have another example I was able to get to work but it didn't use constructor objects and this one does. That's about the only different I can think of. I've tweaked it in many ways but no luck. Please help me understand why it isn't working.
function newGame() {
let Player, Controller;
let context = document.getElementById("canvas").getContext("2d");
//Player
Player = function (x, y, width, height) {
this.width = width,
this.height = height,
this.x = x,
this.y = y,
this.xVelocity = 0;
this.yVelocity = 0;
this.update = function () {
context.fillStyle = "red";
context.fillRect(this.x + this.xVelocity, this.y + this.yVelocity, this.width, this.height);
};
};
let player1 = new Player(200, 200, 25, 25);
let playerUpdate = function () {
player1.update();
};
//Controller
Controller = function() {
this.right = false;
this.left = false;
this.keyDownUp = function(e) {
let keyInput = (e.type == "keydown") ? true : false;
console.log(keyInput)
switch (e.keyCode) {
case 37:
this.left = keyInput;
break;
case 39:
this.right = keyInput;
}
}
};
let loop = function () {
if (Controller.left) {
player1.xVelocity += 10;
};
playerUpdate();
};
window.requestAnimationFrame(loop);
window.addEventListener("keydown", Controller.keyDownUp);
window.addEventListener("keyup", Controller.keyDownUp);
}
newGame();
Your loop only runs once. requestAnimationFrame(loop); is like setTimeout you need to call it for each frame. Add the line requestAnimationFrame(loop); at the bottom of the function loop.
Example
function loop() {
if (Controller.left) {
player1.xVelocity += 10;
}
playerUpdate();
requestAnimationFrame(loop); // get next frame
};
requestAnimationFrame(loop); // start animation
Re comments
The code is a mess and I am unsure as to your intentions in parts of it.
I have re-written it as follows making guesses as to your intentions.
(() => {
function Player(x, y, width, height) {
this.width = width,
this.height = height,
this.x = x,
this.y = y,
this.vx = 0;
this.vy = 0;
}
Player.prototype = {
update() {
this.vx = controller.left ? -10 : 0;
this.vx = controller.right ? 10 : this.vx;
this.x += this.vx;
this.y += this.vy;
this.x = (this.x + ctx.canvas.width) % ctx.canvas.width;
},
draw() {
ctx.fillStyle = "red";
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
function Controller() {
this.right = false;
this.left = false;
addEventListener("keydown", keyEvent.bind(this));
addEventListener("keyup", keyEvent.bind(this));
function keyEvent(e) {
if (e.code === "ArrowRight") { this.right = e.type === "keydown" }
else if (e.code === "ArrowLeft") { this.left = e.type === "keydown" }
}
}
function loop() {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
player.update();
player.draw();
requestAnimationFrame(loop);
};
const ctx = document.getElementById("canvas").getContext("2d");
const controller = new Controller();
const player = new Player(200, 175, 25, 25);
requestAnimationFrame(loop);
})();
<canvas id="canvas" width="300" height="200"></canvas>
Take what you can from it.
When the component or square touches the bottom of the canvas and I press the up arrow afterwards it collides with the bottom, every jump the component jumps when I press the up arrow it jumps upwards less and less until the component eventually does not jump at all. But the component at the same time moves left and right perfectly still when this problem occurs.
I am controlling the square with the arrow keys and it is the player for this platform game that i am creating and i have no clue how i can change it.
var myGamePiece;
var platformWidth = 500;
var platformX = 0;
var platformY = 250;
function startGame() {
myGameArea.start();
myGamePiece = new component(30, 30, "red", 10, 120);
}
var myGameArea = {
canvas: document.createElement("canvas"),
start: function() {
this.canvas.width = 480;
this.canvas.height = 270;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.interval = setInterval(updateGameArea, 20);
window.addEventListener("keydown", function(e) {
myGameArea.key = e.keyCode;
});
window.addEventListener("keyup", function(e) {
myGameArea.key = false;
});
},
clear: function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
};
function component(width, height, color, x, y, type) {
this.type = type;
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.speedX = 0;
this.speedY = 0;
this.gravity = 0.05;
this.gravitySpeed = 0;
this.update = function() {
ctx = myGameArea.context;
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
};
this.newPos = function() {
this.gravitySpeed += this.gravity;
this.x += this.speedX;
this.y += this.speedY + this.gravitySpeed;
this.hitBottom();
};
this.hitBottom = function() {
var rockbottom = myGameArea.canvas.height - this.height;
if (this.y > rockbottom) {
this.y = rockbottom;
if (myGameArea.canvas.height - this.height && myGamePiece.key == 38) {
this.y = this.speedY;
}
}
};
}
function updateGameArea() {
myGameArea.clear();
myGamePiece.speedX = 0;
myGamePiece.speedY = 0;
if (myGameArea.key && myGameArea.key == 37) {
myGamePiece.speedX = -5;
}
if (myGameArea.key && myGameArea.key == 39) {
myGamePiece.speedX = 5;
}
if (myGameArea.key && myGameArea.key == 38) {
myGamePiece.speedY = -5;
} else {
myGamePiece.speedY = 5;
}
if (myGameArea.key && myGameArea.key == 40) {
myGamePiece.speedY = 5;
}
myGamePiece.newPos();
myGamePiece.update();
}
startGame();
Did you forget to reset the gravity speed?
this.hitBottom = function() {
// ...
if (this.y > rockbottom) {
// ...
this.gravitySpeed = 0; // reset?
}
};
var myGamePiece;
var platformWidth = 360;
var platformX = 0;
var platformY = 120;
function startGame() {
myGameArea.start();
myGamePiece = new Component(12, 12, "red", 10, 10);
}
var myGameArea = {
canvas: document.createElement("canvas"),
start: function() {
this.canvas.width = platformWidth;
this.canvas.height = platformY;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.interval = setInterval(updateGameArea, 20);
window.addEventListener("keydown", function(e) {
myGameArea.key = e.keyCode;
});
window.addEventListener("keyup", function(e) {
myGameArea.key = false;
});
},
fill: function(color) {
this.context.save();
this.context.fillStyle = color;
this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.context.restore();
},
clear: function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
};
function Component(width, height, color, x, y, type) {
this.type = type;
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.speedX = 0;
this.speedY = 0;
this.gravity = 0.05;
this.gravitySpeed = 0;
this.update = function() {
ctx = myGameArea.context;
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
};
this.newPos = function() {
this.gravitySpeed += this.gravity;
this.x += this.speedX;
this.y += this.speedY + this.gravitySpeed;
this.hitBottom();
};
this.hitBottom = function() {
var rockbottom = myGameArea.canvas.height - this.height;
if (this.y > rockbottom) {
this.y = rockbottom;
if (myGameArea.canvas.height - this.height && myGamePiece.key == 38) {
this.y = this.speedY;
}
this.gravitySpeed = 0; // reset?
}
};
}
function updateGameArea() {
myGameArea.fill('#DE7');
myGamePiece.speedX = 0;
myGamePiece.speedY = 0;
if (myGameArea.key) {
switch (myGameArea.key) {
case 37: // left arrow
myGamePiece.speedX = -5;
break;
case 38: // up arrow
myGamePiece.speedY = -5;
break;
case 39: // right arrow
myGamePiece.speedX = +5;
break;
case 40: // down arrow
default:
myGamePiece.speedY = +5;
}
}
myGamePiece.newPos();
myGamePiece.update();
}
startGame();
body {
background: #000;
}
Here is another approach using classes, you can clean up the vector math, by using actual vector classes e.g. Victor.js.
const main = () => {
new GravityGame({
width : 360,
height : 180,
refreshRate : 20
}).start();
}
class AbstractGameClient {
constructor(options) {
this.refreshRate = options.refreshRate
this.view = new GameArea({
width : options.width,
height : options.height
})
}
update() {
this.view.update()
}
start() {
let self = this
self.intervalId = setInterval(function() { self.update() }, self.refreshRate)
return self
}
stop() {
if (self.intervalId) {
clearInterval(self.intervalId)
}
}
}
class GravityGame extends AbstractGameClient {
constructor(options) {
super(options)
let myGamePiece = new Component({
width : 12,
height : 12,
color : 'red'
})
this.view.addComponent(myGamePiece)
}
}
class GameArea {
constructor(options) {
let self = this
self.canvas = document.createElement('canvas')
self.width = options.width
self.height = options.height
self.key = null
self.components = []
self.addListeners()
self.render()
}
render() {
let self = this
self.canvas.width = self.width
self.canvas.height = self.height
self.context = self.canvas.getContext('2d')
document.body.insertBefore(self.canvas, document.body.childNodes[0])
}
addComponent(component) {
this.centerComponent(component)
this.components.push(component)
}
addListeners() {
let self = this;
window.addEventListener('keydown', function(e) {
self.key = e.keyCode;
});
window.addEventListener('keyup', function(e) {
self.key = false;
});
}
fill(color) {
this.context.save();
this.context.fillStyle = color;
this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.context.restore();
}
clear() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
update() {
let self = this
let speed = { x : 0, y : 0 }
if (self.key) {
switch (self.key) {
case 37: // left arrow
speed.x = -5;
break;
case 38: // up arrow
speed.y = -5;
break;
case 39: // right arrow
speed.x = +5;
break;
case 40: // down arrow
default:
speed.y = +5;
}
}
self.fill('#DE7')
self.components.forEach(component => {
component.speed.x = speed.x
component.speed.y = speed.y
component.reposition(self.context)
component.redraw(self.context)
})
}
centerComponent(component) {
let xOffset = Math.floor((this.canvas.width / 2) - component.width / 2)
let yOffset = Math.floor((this.canvas.height / 2) - component.height / 2)
component.position = { x : xOffset, y : yOffset }
}
};
class Component {
constructor(options) {
let self = this
self.width = options.width
self.height = options.height
self.position = options.position
self.color = options.color
self.type = options.type
self.speed = { x : 0, y : 0 }
self.gravity = { x : 0, y : 0.05 };
self.acceleration = { x : 0, y : 0 };
}
redraw(context) {
context.fillStyle = this.color;
context.fillRect(this.position.x, this.position.y, this.width, this.height);
}
reposition(context) {
let self = this
// Increase acceleration
self.acceleration.x += self.gravity.x;
self.acceleration.y += self.gravity.y;
// pos + speed + acceleration
self.position.x += self.speed.x + self.acceleration.x;
self.position.y += self.speed.y + self.acceleration.y;
self.checkBounds(context);
}
checkBounds(context) {
let self = this
let rockbottom = context.canvas.height - this.height
if (self.position.y > rockbottom) {
self.position.y = rockbottom
if (context.canvas.height - self.height && self.key == 38) {
self.position.y = self.speed.y
}
self.acceleration = { x : 0, y : 0 } // reset
}
}
}
main();
body {
background: #000;
}
I've been following W3schools tutorial on creating a JavaScript game in a canvas https://www.w3schools.com/graphics/game_obstacles.asp
I've got to the stage where they add an obstacle in. Currently, it has collision detection which stops the game when it hits the wall. I am trying to figure out a way to treat it like a wall where the box could hit it and no longer move that direction and continue the game, making the wall work.
I've previously tried detecting what direction hit the wall and stopping movement that direction, but when I hold down an arrow key it moves through it.
Heres what I've got so far: https://jsfiddle.net/j9cy1mne/1/
<body onload="startGame()">
<script>
var myGamePiece;
var myObstacle;
var speed = 3;
function startGame() {
myGamePiece = new component(30, 30, "red", 10, 120);
myObstacle = new component(10, 200, "green", 300, 120);
myGameArea.start();
}
var myGameArea = {
canvas: document.createElement("canvas"),
start: function() {
this.canvas.width = 480;
this.canvas.height = 270;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.interval = setInterval(updateGameArea, 20);
},
clear: function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop: function() {
clearInterval(this.interval);
}
}
function component(width, height, color, x, y) {
this.width = width;
this.height = height;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea.context;
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
this.crashWith = function(otherobj) {
var myleft = this.x;
var myright = this.x + (this.width);
var mytop = this.y;
var mybottom = this.y + (this.height);
var otherleft = otherobj.x;
var otherright = otherobj.x + (otherobj.width);
var othertop = otherobj.y;
var otherbottom = otherobj.y + (otherobj.height);
var crash = true;
if ((mybottom < othertop) || (mytop > otherbottom) || (myright < otherleft) || (myleft > otherright)) {
crash = false;
}
return crash;
}
}
function updateGameArea() {
if (myGamePiece.crashWith(myObstacle)) {
console.log("crash");
} else {
myGameArea.clear();
myObstacle.update();
myGamePiece.x += myGamePiece.speedX;
myGamePiece.y += myGamePiece.speedY;
myGamePiece.update();
}
}
document.onkeydown = checkKeyD;
function checkKeyD(e) {
e = e || window.event;
if (e.keyCode == '38') {
// up arrow
myGamePiece.speedY = -speed;
} else if (e.keyCode == '40') {
// down arrow
myGamePiece.speedY = speed;
} else if (e.keyCode == '37') {
// left arrow
myGamePiece.speedX = -speed;
} else if (e.keyCode == '39') {
// right arrow
myGamePiece.speedX = speed;
}
}
document.onkeyup = clearmove;
function clearmove() {
myGamePiece.speedX = 0;
myGamePiece.speedY = 0;
}
</script>
</body>
The problem is here:
if (myGamePiece.crashWith(myObstacle)) {
console.log("crash");
} else {
In a real physics engine you detect collisions then you resolve collisions. The simplest "resolve collision" would be to move the piece back to the place it was before the crash. Something like:
if (myGamePiece.crashWith(myObstacle)) {
resolveCollision(myGamePiece, myObstacle);
} else {
But to do this you'll need to modify your physics engine, and your movement function to use a velocity vector. That means that instead of function checkKeyD(e) moving the piece, that function sets a velocity vector. Then crashWith() will determine if the position plus the velocity vector is going to crash and resolve collision will un-crash it.
I have taken an image and made it into my gamepiece put on a canvas, but I cannot get it to rotate properly. I apologize if my code is not very organized just got a little bit hurried. The problem will lie in the component function. Thank you for your help!
var myGamePiece;
function startGame() {
myGamePiece = new component(40, 40, "character.png", 300, 300, "image");
myGameArea.start();
}
var myGameArea = {
canvas: document.createElement("canvas")
, start: function () {
this.canvas.width = 640;
this.canvas.height = 480;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.frameNo = 0;
this.interval = setInterval(updateGameArea, 20);
window.addEventListener('keydown', function (e) {
e.preventDefault();
myGameArea.keys = (myGameArea.keys || []);
myGameArea.keys[e.keyCode] = (e.type == "keydown");
})
window.addEventListener('keyup', function (e) {
myGameArea.keys[e.keyCode] = (e.type == "keydown");
})
}
, stop: function () {
clearInterval(this.interval);
}
, clear: function () {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function component(width, height, color, x, y, type) {
this.type = type;
if (type == "image") {
this.image = new Image();
this.image.src = color;
}
this.width = width;
this.height = height;
this.speed = 0;
this.angle = 0;
this.moveAngle = 0;
this.x = x;
this.y = y;
this.update = function () {
ctx = myGameArea.context;
if (type == "image") {
ctx.save();
ctx.rotate(this.angle);
ctx.drawImage(this.image, this.x, this.y, this.width, this.height);
ctx.restore();
} else {
ctx.save();
ctx.translate(this.x, this.y);
ctx.fillStyle = color;
ctx.fillRect(this.width / -2, this.height / -2, this.width, this.height);
}
}
this.newPos = function () {
this.angle += this.moveAngle * Math.PI / 180;
this.x += this.speed * Math.sin(this.angle);
this.y -= this.speed * Math.cos(this.angle);
}
this.hitBottom = function () {
var bottom = myGameArea.canvas.height - 20;
if (this.y > bottom) {
this.y = this.y - 2.5;
}
}
this.hitTop = function () {
if (this.y < 20) {
this.y = this.y + 2.5;
}
}
this.hitLeft = function () {
if (this.x < 20) {
this.x = this.x + 2.5;
}
}
this.hitRight = function () {
var side = myGameArea.canvas.width - 20;
if (this.x > side) {
this.x = this.x - 2.5;
}
}
}
function updateGameArea() {
myGameArea.clear();
myGamePiece.moveAngle = 0;
myGamePiece.speed = 0;
if (myGameArea.keys && myGameArea.keys[37]) {
myGamePiece.moveAngle = -2.5;
}
if (myGameArea.keys && myGameArea.keys[39]) {
myGamePiece.moveAngle = 2.5;
}
if (myGameArea.keys && myGameArea.keys[38]) {
myGamePiece.speed = 2.5;
}
if (myGameArea.keys && myGameArea.keys[40]) {
myGamePiece.speed = -1;
}
myGamePiece.newPos();
myGamePiece.update();
myGamePiece.hitBottom();
myGamePiece.hitTop();
myGamePiece.hitLeft();
myGamePiece.hitRight();
}
I have start develop small JavaScript game with canvas.
So i need to display multiple cards in the canvas.
But i seems, after i use gameArea.clear(); method within updateGameArea() function one card isn't display. But without using that gameArea.clear(); method those cards are displaying well. But i need multiple cards.
Here my JavaScript code
var cards = [];
var selectedCards = [];
var select = true;
window.addEventListener('DOMContentLoaded', function () {
startGame();
});
function startGame() {
cards.push(new PlayingCard("blue", 5, 150, 10));
cards.push(new PlayingCard("red", 1, 10, 10));
gameArea.click();
gameArea.start();
}
var gameArea = {
canvas: document.createElement("canvas"),
start: function () {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.interval = setInterval(updateGameArea, 100);
},
click: function () {
this.canvas.addEventListener('click', getPosition);
},
clear: function () {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
};
function getPosition(e) {
var top = this.offsetTop;
var left = this.offsetLeft;
var x = e.pageX - left;
var y = e.pageY - top;
cards.forEach(function (card) {
if (y > card.y && y < card.y + card.height && x > card.x && x < card.x + card.width) {
card.selected = select;
if (selectedCards.length < 2) {
selectedCards.push(card);
} else {
selectedCards = [];
selectedCards.push(card);
}
if (selectedCards.length === 2) {
selectedCards.forEach(function (selected_card) {
selected_card.x = 400;
if (selected_card.selected === select) {
console.log(selected_card);
}
});
}
}
});
}
function PlayingCard(color, value, x, y) {
this.color = function () {
if (color === 'red') {
return "#E53935";
} else if (color === 'blue') {
return "#0D47A1";
} else {
throw new Error("No Color Code Found!");
}
};
this.value = value;
this.width = 120;
this.height = 160;
this.x = x;
this.y = y;
this.selected = false;
this.update = function () {
var ctx = gameArea.context;
ctx.fillStyle = this.color();
ctx.shadowBlur = 8;
ctx.shadowColor = 'rgba(0, 0, 0, 0.5)';
ctx.fillRect(this.x, this.y, this.width, this.height);
};
}
function updateGameArea() {
cards.forEach(function (card) {
gameArea.clear();
card.update();
});
}
You are calling gameAera.clear() each time you draw a card. So this is why only the last card is displayed.
function updateGameArea() {
gameArea.clear(); // Move the gameArea.clear(); here
cards.forEach(function (card) {
card.update();
});
}