Can't Make a Player Two - javascript

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>

Related

problems with resizing sprites

I need to resize my spritesheet so it fits the correct dimensions of my game object. I have been looking around the internet and I found that this -ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);- is what i think i need to use. however, i do not know how or where to implement this in my code. i know how it works but i dont know where to put it or where in my code to put it. i use almost completely javascript
var myGamePiece;
var myObstacle;
var object1;
var objects;
var box;
function startGame() {
//creation of objects
wall = new component(30, 100, "black", 300, 200);
myGamePiece = new component(30, 30, "red", 240, 135);
myObstacle = new component(100, 100, "green", 200, 100);
object1 = new component(30, 30, "enemy.png", 340, 125, "image");
box = new component(30, 30, "box.png", 177, 145, "image");
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);
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);
},
collide : function() {
object1.x += 1;
object1.y += 1;
},
//what to do when pushing box
boxleft : function() {
box.x -= 1;
x -= 1;
}
}
function component(width, height, color, x, y, type) {
this.type = type;
if (type == "image") {
this.image = new Image();
this.image.src = color;
}
this.sx = x;
this.sy = y;
this.swidth = width;
this.sheight = height;
this.width = width;
this.height = height;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea.context;
if (type == "image") {
ctx.drawImage(this.image,
this.x,
this.y,
this.width,
this.height
);
} else {
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
this.newPos = function() {
this.x += this.speedX;
this.y += this.speedY;
}
//code for gray square
this.crashWith = function(object1) {
var myleft = this.x;
var myright = this.x + (this.width);
var mytop = this.y;
var mybottom = this.y + (this.height);
var otherleft = object1.x;
var otherright = object1.x + (object1.width);
var othertop = object1.y;
var otherbottom = object1.y + (object1.height);
var crash = true;
if ((mybottom < othertop) ||
(mytop > otherbottom) ||
(myright < otherleft) ||
(myleft > otherright)) {
crash = false;
}
return crash;
}
//code to push box
this.pushboxWith = function(box) {
const myleft = this.x;
const myright = this.x + (this.width);
const mytop = this.y;
const mybottom = this.y + (this.height);
const boxleft = box.x-2;
const boxright = box.x + (box.width)+2;
const boxtop = box.y+2;
const boxbottom = box.y + (box.height)-2;
var pushboxleft = true;
var pushboxright = true;
//test if pushing box
if ((myleft < boxright) && (mybottom >= boxtop) && (mytop <= boxbottom) && (myleft > boxleft)) {
pushboxleft = true;
} else {
pushboxleft = false;
}
return pushboxleft;
}
}
function updateGameArea() {
if (myGamePiece.crashWith(object1)) {
myGameArea.collide();
} else if (myGamePiece.pushboxWith(box)) {
myGameArea.boxleft();
} else {
myGameArea.clear();
myGamePiece.speedX = 0;
myGamePiece.speedY = 0;
//keyboard controls. moves everything but the player
if (myGameArea.key && myGameArea.key == 37) {
myObstacle.x += 2;
object1.x += 2;
box.x += 2;
wall.x += 2;
}
if (myGameArea.key && myGameArea.key == 39) {
myObstacle.x += -2;
object1.x += -2;
box.x += -2;
wall.x += -2;
}
if (myGameArea.key && myGameArea.key == 38) {
myObstacle.y += 2;
object1.y += 2;
box.y += 2;
wall.y += 2
}
if (myGameArea.key && myGameArea.key == 40) {
myObstacle.y += -2;
object1.y += -2;
box.y += -2;
wall.y += -2
}
//other square movement. disabled to isolate code.
/*
if (object1.x < myGamePiece.x) {
object1.x += 1;
}
if (object1.x > myGamePiece.x) {
object1.x += -1;
}
if (object1.y < myGamePiece.y) {
object1.y += 1;
}
if (object1.y > myGamePiece.y) {
object1.y += -1;
}
*/
/* object order: the object that is higher on the list
will be on top of objects lower on the list
*/
myObstacle.update();
myGamePiece.newPos();
myGamePiece.update();
wall.update();
object1.update();
box.update();
//end of list
}
}
i do use some html
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<style>
canvas {
border:1px solid #d3d3d3;
background-color: #f1f1f1;
}
</style>
</head>
<body onload="startGame()">
<script src="main.js"></script>
</body>
</html>
if you need to test my code you can find it here- https://eeeegame-2.octopuscat.repl.co/

i cant get my shot to travel directly to my cursor

I am making a 2d game with javascript and i can't get the shot to travel in a line directly to the cursor. I want it so when the shoot function is called th make the shot travel to the cursor and not alter the path when the cursor is moved after the shot is already out. Right now it is onnly going diagonal to the player
<!DOCTYPE html>
<html lang="en" onclick="shoot()">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta charset="utf-8">
<style>
canvas {
border:4px solid #000000;
background-color: #26af2d;
}
</style>
<body onload="startGame()">
<div name="buttonDiv">
<button type="button" id="startRoundBtn" onclick= startWave();>dont mind this</button>
</div>
<p id="demo">
</p>
<script>
let playerHealth = 100;
let shot = false;
let enemyOut = false;
let waveActive = false;
let enemyDmg = 25;
let playerImmuneTime = 0;
//start
var player;
var TopEdge;
var BottomEdge;
var RightEdge;
var LeftEdge;
let Enemy;
var projectile;
function startGame() {
player = new component(30, 30, "red", 10, 120);
TopEdge = new component(10000, 200, "purple", 0, -200);
BottomEdge = new component(10000, 1, "purple", 0, 500);
RightEdge = new component(1000, 500, "purple", 1150, 0);
LeftEdge = new component(1000, 500, "purple", -1000, 0);
var x = document.getElementById("startRoundBtn");
myGameArea.start();
}
//game area
var myGameArea = {
canvas : document.createElement("canvas"),
start : function() {
this.canvas.width = 1150;
this.canvas.height = 500;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas,
document.body.childNodes[0]);
this.interval = setInterval(updateGameArea, 10);
window.addEventListener('keydown', function (e) {
myGameArea.keys = (myGameArea.keys || []);
myGameArea.keys[e.keyCode] = (e.type == "keydown");
})
window.addEventListener('keyup', function (e) {
myGameArea.keys[e.keyCode] = (e.type == "keydown");
})
},
clear : function(){
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop : function(){
clearInterval(this.interval);
}
}
//coords
var pointerX = 0;
var pointerY = 0;
document.onmousemove = function(event) {
pointerX = event.pageX;
pointerY = event.pageY;
}
setInterval(pointerCheck, 1);
function pointerCheck() {
var cursorCoords = 'Cursor Location: '+pointerX+'X, '+pointerY+'Y health: ' + playerHealth + ' imune time:' +playerImmuneTime
document.getElementById("demo").innerHTML = cursorCoords;
}
//compenents
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);
}
//new pos
this.newPos = function() {
this.X += this.speedX;
this.Y += this.speedY;
}
//crashing
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;
}
}
//updates
function updateGameArea() {
myGameArea.clear();
if (playerHealth > 0) {
player.newPos();
player.update();
}
TopEdge.update();
BottomEdge.update();
RightEdge.update();
LeftEdge.update();
if (shot == true) {
projectile.update();
projectile.newPos();
projectile.speedX = 0;
projectile.speedY = 0;
}
if (enemyOut == true && playerHealth > 0) {
if (Enemy.crashWith(player) && playerImmuneTime <= 0) {
playerHealth = playerHealth -= enemyDmg;
playerImmuneTime = 50;
} if (playerImmuneTime >= 0) {
playerImmuneTime -= 1;
}
Enemy.newPos();
Enemy.update();
Enemy.speedX = 0;
Enemy.speedY = 0;
}
player.speedX = 0;
player.speedY = 0;
//movement
if (myGameArea.keys[65] ) {player.speedX = -2.5; }
if (myGameArea.keys[68] ) {player.speedX = 2.5; }
if (myGameArea.keys[87] ) {player.speedY = -2.5; }
if (myGameArea.keys[83] ) {player.speedY = 2.5; }
if (myGameArea.keys[82]) {waveActive = true;}
if (myGameArea.keys[75]) {waveActive = false;}
if (enemyOut == true && player.x >= Enemy.x) {Enemy.speedX = 1; }
if (enemyOut == true && player.x <= Enemy.x) {Enemy.speedX = -1; }
if (enemyOut == true && player.y >= Enemy.y) {Enemy.speedY = 1; }
if (enemyOut == true && player.y <= Enemy.y) {Enemy.speedY = -1; }
if (waveActive == true && enemyOut == false) {
createEnemy();
}
if (shot == true && pointerX > player.x) {projectile.speedX = 10};
if (shot == true && pointerX < player.x) {projectile.speedX = -10};
if (shot == true && pointerY > player.y) {projectile.speedY = 10};
if (shot == true && pointerY < player.y) {projectile.speedY = -10};
if (shot == true && enemyOut == true && projectile.crashWith(Enemy)) {
shot = false;
enemyOut = false;
waveActive = false;
}
//edges of game area
if (player.crashWith(TopEdge) && myGameArea.keys[87]) {
player.speedY = 0;
}
if (player.crashWith(RightEdge) && myGameArea.keys[68]) {
player.speedX = 0;
}
if (player.crashWith(BottomEdge) && myGameArea.keys[83]) {
player.speedY = 0;
}
if (player.crashWith(LeftEdge) && myGameArea.keys[65]) {
player.speedX = 0;
}
player.x += player.speedX;
player.y += player.speedY;
Enemy.x += Enemy.speedX;
Enemy.y += Enemy.speedY;
projectile.x += projectile.speedX;
projectile.y += projectile.speedY;
}
function createEnemy() {
Enemy = new component(30, 30, "purple",
Math.floor(Math.random() * 1100),
Math.floor(Math.random() * 500));
enemyOut = true;
}
function shoot() {
let midPlayerX = player.x + 12;
let midPlayerY = player.y + 12;
projectile = new component(5, 5, "white", midPlayerX, midPlayerY);
shot = true;
}
</script>
</body>
</html>
you need to 'freeze' the pointerX and pointerY values between the shot being fired and reaching its destination (otherwise those values will change on mousemove).
You already have shot=true when the projectile is launched so it can be read in a conditional you add to your mousemove event listener. That will take care of freezing the pointers when the projectile is fired :
document.onmousemove = function (event) {
if (!shot) {
pointerX = event.pageX
pointerY = event.pageY
} // prevent updates to pointers when shot is fired;
}
but you will need to reactivate the listener by setting shot to false when the projectile colides with the stored pointerX and pointerY values.

