Canvas drawImage is inexplicably offset by 1 Pixel - javascript

I'm working on a canvas game that's using a sprite sheet for the character.
The dimensions of character is 64px wide and 128px high with 10 frames per animation.
So the total width of a single animation is 640px wide and 128px high.
However when I use the following code, The animation is offset by 1px, Sometimes flashing when I hold down a movement key.
player.width = 64;
player.height = 128;
player.x = canvas.width / 2;
player.y = canvas.height / 2;
ctx.drawImage(
LoadedImages.player_sprite,
64, // This is offset by 1px when moving. 63px fixes it.
128,
player.width,
player.height,
player.x,
player.y,
player.width,
player.height
);
Here's a picture of what happens:
Changing the width to 63 seems to fix the problem, But it doesn't explain why it's doing it in the first place.
The full code is available on Codepen
http://codepen.io/Codewoofy/pen/QNGLNj
Sprite Sheet:
Full Code:
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
// jQuery Objects
var $canvas = $("#canvas");
var $debug = $("#debug");
var KEY = {
W: 1,
UP: 38,
LEFT: 39,
RIGHT: 37,
SPACE: 32,
SHIFT: 16
};
var COLOR = {
DARKRED: "#9C1E33",
WHITE: "#FFFFFF"
}
var MESSAGE = {
UNDEFINED: "",
PRELOAD_ATTEMPT: "Attempting to preload: ",
ERROR_IMAGE_PRELOAD: "Unable to preload images.",
SUCCESS_IMAGE_PRELOAD: "Images successfully preloaded."
}
// Images
var Images = {
player_sprite: "http://h.dropcanvas.com/30npe/Talia-Sheet-Fix.png",
main_background: "http://h.dropcanvas.com/9kgs1/background_main.png"
}
var LoadedImages = {};
// Dictionaries.
var game = {};
game.enviroment = {};
game.canvas = $canvas[0];
game.canvas.height = 500;
game.canvas.width = 700;
var ctx = game.canvas.getContext('2d');
var player = {};
// Debug
game.debug = function(msg) {
if (msg == "") msg = MESSAGE.UNDEFINED;
$debug.prepend(msg + "<br />");
}
// Preloader.
game.loadImages = function() {
LoadedImages = {};
Object.keys(Images).forEach(function(path) {
game.debug(MESSAGE.PRELOAD_ATTEMPT + path);
var img = new Image;
img.onload = function() {
LoadedImages[path] = img;
if (Object.keys(LoadedImages).length == Object.keys(Images).length) {
game.onImagesLoaded();
}
}
img.onerror = function() {
game.onFailedPreload();
}
img.src = Images[path];
});
}
game.onFailedPreload = function() {
game.debug(MESSAGE.ERROR_IMAGE_PRELOAD);
}
game.onImagesLoaded = function() {
game.debug(MESSAGE.SUCCESS_IMAGE_PRELOAD);
game.game_update();
}
game.onLoad = function() {
// Game settings
game.keys = [];
game.running = false;
game.lastUpdate = 0;
// Enviroment
game.enviroment.gravity = 0.5;
game.enviroment.friction = 0.9;
// Player settings
player.name = "Talia";
player.color = COLOR.DARKRED;
player.direction = 'L';
player.width = 64;
player.height = 128;
player.speed = 4;
player.walkspeed = 4;
player.sprintspeed = 10;
player.jumping = false;
player.animation_frame = 0;
player.velX = 0;
player.velY = 0;
player.x = 0;
player.y = 0;
// Player Stats
player.health = 100;
player.mana = 100;
player.maxhealth = 100;
player.maxmana = 100;
game.loadImages();
}
/* Update the game every frame */
game.game_update = function() {
// Sprint
if (game.keys[KEY.SHIFT]) {
console.log(LoadedImages);
player.speed = player.sprintspeed;
} else {
player.speed = player.walkspeed;
}
// Jump
if (game.keys[KEY.UP] || game.keys[KEY.SPACE]) {
if (!player.jumping) {
player.jumping = true;
player.velY = -player.walkspeed * 2;
}
}
// Left
if (game.keys[KEY.LEFT]) {
player.direction = "L";
if (player.velX < player.speed) {
player.velX++;
}
}
// Right
if (game.keys[KEY.RIGHT]) {
player.direction = "R";
if (player.velX > -player.speed) {
player.velX--;
}
}
// Gravity and Friction
player.velX *= game.enviroment.friction;
player.velY += game.enviroment.gravity;
player.x += player.velX;
player.y += player.velY;
// Collisions
// LEFT RIGHT
if (player.x >= game.canvas.width - player.width) { // Check Right Collision
player.x = game.canvas.width - player.width;
} else if (player.x <= 0) { // Check Left Collision
player.x = 0;
}
// UP DOWN
if (player.y >= game.canvas.height - player.height) {
player.y = game.canvas.height - player.height;
player.jumping = false;
}
// Draw Objects
game.draw_background();
game.draw_player();
// Request next animation frame
requestAnimationFrame(game.game_update);
}
game.draw_player = function() {
ctx.beginPath();
ctx.drawImage(LoadedImages.player_sprite, 64, 128, player.width, player.height, player.x, player.y, player.width, player.height);
/*
if (player.direction == "R") {
ctx.drawImage(LoadedImages.player_sprite, 65, 128, player.width, player.height, player.x, player.y, player.width, player.height);
} else if (player.direction == "L") {
ctx.drawImage(LoadedImages.player_sprite, 63, 0, player.width, player.height, player.x, player.y, player.width, player.height);
}
*/
ctx.closePath();
}
game.draw_background = function() {
ctx.beginPath();
ctx.clearRect(0, 0, game.canvas.width, game.canvas.height);
ctx.closePath();
}
game.draw_UI = function() {
ctx.beginPath();
ctx.closePath();
}
/* Listeners */
document.body.addEventListener("keydown", function(e) {
game.keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function(e) {
game.keys[e.keyCode] = false;
});
/* Load Game */
window.addEventListener("load", function() {
game.onLoad();
});
body,
html {
position: relative;
}
canvas {
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="canvas" width="700" height="500"></canvas>Use Arrow keys to move.
<p id="debug"><p>

The issue seems to be that your player.x is a float. That way is hard to account for pixel perfect paints.
Round player.x on the drawImage() or when you update the value with velocity.
Using a bitwise operator, you could simply do:
player.x += player.velX | 0;

Related

Snake food collision detection

I am making a snake game with plain javascript. But now I have come to the food part of the game. but I just cant get it to work properly. I have an food function that generates random cords within the gamefield and then draws the food. This is already quite wonky at the first place. but then I want to detect of the snake cords and foodcords match up with a margin of 20px. but I just cant get it to word smoothly together.
Can anyone maybe help me figure out what is going wrong and how I can fix this? Thanks!
let canvas = document.getElementById("canvas");
let movespeedX = 2;
let movespeedY = 0;
var canvasContext = canvas.getContext('2d');
//newest cord
let locationX = 20;
let locationY = 20;
//cords up to snakelength
let cords = [
{X: 5, Y: 5}
];
let snakeLength = 5;
//food location
let foodX;
let foodY;
let isfood = false;
//onload draw, move and set food
window.onload = function() {
setInterval(callField => {draw(); move(); food()}, 1000/60);
//keyboard controls
document.addEventListener('keydown', event => {
const key = event.key.toLowerCase();
if(key == "w" || key == "arrowup")
{
movespeedX = 0;
movespeedY = -2;
}
if(key == "s" || key == "arrowdown")
{
movespeedX = 0;
movespeedY = 2;
}
if(key == "a" || key == "arrowleft")
{
movespeedY = 0;
movespeedX = -2;
}
if(key == "d" || key == "arrowright")
{
movespeedY = 0;
movespeedX = 2;
}
});
}
function move()
{
//add movespeed to location to move all directions
locationX += movespeedX;
locationY += movespeedY;
//if a wall is hit restart
if(cords[0].X >= canvas.width || cords[0].X <= 0 || cords[0].Y >= canvas.height || cords[0].Y < 0)
{
restart();
}
//if food is hit with 20px margin (this is currently verry trippy and does not work)
if(foodY+20 > cords[0].X && foodY+20 > cords[0].Y)
{
isfood = false;
snakeLength += 5;
}
//update cords array with newest location
cords.unshift({X: locationX, Y: locationY});
if(cords.length > snakeLength)
{
delete cords[snakeLength];
}
}
function draw()
{
//draw canvas
drawRect(0,0,canvas.width,canvas.height,"black");
//draw food
drawCircle(foodX, foodY, 20, "red");
//draw snake
cords.forEach(element => {
drawCircle(element.X+20,element.Y,20,"white");
});
}
//reset to standard values
function restart()
{
locationX = 20;
locationY = 20;
movespeedX = 0;
movespeedY = 0;
snakeLength = 1;
cords = [
{X: 0, Y: 0}
];
}
//if the is no food, generate new cords and set food to true
function food()
{
if(isfood === false)
{
foodX = Math.floor(Math.random() * canvas.width) + 50;
foodY = Math.floor(Math.random() * canvas.height) + 50;
isfood = true;
}
}
function drawRect(leftX, topY, width, height, color)
{
canvasContext.fillStyle = color;
canvasContext.fillRect(leftX, topY, width, height);
}
function drawCircle(leftX,topY,radius,color)
{
canvasContext.fillStyle = color;
canvasContext.beginPath();
canvasContext.arc(leftX,topY,radius,0,Math.PI*2,true);
canvasContext.fill()
}```
Use Pythagorean theorem to find the distance of two objects then for circles account the radius plus any additional buffer you may want.
So something like
if (distance < objects.radius + other.objects.radius) {
return true
}
Here's your code
let canvas = document.getElementById("canvas");
let movespeedX = 2;
let movespeedY = 0;
var canvasContext = canvas.getContext("2d");
canvas.width = innerWidth;
canvas.height = innerHeight;
//newest cord
let locationX = 20;
let locationY = 20;
//cords up to snakelength
let cords = [{ X: 5, Y: 5 }];
let snakeLength = 5;
//food location
let foodX;
let foodY;
let isfood = false;
//onload draw, move and set food
window.onload = function () {
setInterval((callField) => {
draw();
move();
food();
}, 1000 / 60);
//keyboard controls
document.addEventListener("keydown", (event) => {
const key = event.key.toLowerCase();
if (key == "w" || key == "arrowup") {
movespeedX = 0;
movespeedY = -2;
}
if (key == "s" || key == "arrowdown") {
movespeedX = 0;
movespeedY = 2;
}
if (key == "a" || key == "arrowleft") {
movespeedY = 0;
movespeedX = -2;
}
if (key == "d" || key == "arrowright") {
movespeedY = 0;
movespeedX = 2;
}
});
};
function move() {
//add movespeed to location to move all directions
locationX += movespeedX;
locationY += movespeedY;
//if a wall is hit restart
if (
cords[0].X >= canvas.width ||
cords[0].X <= 0 ||
cords[0].Y >= canvas.height ||
cords[0].Y < 0
) {
restart();
}
//if food is hit with 20px margin (this is currently verry trippy and does not work)
let dx = foodX - cords[0].X;
let dy = foodY - cords[0].Y;
let dist = Math.hypot(dx, dy);
if (dist < 60) {
isfood = false;
snakeLength += 5;
}
//update cords array with newest location
cords.unshift({ X: locationX, Y: locationY });
if (cords.length > snakeLength) {
delete cords[snakeLength];
}
}
function draw() {
//draw canvas
drawRect(0, 0, canvas.width, canvas.height, "black");
//draw food
drawCircle(foodX, foodY, 20, "red");
//draw snake
cords.forEach((element) => {
drawCircle(element.X + 20, element.Y, 20, "white");
});
}
//reset to standard values
function restart() {
locationX = 20;
locationY = 20;
movespeedX = 0;
movespeedY = 0;
snakeLength = 1;
cords = [{ X: 0, Y: 0 }];
}
//if the is no food, generate new cords and set food to true
function food() {
if (isfood === false) {
foodX = Math.floor(Math.random() * canvas.width) + 50;
foodY = Math.floor(Math.random() * canvas.height) + 50;
isfood = true;
}
}
function drawRect(leftX, topY, width, height, color) {
canvasContext.fillStyle = color;
canvasContext.fillRect(leftX, topY, width, height);
}
function drawCircle(leftX, topY, radius, color) {
canvasContext.fillStyle = color;
canvasContext.beginPath();
canvasContext.arc(leftX, topY, radius, 0, Math.PI * 2, true);
canvasContext.fill();
}
<canvas id="canvas"></canvas>

How to stop key input from blocking the movement of an object drawn on the canvas?

So i have a simple html5 canvas render loop and I'm handling keydown and keyup.
A rectangle drawn on the screen can move left,right, up and down.
The problem is when you move left and right in succession, the rectangle seems to stop for a very long time, like it's being interrupted and I just want it to have a more smooth transition towards the opposite direction.
Even just changing any direction causes the rectangle to stop.
here's the Jsfiddle: https://jsfiddle.net/NeuroTypicalCure/sq6czebr/39/
let canvas = document.getElementById('c');
let ctx = canvas.getContext('2d');
canvas.width = 800;
canvas.height = 600;
let input = {
key: null,
directions: {
up: 1.5,
down: 0.5,
left: 1,
right: 2
}
}
let player = {
x: 0,
y: 0,
direction: null,
speed: 5
}
// start
draw();
function draw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
if(input.key === 'w'){
player.direction = input.directions.up;
}
if(input.key === 's'){
player.direction = input.directions.down;
}
if(input.key === 'a'){
player.direction = input.directions.left;
}
if(input.key === 'd'){
player.direction = input.directions.right;
}
// keyup -> speed 0 // else -> speed 5
if(input.key === null){
player.speed = 0;
}else{
player.speed = 5;
}
player.x += Math.cos(player.direction*Math.PI)*player.speed;
player.y += Math.sin(player.direction*Math.PI)*player.speed;
ctx.fillRect(player.x,player.y,50,50);
requestAnimationFrame(draw);
}
function handleKeyDown(e){
e.preventDefault();
input.key = e.key
}
function handleKeyUp(e){
e.preventDefault();
input.key = null;
}
window.addEventListener('keydown',handleKeyDown);
window.addEventListener('keyup',handleKeyUp);
Your problem lies with the fact that you can hold multiple keys at the same time, your logic should reflect that. i.e.:
https://jsfiddle.net/danfoord1/cr84xh2n/19/
let canvas = document.getElementById('c');
let ctx = canvas.getContext('2d');
canvas.width = 800;
canvas.height = 600;
let input = {
keys: [],
directions: {
up: 1.5,
down: 0.5,
left: 1,
right: 2
}
}
let player = {
x: 0,
y: 0,
directions: [],
speed: 5
}
const directions = {
'w': 1.5,
's': 0.5,
'a': 1,
'd': 2
};
// start
draw();
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// keyup -> speed 0 // else -> speed 5
if (input.keys.length === 0) {
player.speed = 0;
} else {
player.speed = 5;
}
player.directions = input.keys.map(k => directions[k]);
player.directions.forEach(d => {
player.x += Math.cos(d * Math.PI) * player.speed;
player.y += Math.sin(d * Math.PI) * player.speed;
});
ctx.fillRect(player.x, player.y, 50, 50);
requestAnimationFrame(draw);
}
function handleKeyDown(e) {
e.preventDefault();
if (input.keys.indexOf(e.key) === -1) {
input.keys.push(e.key);
}
}
function handleKeyUp(e) {
e.preventDefault();
if (input.keys.indexOf(e.key) > -1) {
input.keys.splice(input.keys.indexOf(e.key), 1);
}
}
window.addEventListener('keydown', handleKeyDown);
window.addEventListener('keyup', handleKeyUp);
The problem with your code lies in your handling of keyup events:
function handleKeyUp(e){
e.preventDefault();
input.key = null;
}
You're basically reseting input.key whenever a key is released, no matter if it's a different key than the one that initiated the move. So if you press two keys and then release one, it will reset input.key (until your computer sent another keydown event - if you're still holding down the key). This can be fixed with a simple check if the keyup event belongs to the current input.key.
function handleKeyUp(e){
e.preventDefault();
if (e.key === input.key) input.key = null;
}
Here's a code snippet:
let canvas = document.getElementById('c');
let ctx = canvas.getContext('2d');
canvas.width = 800;
canvas.height = 600;
let input = {
key: null,
directions: {
up: 1.5,
down: 0.5,
left: 1,
right: 2
}
}
let player = {
x: 0,
y: 0,
direction: null,
speed: 5
}
// start
draw();
function draw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
if(input.key === 'w'){
player.direction = input.directions.up;
}
if(input.key === 's'){
player.direction = input.directions.down;
}
if(input.key === 'a'){
player.direction = input.directions.left;
}
if(input.key === 'd'){
player.direction = input.directions.right;
}
// keyup -> speed 0 // else -> speed 5
if(input.key === null){
player.speed = 0;
}else{
player.speed = 5;
}
player.x += Math.cos(player.direction*Math.PI)*player.speed;
player.y += Math.sin(player.direction*Math.PI)*player.speed;
ctx.fillRect(player.x,player.y,50,50);
requestAnimationFrame(draw);
}
function handleKeyDown(e){
e.preventDefault();
input.key = e.key
}
function handleKeyUp(e){
e.preventDefault();
if (e.key === input.key) input.key = null;
}
window.addEventListener('keydown',handleKeyDown);
window.addEventListener('keyup',handleKeyUp);
canvas{
border: 1px solid aqua;
}
<!DOCTYPE html>
<html>
<body>
<canvas id="c"></canvas>
</body>
</html>

Rotate the user character on mouse position

I'm trying to get the character to rotate the character object based on where the mouse is.
So far I got it to rotate incrementally without mouse position. I was checking if it effected my zombie's chasing capabilities.
My script
let player, zombie, mouseX, mouseY;;
let bgCanvas = document.getElementById('backgroundCan');
function startGame() {
document.getElementById("startScreen").style.display = "none";
player = new playerComponent(350, 220);
zombie = new zombieComponent(750, 220);
gameArea.start();
}
let gameArea = {
canvas : document.createElement("canvas"),
start : function() {
this.canvas.width = 800;
this.canvas.height = 500;
this.canvas.style = "position: absolute";
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[2]);
this.interval = setInterval(updateArea, 20);
window.addEventListener('keydown', function (e) {
gameArea.keys = (gameArea.keys || []);
gameArea.keys[e.keyCode] = true;
})
window.addEventListener('keyup', function (e) {
gameArea.keys[e.keyCode] = false;
});
this.canvas.addEventListener("mousemove", function(e){
mouseX = e.clientX - ctx.canvas.offsetLeft;
mouseY = e.clientY - ctx.canvas.offsetTop;
});
this.canvas.addEventListener("mousedown", function(e){
let gShot = new Audio('assets/shot.mp3');
gShot.play();
var mX = e.clientX - ctx.canvas.offsetLeft;
var mY = e.clientY - ctx.canvas.offsetTop;
if(mX >= zombie.x && mX < zombie.x+zombie.w && mY >= zombie.y && mY < zombie.y+zombie.h){
if(zombie.health > 0){
zombie.health += -1;
zombie.speedX += 10;
zombie.newPos();
zombie.update();
}
else {
zombie.status = "dead";
}
}
});
},
clear : function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function playerComponent(x, y){
this.x = x;
this.y = y;
this.speedX = 0;
this.speedY = 0;
this.health = 10;
this.status = "alive";
let rotNum = 1;
this.update = function(){
ctx = gameArea.context;
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(rotNum * Math.PI / 180);
playerSprite = new Image();
playerSprite.src = "assets/playerGun.png";
ctx.drawImage(playerSprite, 0, 0);
ctx.restore();
rotNum++;
}
this.newPos = function() {
this.x += this.speedX;
this.y += this.speedY;
}
}
function updateArea() {
gameArea.clear();
if(player.status == "alive"){
player.speedX = 0;
player.speedY = 0;
if (gameArea.keys && gameArea.keys[65]) {
if(player.x > 20){
player.speedX = -3;
}
}
if (gameArea.keys && gameArea.keys[68]) {
if(player.x < 740){
player.speedX = 3;
}
}
if (gameArea.keys && gameArea.keys[87]) {
if(player.y > 20){
player.speedY = -3;
}
}
if (gameArea.keys && gameArea.keys[83]) {
if(player.y < 445){
player.speedY = 3;
}
}
player.newPos();
player.update();
}
if(zombie.status == "alive"){
if(zombie.x > player.x){
zombie.speedX = -1;
}
else{
zombie.speedX = 1;
}
if(zombie.y > player.y){
zombie.speedY = -1;
}
else{
zombie.speedY = 1;
}
zombie.newPos();
zombie.update();
}
else{
zombie.update();
}
}
So far, I have the mouse position on the canvas and am able to rotate the character, but I just don't how to connect the two. How should use the mouse position and the character position to rotate towards the mouse? The character is initially facing right (i think?), at least the sprite initially is.
Here's an image illustrating the situation:
You have the mouseY, playerY and mouseX, playerX
Therefore you can calculate the height and base of the triangle,
Thus the angle with
However, since in the second and third quadrants y/x will return an angle in the first and fourth quadrants, you need to use the Math.atan2(y,x) function in Javascript, not Math.atan(y/x). This will give you an angle between -180 and 180 instead of between -90 and 90.
Atan Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atan2
Then all you have to do is rotate based on the angle!
(P.S. Remember that you will have to convert between radians and degrees)

Can't Make a Player Two

I am trying to add a second player to javascript game but the code isn't working. I need some instruction on how to follow through with this. The second player doesn't need to be fancy, a different color square would suffice. My current player is the green square. Any information would be helpful thank you.
var myObstacle;
(function() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
function startGame() {}
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 700,
height =600,
player = {
x : 1,
y : 7,
width : 25,
height : 25,
speed: 10,
velX: 0,
velY: 0,
jumping: false
},
keys = [],
friction = .9,
gravity = .8;
canvas.width = width;
canvas.height = height;
function update(){
// check keys
if (keys[38] || keys[32]) {
// up arrow or space
if(!player.jumping){
player.jumping = true;
player.velY = -player.speed*.1;
}
}
if (keys[39]) {
// right arrow
if (player.velX < player.speed) {
player.velX++;
}
}
if (keys[37]) {
// left arrow
if (player.velX > -player.speed) {
player.velX--;
}
}
player.velX *= friction;
player.velY += gravity;
player.x += player.velX;
player.y += player.velY;
if (player.x >= width-player.width) {
player.x = width-player.width;
} else if (player.x <= 0) {
player.x = 0;
}
if(player.y >= height-player.height){
player.y = height - player.height;
player.jumping = false;
}
ctx.clearRect(0,0,width,height);
ctx.fillStyle = "green";
ctx.fillRect(player.x, player.y, player.width, player.height);
requestAnimationFrame(update);
}
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();
});
<html>
<head>
<title>Square Stairs™</title>
</head>
<body bgcolor="#000">
<canvas id="canvas" style="border:3px solid #fff"></canvas>
</body>
</html>
Please help if you can, Thank You.
Use a little bit of OOP:
var myObstacle;
(function() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
function Player(color){
this.x = 1;
this.y = 7
this.width = 25
this.height= 25
this.speed= 10
this.velX= 0
this.velY= 0
this.jumping= false
this.color = color;
}
function startGame() {}
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 700,
height =600,
player = new Player('green'),
player2 = new Player('red')
keys = [],
friction = .9,
gravity = .8;
canvas.width = width;
canvas.height = height;
function update(){
// check keys
if (keys[38] || keys[32]) {
// up arrow or space
if(!player.jumping){
player.jumping = true;
player.velY = -player.speed*.1;
}
}
if (keys[39]) {
// right arrow
if (player.velX < player.speed) {
player.velX++;
}
}
if (keys[37]) {
// left arrow
if (player.velX > -player.speed) {
player.velX--;
}
}
player.velX *= friction;
player.velY += gravity;
player.x += player.velX;
player.y += player.velY;
if (player.x >= width-player.width) {
player.x = width-player.width;
} else if (player.x <= 0) {
player.x = 0;
}
if(player.y >= height-player.height){
player.y = height - player.height;
player.jumping = false;
}
player2.velY += gravity;
player2.x += player2.velX;
player2.y += player2.velY;
if (player2.x >= width-player2.width) {
player2.x = width-player2.width;
} else if (player2.x <= 0) {
player2.x = 0;
}
if(player2.y >= height-player2.height){
player2.y = height - player2.height;
player2.jumping = false;
}
ctx.clearRect(0,0,width,height);
ctx.fillStyle = player.color;
ctx.fillRect(player.x, player.y, player.width, player.height);
ctx.fillStyle = player2.color;
ctx.fillRect(player2.x, player2.y, player2.width, player2.height);
requestAnimationFrame(update);
}
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();
});
<html>
<head>
<title>Square Stairs™</title>
</head>
<body bgcolor="#000">
<canvas id="canvas" style="border:3px solid #fff"></canvas>
</body>
</html>
Okay, I couldn't resist... I added even more OOP. So, now you can add as many players as you'd like. The important distinction is the color and the key mappings. My example (arbitrarily) adds three players:
var players=[];
players.push(new Player('green', {
32: 'jump',
37: 'left',
38: 'jump',
39: 'right'
}))
players.push(new Player('red', {
56: 'jump',
52: 'left',
54: 'right'
}, width-25))
players.push(new Player('blue', {
87: 'jump',
65: 'left',
68: 'right'
}, (width-25)/2))
var myObstacle;
(function() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
function startGame() {}
function Player(color,keymap,x) {
this.x = (typeof x === 'undefined') ? 1 : x;
this.y = 7;
this.width = 25;
this.height = 25;
this.speed = 10;
this.velX = 0;
this.velY = 0;
this.jumping= false;
this.keymap = {}
for (let key in keymap) {
switch (keymap[key]) {
case 'jump':
this.keymap[key] = this.jump
break;
case 'left':
this.keymap[key] = this.moveLeft
break;
case 'right':
this.keymap[key] = this.moveRight
break;
}
}
this.color = color;
} // Player()
Player.prototype.jump=function () {
if (!this.jumping) {
this.jumping = true;
this.velY = -this.speed*1.5;
}
}
Player.prototype.moveRight = function () {
if (this.velX < this.speed) {
this.velX++;
}
}
Player.prototype.moveLeft = function () {
if (this.velX > -this.speed) {
this.velX--;
}
}
// Globals
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 700,
height =600,
keys = [],
friction = .9,
gravity = .8;
canvas.width = width;
canvas.height = height;
// Set up players
var players=[];
players.push(new Player('green', {
32: 'jump',
37: 'left',
38: 'jump',
39: 'right'
}))
players.push(new Player('red', {
56: 'jump',
52: 'left',
54: 'right'
}, width-25))
players.push(new Player('blue', {
87: 'jump',
65: 'left',
68: 'right'
}, (width-25)/2))
function update() {
ctx.clearRect(0,0,width,height);
players.forEach(player => {
// check player-specific keys
for (let i in player.keymap)
{
if (keys[i] && typeof player.keymap[i] === 'function')
player.keymap[i].bind(player)();
}
player.velX *= friction;
player.velY += gravity;
player.x += player.velX;
player.y += player.velY;
if (player.x >= width-player.width) {
player.x = width-player.width;
} else if (player.x <= 0) {
player.x = 0;
}
if (player.y >= height-player.height) {
player.y = height - player.height;
player.jumping = false;
}
ctx.fillStyle = player.color;
ctx.fillRect(player.x, player.y, player.width, player.height);
}) // player.forEach
requestAnimationFrame(update);
}
document.body.addEventListener("keydown", function(e) {
// console.log(e.keyCode);
keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function(e) {
keys[e.keyCode] = false;
});
window.addEventListener("load",function(){
update();
});
html>
<head>
<title>Square Stairs™</title>
</head>
<body bgcolor="#000">
<canvas id="canvas" style="border:3px solid #fff"></canvas>
</body>
</html>

Moving character around on canvas but keping the character in the middle of the screen

I am making a 2d game in JavaScript but my character can only move around the length of the screen so I was wondering if there was a way to make the canvas move but my character stay on the middle of the screen?
This is what I am trying to get it to work like, this is how terrible the game is right now, just because I was trying out a few game mechanics.
Here is my code for the test game
var audio = new Audio('billischill.ddns.net/gameQuest/sounds/theServerRoom.mp3');
audio.play();
// Create the canvas
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);
// Background image
var bgReady = false;
var bgImage = new Image();
bgImage.onload = function() {
bgReady = true;
};
bgImage.src = "billischill.ddns.net/gameQuest/images/gamemap.png";
//computer
var computerReady = false;
var computerImage = new Image();
computerImage.onload = function() {
computerReady = true;
};
computerImage.src ="billischill.ddns.net/gameQuest/images/computer1.png";
//hp box
var hpBoxReady = false;
var hpBoxImage = new Image();
hpBoxImage.onload = function() {
hpBoxReady = true;
};
hpBoxImage.src = "billischill.ddns.net/gameQuest/images/hpbox.png";
// player image
var playerReady = false;
var playerImage = new Image();
playerImage.onload = function() {
playerReady = true;
};
playerImage.src = "billischill.ddns.net/gameQuest/images/char.png";
// enemy image
var enemyReady = false;
var enemyImage = new Image();
enemyImage.onload = function() {
enemyReady = true;
};
enemyImage.src = "billischill.ddns.net/gameQuest/images/enemy_idle01.png";
var computer = {
wifi: true,
x: 399,
y: 200
}
// Game objects
var hpBox = {
restoreHealth: 34,
x: 300,
y: 300
}
var player = {
hackingSkill : 10,
stamina: 7,
health: 100,
sprintSpeed: 400,
weakSpeed: 150,
speed: 300 // movement in pixels per second
};
var enemy = {
speed: 250,
viewDistance: 40
};
var enemysCaught = 0;
// Handle keyboard controls
var keysDown = {};
addEventListener("keydown", function(e) {
keysDown[e.keyCode] = true;
}, false);
addEventListener("keyup", function(e) {
delete keysDown[e.keyCode];
}, false);
// Reset the game when the player catches a enemy
var reset = function() {
player.x = canvas.width / 2;
player.y = canvas.height / 2;
// Throw the enemy somewhere on the screen randomly
enemy.x = 32 + (Math.random() * (canvas.width - 64));
enemy.y = 32 + (Math.random() * (canvas.height - 64));
};
//w is 87
//a is 65
//s is 83
//d is 68
// Update game objects
var update = function(modifier) {
if (87 in keysDown) { // Player holding up
player.y -= player.speed * modifier;
}
if (83 in keysDown) { // Player holding down
player.y += player.speed * modifier;
}
if (65 in keysDown) { // Player holding left
player.x -= player.speed * modifier;
}
if (68 in keysDown) { // Player holding right
player.x += player.speed * modifier;
}
if (
player.x <= (0)) {
player.health -= 1;
console.log('health decreasing');
}
}
if (
player.y <= (0)) {
player.health -= 1;
console.log('health decreasing');
};
// Are they touching?
if (
player.x <= (enemy.x + 32) &&
enemy.x <= (player.x + 32) &&
player.y <= (enemy.y + 32) &&
enemy.y <= (player.y + 32)
) {
++enemysCaught;
reset();
}
// Draw everything
var render = function() {
if (bgReady) {
context.drawImage(bgImage, 0, 0);
}
if (computerReady) {
context.drawImage(computerImage, computer.x, computer.y);
}
if (hpBoxReady) {
context.drawImage(hpBoxImage, hpBox.x, hpBox.y);
}
if (playerReady) {
context.drawImage(playerImage, player.x, player.y);
}
if (enemyReady) {
context.drawImage(enemyImage, enemy.x, enemy.y);
}
// Score
};
function dieEvent() {
player.health = 100;
}
function updateHealth() {
context.fillStyle = "white";
context.textAlign = "left";
context.fillText("Health: " + player.health, 30, 32);
context.fillStyle="#FF0000";
context.fillRect(10,10,(player.health/100)*140,25);
context.stroke();
}
function updateHackerSkill(){
context.fillStyle = "green";
context.textAlign = "left";
context.fillText("Health: " + player.hackerSkill, 30, 32);
context.fillStyle="#FF0000";
context.fillRect(10,10,(player.hackerSkill/100)*1,45);
context.stroke();
}
function isNearComputer() {
if (player.y <= (computer.y + enemy.viewDistance + 23) &&
player.y >= (computer.y - enemy.viewDistance) &&
player.x <= (computer.x + enemy.viewDistance + 32) &&
player.x >= (computer.x - enemy.viewDistance)) {
console.log("near computer");
context.fillStyle = "black";
context.fillRect(0, 0, canvas.width, canvas.height);
context.stroke();
context.fillStyle = "green";
context.font = "24px Helvetica";
context.textAlign = "left";
context.textBaseline = "top";
context.fillText("Welcome to uOS v1.0 " , 20 ,10);
window.setTimeout(500);
context.fillText("user$> " , 20 ,35);
}
}
function isNearHPBox() {
if (
player.y <= (hpBox.y + enemy.viewDistance + 64) &&
player.y >= (hpBox.y - enemy.viewDistance - 64) &&
player.x <= (hpBox.x + enemy.viewDistance + 64) &&
player.x >= (hpBox.x - enemy.viewDistance - 64)) {
console.log("healing!");
if (player.health <= 100) {
hpBox.restoreHealth = player.health - 100;
player.health += hpBox.restoreHealth;
}
}
}
function moveEnemy() {
if (
player.y <= (enemy.y + enemy.viewDistance + 64) &&
player.y >= (enemy.y - enemy.viewDistance - 64) &&
player.x <= (enemy.x + enemy.viewDistance + 64) &&
player.x >= (enemy.x - enemy.viewDistance - 64)) {
console.log("seen on enemys Y");
var audio = new Audio('sounds/theWanderer_Scream.m4a');
audio.play();
if (player.x >= (enemy.x)) {
enemy.x -= enemy.speed;
}
if (player.x >= (enemy.x)) {
enemy.x -= enemy.speed;
}
}
}
function checkWallCollision() {
if (player.y <= 0) {
console.log("y")
player.y += 64;
}
if (player.x <= 0) {
console.log("x")
player.x += 64;
}
if (enemy.y <= 0) {
console.log("y")
enemy.y += 64;
}
if (enemy.x <= 0) {
console.log("x")
enemy.x += 64;
}
}
// function updateMouseCoords(){
// document.onmousemove = function(e){
// cursorX = e.pageX;
// cursorY = e.pageY;
// context.fillStyle = "green";
// context.font = "24px Helvetica";
// context.textAlign = "left";
// context.textBaseline = "top";
// context.fillText("x" + cursorX + "y" + cursorY , 20 ,10);
//
// }
// }
// function drawViewLine(){
// var cursorX;
// var cursorY;
// context.beginPath();
// context.moveTo(player.x,player.y);
// context.lineTo(cursorX,cursorY);
// context.stroke();
// console.log("drawing line")
// }
function reducedSpeed() {
player.speed = player.weakSpeed;
}
// The main game loop
var main = function() {
var now = Date.now();
var delta = now - then;
update(delta / 1000);
context.clearRect(0, 0, canvas.width, canvas.height);
render();
updateHealth();
moveEnemy();
if (player.health <= 20) {
reducedSpeed();
} else {
player.speed = 300;
}
if (player.health <= 0) {
dieEvent();
}
checkWallCollision();
isNearHPBox();
isNearComputer();
//updateMouseCoords();
//drawViewLine();
then = now;
// Request to do this again ASAP
requestAnimationFrame(main);
};
// Cross-browser support for requestAnimationFrame
var w = window;
requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame;
// Let's play this game!
var then = Date.now();
reset();
main();
body {
margin: 0;
padding: 0;
}
<html>
<body>
<canvas id="canvas">
</canvas>
</body>
</html>

Categories

Resources