I'm coding Snake Game, but I have an issue.
var ctx = document.getElementById('ctx').getContext('2d');
var canvas = document.getElementById('ctx');
var y = [240, 230, 220];
var x = [240, 240, 240];
var xSpeed = 0;
var ySpeed = 0;
function load() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (p = 0; p < x.length; p++) {
ctx.fillStyle = "black";
ctx.fillRect(x[p], y[p], 10, 10);
}
}
function keyDown() {
var key = event.keyCode; /*getting keyCode of pressed key*/
ctx.fillStyle = "black"; /*color of rectangle*/
switch (key) {
case 39: //RIGHT
xSpeed = 10;
ySpeed = 0;
break;
case 37: //LEFT
xSpeed = -10;
ySpeed = 0;
break;
case 38: //UP
xSpeed = 0;
ySpeed = -10;
break;
case 40: //DOWN
xSpeed = 0;
ySpeed = 10;
break;
}
}
function update() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (x[0] >= 490) {
xSpeed = 0;
} else if (y[0] >= 490) {
ySpeed = 0;
}
//console.clear();
y[0] += ySpeed;
x[0] += xSpeed;
for (i = x.lenght; i >= 0; i--) {
y[i] = y[i - 1];
x[i] = x[i - 1];
console.log(i);
}
for (i = 0; i < x.length; i++) {
ctx.fillStyle = "black";
ctx.fillRect(x[i], y[i], 10, 10);
//console.log("y= " + y[i]);
//console.log("x= " + x[i]);
}
//console.log(xSpeed);
//console.log(ySpeed);
}
setInterval(update, 500);
<!DOCTYPE html>
<html>
<head>
<link rel="shortcut icon" href="#">
<title>The Snake Game</title>
</head>
<style>
#ctx {
position: absolute;
/*it can be fixed too*/
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
/*this to solve "the content will not be cut when the window is smaller than the content":*/
max-width: 100%;
max-height: 100%;
overflow: auto;
}
</style>
<body onkeydown="keyDown()" onload="load()">
<center><canvas id="ctx" width="500" height="500" style="border:1px solid black"></canvas></center>
</body>
<script src="script.js"></script>
</html>
The for loop inside of update function is not loggin, so it looks like it's not working.
for (i = x.lenght; i >= 0; i--) {
y[i] = y[i - 1];
x[i] = x[i - 1];
console.log(i);
}
I don't know what I've done wrong, but I think it's just another one stupid mistake. Please don't criticize me so much, I'm just nooby 14 y.o. programmer.
Thanks in advice,
Tomas ;-)
On a first sight it's just a typing mistake because you wrote x.lenght instead of x.length.
var ctx = document.getElementById('ctx').getContext('2d');
var canvas = document.getElementById('ctx');
var y = [240, 230, 220];
var x = [240, 240, 240];
var xSpeed = 0;
var ySpeed = 0;
function load() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (p = 0; p < x.length; p++) {
ctx.fillStyle = "black";
ctx.fillRect(x[p], y[p], 10, 10);
}
}
function keyDown() {
var key = event.keyCode; /*getting keyCode of pressed key*/
ctx.fillStyle = "black"; /*color of rectangle*/
// Prevent the snake from going in the reverse direction.
switch (key) {
case 39: //RIGHT
if(xSpeed != -10) {
xSpeed = 10;
ySpeed = 0;
}
break;
case 37: //LEFT
if(xSpeed != 10) {
xSpeed = -10;
ySpeed = 0;
}
break;
case 38: //UP
if(ySpeed != 10) {
xSpeed = 0;
ySpeed = -10;
}
break;
case 40: //DOWN
if(ySpeed != -10) {
xSpeed = 0;
ySpeed = 10;
}
break;
}
}
function update() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (x[0] >= 490) {
xSpeed = 0;
} else if (y[0] >= 490) {
ySpeed = 0;
}
if((xSpeed + ySpeed) != 0) {
for(var idx = x.length - 1; idx >= 1; idx--) {
y[idx] = y[idx - 1];
x[idx] = x[idx - 1];
}
}
y[0] += ySpeed;
x[0] += xSpeed;
for (i = 0; i < x.length; i++) {
ctx.fillStyle = "black";
ctx.fillRect(x[i], y[i], 10, 10);
}
}
setInterval(update, 500);
<!DOCTYPE html>
<html>
<head>
<link rel="shortcut icon" href="#">
<title>The Snake Game</title>
</head>
<style>
#ctx {
position: absolute;
/*it can be fixed too*/
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
/*this to solve "the content will not be cut when the window is smaller than the content":*/
max-width: 100%;
max-height: 100%;
overflow: auto;
}
</style>
<body onkeydown="keyDown()" onload="load()">
<center><canvas id="ctx" width="500" height="500" style="border:1px solid black"></canvas></center>
</body>
<script src="script.js"></script>
</html>
I really liked your code, especially for how simple it is! So I have added a slightly improved version here. These are the issues I noticed:
Spoilers
In the keyDown function, by adding the condition to check previous speed you can prevent the snake from reversing its direction.
In update function you should update the location of x[0] and y[0] only after updating the "tail" elements. Otherwise, you would not have the new location for the x[1] and y[1] element.
Also, you might need to put an if condition for (xSpeed + ySpeed) != 0 around the loop that updates the location of the tail elements. This would help ensure that the snake doesn't jumble up into single element before the user interacts with it.
Related
I am trying to make bullet objects for my HTML game, but they won't get drawn, even though the background (which is drawn the same way before the bullets) works.
<!DOCTYPE html>
<html>
<head>
<title>
Shooter
</title>
<style>
body{
background-color: blue;
}
canvas{
position: absolute;
top: 50px;
left: 50px;
}
h1{
color: yellow;
position: absolute;
top: 0px;
left: 50px;
}
p{
color: red;
position: absolute;
top: 450px;
left: 50px;
}
</style>
</head>
<body onkeydown='getKeyAndMove(event)'>
<h1>
Shooter
</h1>
<canvas width='800' height='400' id='myCanvas'></canvas>
<p>
Use Up and Down to move, Space to shoot. Don't get hit!
</p>
<script>
var start = null;
var playery = 0;
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var radius = 1;
var bullets = [null];
var enemies = new Array(null);
function fire(playery, bullets, enemies){
if (bullets[0] === null){
console.log(9)
bullets[0] = {
x:0,
y:playery,
length:50,
height:25,
update: function(enemies){
bullets[0].x += 5;
var maxCount = enemies.length;
/*for (i=0; i<maxCount; i++){
var enemy = enemies[i];
if (enemy.x <= bullets[0].x + bullets[0].length){
if (enemy.x + enemy.length >= bullets[0].x){
if (enemy.y + enemy.height >= bullets[0].y){
if (enemy.y <= bullets[0].y + bulets[0].height){
enemies[i] = null;
bullets[0] = null;
}
}
}
}
}*/
if (bullets[0].x >= 800){
bullets[0] = null;
return;
}
}
};
}
};
function getKeyAndMove(e){
var key_code=e.which||e.keyCode;
switch(key_code){
case 38:
playery -= 5
break;
case 40:
playery += 5
break;
case 32:
console.log(32)
fire(playery, bullets, enemies);
break;
}
};
function step(timestamp){
if (!start) start = timestamp;
var progress = timestamp - start;
ctx.fillStyle = 'white'
ctx.fillRect(0, 0, canvas.width, canvas.height)
ctx.fillStyle = 'rgb(0, 0, 0)'
ctx.fillRect(1, 1, canvas.width - 2, canvas.height - 2)
var i=0;
var j=0;
for (i=0; i < 800; i++){
for (j=0; j < 400; j++){
if (Math.random() > 0.9999) {
ctx.beginPath();
ctx.arc(i, j, radius, 0, 2 * Math.PI, false);
ctx.fillStyle = 'white';
ctx.fill();
ctx.lineWidth = 0;
ctx.strokeStyle = '#FFFFFF';
ctx.stroke();
ctx.closePath();
}
}
}
if (bullets[0] != null){
bullets[0].update(enemies)
console.log(0)
if(bullets[0] != null){
ctx.fillStyle = '#DD0000'
ctx.fillRect(bullets[0].x, bullets[0].y, bullets[0].width, bullets[0].height)
}
}
window.requestAnimationFrame(step)
}
window.requestAnimationFrame(step)
</script>
</body>
</html>
The console shows no errors when I run the code. I have set it to log every frame that there is a bullet, and the log is showing up, the bullet just never appears.
What am I doing wrong?
I accidentally typed width instead of length in line 126. The problem is solved.
I'm still getting used to objects, but no matter what I do I can't get my objects to reverse their x or y. It doesn't even register that any of them have hit a canvas wall, they just go off screen.
Here's my code:
"use strict";
//variables
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var randomX = 0; //in for loop use Math.random()
var randomY = 0; //in for loop use Math.random()
var ballRadius = 10;
var ballX = canvas.width/2;
var ballY = canvas.height-30;
var ballMove = [];
var ballObject = [];
//declares the objects x and y's
for(var i = 0; i < 10; i++){
ballObject[i] = { x: 0, y: 0 };
ballMove[i] = { x:1, y:-1 };
randomX = (Math.random() * (canvas.width-ballRadius)) +1;
randomY = (Math.random() * (canvas.height-ballRadius)) +1;
ballObject[i].x = randomX;
ballObject[i].y = randomY;
}
function draw()
{
ctx.clearRect(0,0,canvas.width, canvas.height);
//didn't actually need this for loop but was experimenting
for(var i = 0; i<10; i++){
drawBall(i);
}
moveBall();
//this method should check the x and y of the balls.
bounceBall();
}
// basic ball drawing function
function drawBall(i)
{
ctx.beginPath();
ctx.arc(ballObject[i].x, ballObject[i].y, ballRadius, 0, Math.PI*2);
ctx.fillStyle = "blue";
ctx.fill();
ctx.closePath();
}
//extremely basic move function (just adds to x and y)
function moveBall()
{
for(var i = 0; i < 10; i++){
ballObject[i].x += ballMove[i].x;
ballObject[i].y += ballMove[i].y;
}
}
//WHY IT NO WORK
//for whatever reason this function doesn't reverse the x and y
function bounceBall()
{
for(var i = 0; i < 10; i++)
{
if (ballObject[i].x == canvas.width-ballRadius || ballObject[i].x == 0+ballRadius){
alert("i've hit a wall");
ballMove[i].x = -ballMove[i].x;
}
if (ballObject[i].y == canvas.height-ballRadius || ballObject[i].y == 0+ballRadius){
alert("i've hit a wall");
ballMove[i].y = -ballMove[i].y;
}
}
}
setInterval(draw, 10);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Gamedev Canvas Workshop</title>
<style>
* { padding: 0; margin: 15; }
canvas { background: #eee; display: block; margin: 0 auto; }
</style>
</head>
<body>
<canvas id="myCanvas" width="480" height="320"></canvas>
<script src="ballPop.js">
</script>
</body>
</html>
I've kinda made a mess of my code trying to use objects and make them bounce.
I made a brick break game after following some tut online and the bounce worked fine - however that same concept doesn't seem to work with objects.
This likely has to do with the fact that your ball coordinates are floating point values. For example:
> (Math.random() * (200 - 3)) + 1
179.1025927176495
When you do your checks in bounceBall you may get better results by checking if the ball would exceed the boundary
function bounceBall()
{
for(var i = 0; i < 10; i++)
{
if (ballObject[i].x >= canvas.width-ballRadius || ballObject[i].x <= 0+ballRadius) {
alert("i've hit a wall");
ballMove[i].x = -ballMove[i].x;
}
if (ballObject[i].y >= canvas.height-ballRadius || ballObject[i].y <= 0+ballRadius){
alert("i've hit a wall");
ballMove[i].y = -ballMove[i].y;
}
}
}
Note: == changed to >= and <=
I am attempting a game of snake, although the shape seems to not be moving. I don't know why it is doing this and it is not a typographical error. In order to see my problem, see snippet below ↓.
I have added both a CSS and HTML file as well, so you know I did that right. My method of making this is to get the direction of the snake (represented by the variables 'vx' and 'vy') and then use the direction to calculate the future position of the 'snakePiece()' object in the Array of 'snake'.
window.onload = function main() {
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
function snakePiece() {
this.color = "#9999ff";
this.dimension = 25;
this.x = 0;
this.y = 0;
this.vx = 0;
this.vy = 0;
}
var snake = new Array(new snakePiece());
function setPosition() {
for (i = 0; i < snake.length; i++) {
switch (snake[i].vx) {
case 1:
snake[i].x += snake[i].dimension;
snake[i + 1].x = snake[i].x - snake[i].dimension;
snake[i + 1].vx = 1;
break;
case -1:
snake[i].x -= snake[i].dimension;
snake[i + 1].x = snake[i].x + snake[i].dimension;
snake[i + 1].vx = -1;
break;
}
switch (snake[i].vy) {
case 1:
snake[i].y -= snake[i].dimension;
snake[i + 1].y = snake[i].y + snake[i].dimension;
snake[i + 1].vy = 1;
break;
case -1:
snake[i].y += snake[i].dimension;
snake[i + 1].y = snake[i].y - snake[i].dimension;
snake[i + 1].vy = -1;
break;
}
}
}
setInterval(function draw() {
setPosition();
ctx.clearRect(0, 0, c.width, c.height);
for (j = 0; j < snake.length; j++) {
ctx.fillStyle = snake[j].color;
ctx.fillRect(snake[j].x, snake[j].y, snake[j].dimension, snake[j].dimension);
}
}, 500);
document.onkeydown = function(event) {
var keyPress = String.fromCharCode(event.keyCode);
switch (keyPress) {
case 40: //DOWN
snake[0].vy = 1;
snake[0].vx = 0;
break;
case 39: //RIGHT
snake[0].vx = 1;
snake[0].vy = 0;
break;
case 38: //UP
snake[0].vy = -1;
snake[0].vx = 0;
break;
case 37: //LEFT
snake[0].vx = -1;
snake[0].vy = 0;
break;
}
}
}
body {
padding: 15px;
}
#canvas {
border: 3px solid black;
background-color: #FFB6C1;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Simple Snake</title>
<script src="snake-java.js" type="text/javascript" rel="javascript"></script>
<link href="snake-css.css" type="text/css" rel="stylesheet" />
</head>
<body>
<canvas height="900" width="900" id="canvas"></canvas>
</body>
</html>
Here's my take on it. I added comments in the code where I modified something to exlain what was wrong.
window.onload = function main() {
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
function snakePiece() {
this.color = "#9999ff";
this.dimension = 25;
this.x = 100;
this.y = 100;
this.vx = 0;
this.vy = 0;
}
var snake = new Array(new snakePiece());
function setPosition() {
for (i = 0; i < snake.length; i++) {
switch (snake[i].vx) {
case 1:
snake[i].x += snake[i].dimension;
// You don't need all the commented lines in this function.
// The for loop is already taking care of your snake cells.
// Moreover snake[i + 1] is undefined if your snake is length 1 (hence a JS error).
//snake[i + 1].x = snake[i].x - snake[i].dimension;
//snake[i + 1].vx = 1;
break;
case -1:
snake[i].x -= snake[i].dimension;
//snake[i + 1].x = snake[i].x + snake[i].dimension;
//snake[i + 1].vx = -1;
break;
}
switch (snake[i].vy) {
case 1:
snake[i].y -= snake[i].dimension;
//snake[i + 1].y = snake[i].y + snake[i].dimension;
//snake[i + 1].vy = 1;
break;
case -1:
snake[i].y += snake[i].dimension;
//snake[i + 1].y = snake[i].y - snake[i].dimension;
//snake[i + 1].vy = -1;
break;
}
}
}
setInterval(function draw() {
setPosition();
ctx.clearRect(0, 0, c.width, c.height);
for (j = 0; j < snake.length; j++) {
ctx.fillStyle = snake[j].color;
ctx.fillRect(snake[j].x, snake[j].y, snake[j].dimension, snake[j].dimension);
}
}, 500);
document.onkeydown = function(event) {
//var keyPress = String.fromCharCode(event.keyCode); <- this is wrong -> verify with : console.log(keyPress);
switch (event.keyCode) { // switch on event.keyCode instead
case 40: //DOWN
snake[0].vy = -1; // -1 instead of 1
snake[0].vx = 0;
break;
case 39: //RIGHT
snake[0].vx = 1;
snake[0].vy = 0;
break;
case 38: //UP
snake[0].vy = 1; // 1 instead of -1
snake[0].vx = 0;
break;
case 37: //LEFT
snake[0].vx = -1;
snake[0].vy = 0;
break;
}
// add preventDefault(); to disable window scrolling
event.preventDefault();
}
}
body {
padding: 15px;
}
#canvas {
border: 3px solid black;
background-color: #FFB6C1;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Simple Snake</title>
<script src="snake-java.js" type="text/javascript" rel="javascript"></script>
<link href="snake-css.css" type="text/css" rel="stylesheet" />
</head>
<body>
<canvas height="900" width="900" id="canvas"></canvas>
</body>
</html>
The "spaceShip" in the following code isn't moving smoothly at the beginning of holding any arrow key down. It moves one step, freezes for a split second, and then moves "smoothly". How can I make it move smoothly right from the beginning, with not "freezing"?
My code:
<!doctype html>
<html>
<head>
<meta http-content="Content-type" charset="utf-8">
<title>Make body move smoothly</title>
<style type="text/css">
body {
}
canvas {
margin: auto;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="canvas" width="400" height="600"></canvas>
<script type="text/javascript">
// Set up requestAnimationFrame and cancelAnimationFrame
(function() {
var lastTime =0;
var vendors=['ms', 'moz', 'webkit', 'o'];
for(var x=0; x<vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame=window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame =
window[vendors[x]+ 'CancelAnimationFrame'] ||
window[vendors[x] +'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame=function(callback, element) {
var currTime =new Date().getTime();
var timeToCall =Math.max(0, 16 - (currTime - lastTime));
var id =window.setTimeout(function() { callback(currTime+timeToCall); },
timeToCall);
lastTime =currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame=function(id) {
clearTimeout(id);
};
}());
var canvas;
var ctx;
// ship data
var shipPositionX = document.getElementById('canvas').width/2;
var shipPositionY = document.getElementById('canvas').height - 30;
var deltaShipPositionX = 10;
var deltaShipPositionY = 10;
function init() {
canvas = document.getElementById('canvas');
ctx = canvas.getContext('2d');
draw();
}
function draw(){
clear();
createRectangleToCoverCanvas();
createSpaceShip(shipPositionX, shipPositionY, 10);
requestAnimationFrame(draw);
}
function clear(){
ctx.clearRect(0, 0, document.getElementById('canvas').width, document.getElementById('canvas').height);
}
function createRectangleToCoverCanvas(){
ctx.fillStyle = 'black';
ctx.strokeStyle = 'black';
ctx.beginPath();
ctx.rect(0, 0, canvas.width, canvas.height);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
function createSpaceShip(x, y, radius) {
ctx.fillStyle = 'white'
ctx.strokeStyle = 'white'
ctx.beginPath();
ctx.rect(x, y, 20, 20);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
function moveSpaceShip(event){
switch(event.keyCode){
// left
case 37:
if(shipPositionX - deltaShipPositionX + 15 > 0){
shipPositionX -= deltaShipPositionX;
}
break;
// up
case 38:
if(shipPositionY - deltaShipPositionY + 15 > 0){
shipPositionY -= deltaShipPositionY;
}
break;
// right
case 39:
if(shipPositionX + deltaShipPositionX < document.getElementById('canvas').width){
shipPositionX += deltaShipPositionX;
}
break;
//down
case 40:
if(shipPositionY + deltaShipPositionY < document.getElementById('canvas').height){
shipPositionY += deltaShipPositionY;
}
break;
}
}
window.addEventListener('load', init);
window.addEventListener('keydown', moveSpaceShip, true);
</script>
</body>
</html>
Notice the difference between my code and this example: http://atomicrobotdesign.com/blog_media/sprite_sheet/spritesheet.html
See how the example's is smooth, but my "spaceShip" isn't?
Why is it happening and how can I fix it? Is it because the example uses a sprite (but this doesn't seem to make much sense)?
The problem is that you wait for each keydown event to update the ship position.
The keydown event has a delay before it triggers again : the delay you are experiencing at beginning and the jump you face at each redraw.
The solution here is to trigger the movement on keydown and release it on keyup. This way, your ship will move smoothly as soon as you push the button.
// Im' assuming most of visitors here have recent browsers, so I removed the rAF polyfill for readibility
// If you wrap it after the canvas element decalaration, you can already populate this variable, it will avoid that you make a lot of calls to document.getElementById()
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// ship data
var shipPositionX = canvas.width / 2;
// Just for the snippet height
var shipPositionY = 0;
var deltaShipPositionX = 10;
var deltaShipPositionY = 10;
//Removed the init() function, since our elements are loaded.
function draw() {
clear();
createRectangleToCoverCanvas();
createSpaceShip(shipPositionX, shipPositionY, 10);
}
function clear() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
function createRectangleToCoverCanvas() {
ctx.fillStyle = 'black';
ctx.strokeStyle = 'black';
ctx.beginPath();
ctx.rect(0, 0, canvas.width, canvas.height);
ctx.fill();
ctx.stroke();
}
function createSpaceShip(x, y, radius) {
ctx.fillStyle = 'white'
ctx.strokeStyle = 'white'
ctx.beginPath();
ctx.rect(x, y, 20, 20);
ctx.fill();
ctx.stroke();
}
// instantiate a variable that will store our animationFrame id, so we can cancel it further
var raf,
// the direction object, with an x and y values
direction = {
x: 0,
y: 0
};
// we can set a speed variable
var speed = 2.5;
function triggerMoveSpaceShip(event) {
switch (event.keyCode) {
// left
case 37:
// update the direction object
direction.x = -speed;
// avoid the scroll in the snippet
event.preventDefault();
break;
// up
case 38:
direction.y = -speed;
event.preventDefault();
break;
// right
case 39:
direction.x = speed;
event.preventDefault();
break;
//down
case 40:
direction.y = speed;
event.preventDefault();
break;
}
// if we haven't initiated the animation yet, and that our direction is not 0, then do it now
if (!raf && (direction.x || direction.y)) moveSpaceShip();
}
function releaseMoveSpaceShip(event) {;
switch (event.keyCode) {
// left
case 37:
//reset this direction
direction.x = 0;
break;
// up
case 38:
direction.y = 0;
break;
// right
case 39:
direction.x = 0;
break;
//down
case 40:
direction.y = 0;
break;
}
if (!direction.x && !direction.y) {
// if none of the directions is set, stop the animation
cancelAnimationFrame(raf);
raf = undefined;
}
}
function moveSpaceShip() {
// declare our animation function
var move = function() {
// update the positions without going out of the screen
// Sorry, this is dirty...
if(direction.x){
if(
(shipPositionX > 0 && shipPositionX < canvas.width-20) ||
(shipPositionX <= 0 && direction.x > 0) ||
(shipPositionX >= canvas.width-20 && direction.x < 0))
shipPositionX += direction.x;
}
if(direction.y){
if(
(shipPositionY > 0 && shipPositionY < canvas.height-20) ||
(shipPositionY <= 0 && direction.y > 0) ||
(shipPositionY >= canvas.width-20 && direction.y < 0))
shipPositionY += direction.y;
}
// finally draw ou ship
draw();
// update our raf id
raf = requestAnimationFrame(move);
};
// let's go !
raf = requestAnimationFrame(move);
}
draw();
window.addEventListener('keydown', triggerMoveSpaceShip, true);
window.addEventListener('keyup', releaseMoveSpaceShip, true);
canvas {
margin: auto;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
border: 1px solid black;
}
body{
overflow: none;
}
<canvas id="canvas" width="400" height="200"></canvas>
uncommented fiddle
I am having issues trying to place an image as an object for an "asteroid avoidance" game. I was able to get the game itself to work based on what was written in my book "Foundation: HTML5 Canvas for Games and Entertainment". I want to go one step beyond what was written in the book. I want to replace the triangle shaped ship with that of an image. However, I am unable to figure out where to put the code for this.draw. My professor showed us a way to do it. When I try to implement it into my code it doesn't want to work properly. May I ask for some advice on how to place the image as the ship?
Here is my working code from the book, before I made any this.draw edits:(http://jsbin.com/tukejopofo/1/)
$(document).ready(function() {
var canvas = $("#gameCanvas");
var context = canvas.get(0).getContext("2d");
//canvas dimensions
var canvasWidth = canvas.width();
var canvasHeight = canvas.height();
var playGame;
var asteroids;
var numAsteroids;
var player;
var score;
var scoreTimeout;
var arrowUp = 38;
var arrowRight = 39;
var arrowDown = 40;
var arrowLeft = 37;
//game UI
var ui = $("#gameUI");
var uiIntro = $("#gameIntro");
var uiStats = $("#gameStats");
var uiComplete = $("#gameComplete");
var uiPlay = $("#gamePlay");
var uiReset = $(".gameReset");
var uiScore = $(".gameScore");
var soundBackground = $("#gameSoundBackground").get(0);
var soundThrust = $("#gameSoundThrust").get(0);
var soundDeath = $("#gameSoundDeath").get(0);
var Asteroid = function(x, y, radius, vX) {
this.x = x;
this.y = y;
this.radius = radius;
this.vX = vX;
};
var Player = function(x, y) {
this.x = x;
this.y = y;
this.width = 24;
this.height = 24;
this.halfWidth = this.width / 2;
this.halfHeight = this.height / 2;
this.flameLength1 = 20;
this.flameLength2 = 20;
this.vX = 0;
this.vY = 0;
this.moveRight = false;
this.moveUp = false;
this.moveDown = false;
this.moveLeft = false;
};
//Reset and start the game
function startGame() {
//Reset game stats
uiScore.html("0");
uiStats.show();
//set up initial game settings
playGame = false;
asteroids = new Array();
numAsteroids = 10;
score = 0;
player = new Player(150, canvasHeight / 2, 50, 50);
for (var i = 0; i < numAsteroids; i++) {
var radius = 5 + (Math.random() * 10);
var x = canvasWidth + radius + Math.floor(Math.random() * canvasWidth);
var y = Math.floor(Math.random() * canvasHeight);
var vX = -5 - (Math.random() * 5);
asteroids.push(new Asteroid(x, y, radius, vX));
};
$(window).keydown(function(e) {
var keyCode = e.keyCode;
if (!playGame) {
playGame = true;
soundBackground.currentTime = 0;
soundBackground.play();
animate();
timer();
};
if (keyCode == arrowRight) {
player.moveRight = true;
if (soundThrust.paused) {
soundThrust.currentTime = 0;
soundThrust.play();
}
} else if (keyCode == arrowLeft) {
player.moveLeft = true;
} else if (keyCode == arrowUp) {
player.moveUp = true;
} else if (keyCode == arrowDown) {
player.moveDown = true;
}
});
$(window).keyup(function(e) {
var keyCode = e.keyCode;
if (!playGame) {
playGame = true;
animate();
};
if (keyCode == arrowRight) {
player.moveRight = false;
if (keyCode == arrowRight) {
player.moveRight = false;
soundThrust.pause();
}
} else if (keyCode == arrowUp) {
player.moveUp = false;
} else if (keyCode == arrowDown) {
player.moveDown = false;
} else if (keyCode == arrowLeft) {
player.moveLeft = false;
}
});
//start the animation loop
animate();
};
//initialize the game environment
function init() {
uiStats.hide();
uiComplete.hide();
uiPlay.click(function(e) {
e.preventDefault();
uiIntro.hide();
startGame();
});
uiReset.click(function(e) {
e.preventDefault();
uiComplete.hide();
$(window).unbind("keyup");
$(window).unbind("keydown");
soundThrust.pause();
soundBackground.pause();
clearTimeout(scoreTimeout);
startGame();
});
};
function timer() {
if (playGame) {
scoreTimeout = setTimeout(function() {
uiScore.html(++score);
if (score % 5 == 0) {
numAsteroids += 5;
}
timer();
}, 1000);
};
};
//Animation loop that does all the fun stuff
function animate() {
//Clear
context.clearRect(0, 0, canvasWidth, canvasHeight);
var asteroidsLength = asteroids.length;
for (var i = 0; i < asteroidsLength; i++) {
var tmpAsteroid = asteroids[i];
tmpAsteroid.x += tmpAsteroid.vX;
if (tmpAsteroid.x + tmpAsteroid.radius < 0) { //creates bounderies to prevent player from leaving the canvas
tmpAsteroid.radius = 5 + (Math.random() * 10);
tmpAsteroid.x = canvasWidth + tmpAsteroid.radius;
tmpAsteroid.y = Math.floor(Math.random() * canvasHeight);
tmpAsteroid.vX = -5 - (Math.random() * 5);
}
var dX = player.x - tmpAsteroid.x;
var dY = player.y - tmpAsteroid.y;
var distance = Math.sqrt((dX * dX) + (dY * dY));
if (distance < player.halfWidth + tmpAsteroid.radius) { //checks for collision
soundThrust.pause()
soundDeath.currentTime = 0;
soundDeath.play();
//Game over
playGame = false;
clearTimeout(scoreTimeout);
uiStats.hide();
uiComplete.show();
soundBackground.pause();
$(window).unbind("keyup"); //unbinds keys to stop player movement at the end of the game
$(window).unbind("keydown");
};
context.fillStyle = "rgb(255, 255, 255)";
context.beginPath();
context.arc(tmpAsteroid.x, tmpAsteroid.y, tmpAsteroid.radius, 0, Math.PI * 2, true);
context.fill();
};
player.vX = 0;
player.vY = 0;
if (player.moveRight) {
player.vX = 3;
};
if (player.moveLeft) {
player.vX = -3;
};
if (player.moveUp) {
player.vY = -3;
};
if (player.moveDown) {
player.vY = 3;
};
player.x += player.vX;
player.y += player.vY;
if (player.x - player.halfWidth < 20) {
player.x = 20 + player.halfWidth;
} else if (player.x + player.halfWidth > canvasWidth - 20) {
player.x = canvasWidth - 20 - player.halfWidth;
}
if (player.y - player.halfHeight < 20) {
player.y = 20 + player.halfHeight;
} else if (player.y + player.halfHeight > canvasHeight - 20) {
player.y = canvasHeight - 20 - player.halfHeight;
}
if (player.moveRight) {
context.save();
context.translate(player.x - player.halfWidth, player.y);
if (player.flameLength1 == 20) {
player.flameLength1 = 15;
(player.flameLength2 == 20)
player.flameLength2 = 15;
} else {
player.flameLength1 = 20;
player.flameLength2 = 20;
};
context.fillStyle = "orange";
context.beginPath();
context.moveTo(0, -12);
context.lineTo(-player.flameLength1, -7);
context.lineTo(0, -5);
context.closePath();
context.fill();
context.fillStyle = "orange";
context.beginPath();
context.moveTo(0, 12);
context.lineTo(-player.flameLength2, 7);
context.lineTo(0, 5);
context.closePath();
context.fill();
context.restore();
};
//draw ship
context.fillStyle = "rgb(255, 0, 0)";
context.beginPath();
context.moveTo(player.x + player.halfWidth, player.y);
context.lineTo(player.x - player.halfWidth, player.y - player.halfHeight);
context.lineTo(player.x - player.halfWidth, player.y + player.halfHeight);
context.closePath();
context.fill();
while (asteroids.length < numAsteroids) { //adds asteroids as the difficulty increases
var radius = 5 + (Math.random() * 10)
var x = Math.floor(Math.random() * canvasWidth) + canvasWidth + radius;
var y = Math.floor(Math.random() * canvasHeight);
var vX = -5 - (Math.random() * 5);
asteroids.push(new Asteroid(x, y, radius, vX));
}
if (playGame) {
//run the animation loop again in 33 milliseconds
setTimeout(animate, 24);
};
};
init();
});
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
width: 100%;
}
canvas {
display: block;
}
body {
background: #000;
color: #fff;
font-family: Verdana, Arial, sans-serif;
font-size: 18px;
}
h1 {
font-size: 30px;
}
h6 {
font-size: 15px;
}
p {
margin: 0 20px;
}
a {
color: #fff;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
a.button {
background: #185da8;
border-radius: 5px;
display: block;
font-size: 30px;
margin: 40px 0 0 350px;
padding: 10px;
width: 200px;
text-align: center;
}
a.button:hover {
background: #2488f5;
color: #fff;
text-decoration: none;
}
#game {
height: 600px;
left: 50%;
margin: -250px 0 0 -500px;
position: relative;
top: 50%;
width: 980px;
}
#gameCanvas {
background: #001022;
border: 5px solid green;
background-image: url(../images/space.jpg);
background-position: center top;
background-repeat: no-repeat;
background-size: cover;
}
#gameUI {
height: 600px;
position: absolute;
width: 980px;
}
#gameIntro,
#gameComplete {
background: rgba(0, 0, 0, 0.5);
margin: 100px 0 0 10px;
padding: 40px 0;
text-align: center;
}
#gameStats {
font-size: 14px;
margin: 20px 0;
}
#gameStats .gameReset {
margin: 20px 20px 0 0;
position: absolute;
right: 0;
top: 0;
}
<body>
<div id="game">
<div id="gameUI">
<div id="gameIntro">
<h1>Debris Fields of Spiral Galaxy</h1>
<h6>A <i>Galaxy Smuggler's Run</i> Game</h6>
<hr>
<p>You are Captain Amadaeus delivering goods to a dependent planet on the other side of a debris field</p>
<p>Click <i>"Play"</i> and then press any key to start.</p>
<p><a id="gamePlay" class="button" href="">Play!</a>
</p>
</div>
<div id="gameStats">
<p><b>Time: </b><span class="gameScore"></span> seconds</p>
<p><a class="gameReset" href="">Reset</a>
</p>
</div>
<div id="gameComplete">
<h1>Game Over!</h1>
<p>You survived for <span class="gameScore"></span> seconds.</p>
<p>Would you like to give it another go?</p>
<p><a class="gameReset button" href="">Play Again?</a>
</p>
</div>
</div>
<canvas id="gameCanvas" width="980" height="600">
</canvas>
<audio id="gameSoundBackground" loop>
<source src="sounds/background.ogg">
<source src="sounds/background.mp3">
</audio>
<audio id="gameSoundThrust" loop>
<source src="sounds/thrust.ogg">
<source src="sounds/thrust.mp3">
</audio>
<audio id="gameSoundDeath">
<source src="sounds/death.ogg">
<source src="sounds/death.mp3">
</audio>
</div>
</body>
and here is my Professor's code for drawing an image:(http://jsbin.com/rapayufafe/1/)
// JS file for the ship
function Ship() {
this.x = 100;
this.y = 100;
this.color = "yellow";
this.fillStyle = "white";
this.vx = 0;
this.vy = 0;
this.ax = 1;
this.ay = 1;
//function "move" that will add velocity to the position of the ship
this.move = function() {
this.x += this.vx;
this.y += this.vy;
}//end move function
//draw the ship
this.draw=function () {
//ship var
var imageObj = new Image();
imageObj.src = "images/ship.png";
//save the current state of the canvas
context.save();
//moving the point of origin (0,0) to the ships x and y coordinates
context.translate(this.x,this.y);
context.lineStyle = this.color;
context.fillStyle = this.fillStyle;
/*context.beginPath();
context.moveTo(25,0);
context.lineTo(-25,25)
context.lineTo(-25,-25)*/
//draw ship
context.drawImage(imageObj,-25,-25,50,50);
context.closePath();
context.stroke();
context.fill();
context.restore();
}//end of draw ship
}//end ship function
/*var asteroidsLength = asteroids.length;
for (var i = 0; i < asteroidsLength; i++) {
var tmpAsteroid = asteroids[i];
context.fillStyle = "gray";
context.beginPath();
context.arc(tmpAsteroid.x, tmpAsteroid.y, tmpAsteroid.radius, 0, Math.PI*2, true);
context.closePath();
context.fill();
};*/
As you can see in your starting code, you have a section looking like this:
//draw ship
context.fillStyle = "rgb(255, 0, 0)";
context.beginPath();
context.moveTo(player.x + player.halfWidth, player.y);
context.lineTo(player.x - player.halfWidth, player.y - player.halfHeight);
context.lineTo(player.x - player.halfWidth, player.y + player.halfHeight);
context.closePath();
context.fill();
Just replace that code with the code for drawing an image.
var imageObj = new Image();
imageObj.src = "images/ship.png";
context.drawImage(imageObj,player.x,player.y);
Although, I'd recommend declaring the imageObj and setting the source at the top of your code where you declare the rest of your variables so that you don't load the image every time you want to draw the ship.