Using buttons as touchscreen controls for javascript game

I'm making a webpage that is just a place to take a break, and a lot of my users are on touchscreen, so I'm trying to implement touchscreen controls into the games, but it's not working and I cannot for the life of me figure out why. The arrow key controls still work, but not the buttons.
<canvas id="myCanvas" width="480" height="320" ></canvas>
<script>
function playGame() { var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var x = canvas.width/2;
var y = canvas.height-30;
var dx = 2;
var dy = -2;
var ballRadius = 10;
var paddleHeight = 10;
var paddleWidth = 75;
var paddleX = (canvas.width-paddleWidth) / 2;
var rightPressed = false;
var leftPressed = false;
var difficulty = 10
var score = 0
var gameRunning = false
var paused = false
function paddleMoveLeft(){ paddleX -= 5;
if (paddleX < 0){
paddleX = 0;
}}
function paddleMoveRight(){ paddleX += 5;
if (paddleX + paddleWidth > canvas.width){
paddleX = canvas.width - paddleWidth;
}}
function playPause(){
if(paused === true){paused = false}
else {paused = true}
}
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height-paddleHeight, paddleWidth, paddleHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function drawScore() {
ctx.font = "24px ";
ctx.fillStyle = "#0095DD";
ctx.fillText("Score: "+score, 8, 20);
}
function draw() {
if (paused === false){
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBall();
drawPaddle();
drawScore();
x += dx;
y += dy;
if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
dx = -dx;
}
if(y + dy < ballRadius) {
dy = -dy;
} else if(y + dy > canvas.height-ballRadius) {
if(x > paddleX && x < paddleX + paddleWidth) {
dy = -dy;
difficulty = difficulty + 0.5;
score = score + 1;
}
else {
alert("GAME OVER! you scored " + score);
ctx.clearRect(0, 0, canvas.width, canvas.height);
clearInterval(interval);
canvas.style.display = 'none';
}
}
if(rightPressed) {
paddleMoveRight();
}
else if(leftPressed) {
paddleMoveLeft();
}
}
}
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
function keyDownHandler(e) {
if(e.key == "Right" || e.key == "ArrowRight") {
rightPressed = true;
}
else if(e.key == "Left" || e.key == "ArrowLeft") {
leftPressed = true;
}
}
function keyUpHandler(e) {
if(e.key == "Right" || e.key == "ArrowRight") {
rightPressed = false;
}
else if(e.key == "Left" || e.key == "ArrowLeft") {
leftPressed = false;
}
}
var interval = setInterval(draw, difficulty);}
</script>
<div style = 'width: 30%; margin: auto;'>
<button style = 'font-size:large;' onclick = 'paddleMoveLeft()'> left</button>
<button style = 'font-size: large;' onclick = 'paddleMoveRight()'> right</button>
</div>
Any idea what's wrong?
Just by opening the console, it will tells you what's wrong.
So far, you call paddleMoveLeft in html but it's not globally defined, as it is inside the playGame method. About scope

Javscript animation is blinking

I am making a javascript game, and the animated sprite blinks when he moves i think it has to do with the speed of the animation because I also need to slow it down. here is my code for updateign the animation
var playerani = setInterval(function(){
if(animate == true){
if(aniframe == maxframes){
aniframe = 1
}else{
aniframe += 1;
}
}
if(controller.left == true){
animate = true;
window.aniimgY = 576;
}else if(controller.up == true){
animate = true;
window.aniimgY = 512;
}else if(controller.down == true){
animate = true;
window.aniimgY = 640;
}else if(controller.right == true){
animate = true;
window.aniimgY = 704;
}else{
animate = false;
aniframe = 0;
}
},10)
Here is The spritesheet
, And a Gif of the animation
You can test the game here
As #HanYolo suggested, set var maxframes = 8; :
var aniframe = 0;
var maxframes = 8;
var animate = false;
window.aniimg = document.getElementById("aniimg1")
var timer = null;
var aniTimer = null;
var levelnum = 0;
var img = document.getElementById("img")
var img2 = document.getElementById("img2")
var c = document.getElementById("c");
var ctx = c.getContext('2d')
var props = document.getElementById("props");
var prps = c.getContext('2d')
var tilesize = 32;
var tiles = 10;
player = {
size: 10,
x: 150,
y: 150,
v: 2,
}
controller = {
up: false,
right: false,
left: false,
down: false,
keyParse: function(key) {
switch (key) {
//keydowns
case 38:
this.up = true;
break;
case 37:
this.left = true;
break;
case 39:
this.right = true;
break;
case 40:
this.down = true;
break;
}
},
keyStop: function(key) {
switch (key) {
//keydowns
case 38:
this.up = false;
break;
case 37:
this.left = false;
break;
case 39:
this.right = false;
break;
case 40:
this.down = false;
break;
}
}
}
function drawlvl() {
for (y = 0; y < lvl[levelnum].length; y++) {
for (x = 0; x < lvl[levelnum][y].length; x++) {
switch (lvl[levelnum][y][x]) {
case 0:
//nw grass
var imgvar = img
var sx = 32;
var sy = 192;
break;
case 1:
//w dirt
var imgvar = img
var sx = 224;
var sy = 160;
break;
case 2:
//nw top dirt
var imgvar = img
var sx = 128;
var sy = 96;
break;
case 3:
//nw bottom dirt
var imgvar = img2
var sx = 95;
var sy = 320;
break;
case 4:
//lvl up dirt
var imgvar = img
var sx = 224;
var sy = 160;
break;
case 5:
//lvl down dirt
var imgvar = img
var sx = 224;
var sy = 160;
break;
case 6:
//w water
var imgvar = img
var sx = 0;
var sy = 416;
break;
case 7:
//w water side left
var imgvar = img
var sx = 0;
var sy = 288;
break;
case 8:
//w water side right
var imgvar = img2
var sx = 223;
var sy = 128;
break;
}
ctx.drawImage(imgvar, sx, sy, 32, 32, x * tilesize, y * tilesize, tilesize, tilesize)
}
}
}
walkable_blocks = [1, 6, 7, 8]
walkable_props = [0, 8, 9, 10, 11, 12]
lvlup_blocks = [4]
lvldown_blocks = [5]
function gameLoop() {
if (controller.up == true) {
player.newY = player.y - player.v
} else if (controller.left == true) {
player.newX = player.x - player.v
} else if (controller.right == true) {
player.newX = player.x + player.v
} else if (controller.down == true) {
player.newY = player.y + player.v
} else {
player.newY = player.y;
player.newX = player.x;
}
function playerani() {
if (animate == true) {
if (aniframe == maxframes) {
aniframe = 1
} else {
aniframe += 1;
}
}
if (window.aniimgY == null) {
window.aniimgY = 640;
}
if (controller.left == true) {
animate = true;
window.aniimgY = 576;
} else if (controller.up == true) {
animate = true;
window.aniimgY = 512;
} else if (controller.down == true) {
animate = true;
window.aniimgY = 640;
} else if (controller.right == true) {
animate = true;
window.aniimgY = 704;
} else {
animate = false;
aniframe = 0;
}
}
player.col = Math.floor((player.newX + 5) / tilesize)
player.row = Math.floor((player.newY + 5) / tilesize)
tileval = lvl[levelnum][player.row][player.col]
propval = propsArr[levelnum][player.row][player.col]
ctx.fillStyle = "black"
if (walkable_blocks.includes(tileval) && walkable_props.includes(propval)) {
player.y = player.newY;
player.x = player.newX;
if (player.x <= 0) {
player.x = 0
}
if (player.y <= 0) {
player.y = 0
}
if (player.x + player.size >= c.width) {
player.x = c.width - player.size;
}
if (player.y + player.size >= c.height) {
player.y = c.height - player.size;
}
} else if (lvlup_blocks.includes(tileval)) {
document.getElementById("body").style.ainmation = "fadeInAnimation";
document.getElementById('body').style.animationPlayState = "running";
if (timer == null) {
timer = setTimeout(function() {
levelnum++;
player.x = 280;
player.y = 150;
timer = null;
}, 2500)
if (aniTimer == null) {
aniTimer = setTimeout(function() {
document.getElementById("body").style.animationPlayState = "paused";
clearTimeout(aniTimer)
aniTimer = null;
}, 5000)
}
} else {
}
} else if (lvldown_blocks.includes(tileval)) {
document.getElementById("body").style.ainmation = "fadeInAnimation";
document.getElementById('body').style.animationPlayState = "running";
if (timer == null) {
timer = setTimeout(function() {
levelnum--;
player.x = 33;
player.y = 150;
timer = null;
}, 2500)
}
if (aniTimer == null) {
aniTimer = setTimeout(function() {
document.getElementById("body").style.animationPlayState = "paused";
clearTimeout(aniTimer);
aniTimer = null;
}, 5000)
}
} else {
player.y = player.y;
player.x = player.x;
if (player.x <= 0) {
player.x = 0
}
if (player.y <= 0) {
player.y = 0
}
if (player.x + player.size >= c.width) {
player.x = c.width - player.size;
}
if (player.y + player.size >= c.height) {
player.y = c.height - player.size;
}
}
ctx.fillRect(0, 0, c.width, c.height)
drawlvl()
drawprops()
drawEnemy()
playerani()
ctx.drawImage(window.aniimg, 64 * (Math.floor(aniframe)), window.aniimgY, 64, 64, player.x - 16, player.y - 16, 48, 48)
}
var gameintertval = setInterval(function() {
gameLoop()
}, 10)
document.addEventListener('keydown', function(event) {
controller.keyParse(event.keyCode)
})
document.addEventListener('keyup', function(event) {
controller.keyStop(event.keyCode)
})
body {
zoom: 100%;
animation: fadeInAnimation ease 5s;
animation-play-state: paused;
animation-iteration-count: infinite;
}
#keyframes fadeInAnimation {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
canvas{
position: absolute;
}
#props{
z-index: 1000;
}
#c{
z-index: -1000;
}
<html>
<head>
<title>TileGame</title>
<base href="http://ryangrube.com/projects/tilegame/">
</head>
<body id="body">
<img id="img" style="display: none;" src="TileSet_V1.png">
<img id="img2" style="display: none;" src="TileSet_V2.png">
<img id="img3" style="display: none;" src="TileSet_V3.png">
<img id="aniimg1" style="display: none;" src="no_dagger.png">
<img id="aniimg2" style="display: none;" src="dagger.png">
<canvas id="c" width="320" height="320" style="background-color: black;border:3px solid black;"></canvas>
<canvas id="props" width="320" height="320" style="border:3px solid black;"></canvas>
<script src="map.js"></script>
<script src="props.js"></script>
<script src="drawprops.js"></script>
<script src="enemy.js"></script>
<script src="drawenemy.js"></script>
</body>
</html>

Canvas drawImage is inexplicably offset by 1 Pixel

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;

Categories

Resources