Im trying to make simple game in canvas. I made animation for hero using setTimeout() function. I check pressed keys with function moove(e):
Everything works pretty fine when i press leftarrow or rightarrow for the first time, but then hero doesnt moove. Any recomendations to the code is appreciated.
var cns = document.getElementById("can");
cns.height = 600;
cns.width = 300;
var ctx = cns.getContext("2d");
var hero = new Image();
hero.src = "images/hero.png";
hero.onload = function() {
ctx.drawImage(hero, 120, 570);
hero.xx = 120;
hero.yy = 570;
};
var intervalL, intervalR, intervalLL, intervalRR;
var keys = [];
function moove(e) {
keys[e.keyCode] = (e.type == "keydown");
if (keys[37]) {
clearTimeout(intervalR);
clearTimeout(intervalRR);
goLeft(hero);
} else {
clearTimeout(intervalL);
clearTimeout(intervalLL);
}
if (keys[39]) {
clearTimeout(intervalL);
clearTimeout(intervalLL);
goRight(hero);
} else {
clearTimeout(intervalR);
clearTimeout(intervalRR);
}
}
function goLeft(img) {
var x = img.xx,
y = img.yy;
function f() {
ctx.clearRect(img.xx, img.yy, img.width, img.height);
ctx.drawImage(img, x, y);
img.xx = x;
img.yy = y;
x -= 1.2;
if (x < -35) {
x = cns.width;
}
}
if (!intervalL) {
intervalL = setTimeout(function run() {
f();
intervalLL = setTimeout(run, 5);
}, 5);
}
}
Function goRight is similiar to goLeft.
Function moove is called in tag body onkeydown='moove(event)' onkeyup='moove(event)'.
You can check the project here: https://github.com/Fabulotus/Fabu/tree/master/Canvas%20game%20-%20dodge%20and%20jump
The reason it doesn't work the first time is because the first time through you are setting the position to its previous position (x = image.xx) then updating x after you draw. You should update the x value x -= 1.2 before calling drawImage
Here is a "working" version of your code:
var cns = document.getElementById("can");
cns.height = 170;
cns.width = 600;
var ctx = cns.getContext("2d");
var hero = new Image();
hero.src = "http://swagger-net-test.azurewebsites.net/api/Image";
hero.onload = function() {
ctx.drawImage(hero, cns.width-10, cns.height/2);
hero.xx = cns.width-10;
hero.yy = cns.height/2;
};
var intervalL, intervalR, intervalLL, intervalRR;
var keys = [];
function goLeft(img) {
function f() {
ctx.beginPath()
ctx.clearRect(0, 0, cns.width, cns.height);
ctx.drawImage(img, img.xx, img.yy);
img.xx--;
if (img.xx < -img.width) {
img.xx = cns.width;
}
}
if (!intervalL) {
intervalL = setTimeout(function run() {
f();
intervalLL = setTimeout(run, 5);
}, 5);
}
}
goLeft(hero)
<canvas id="can">
As you can see the function goLeft has been significantly simplified.
One recommendation: avoid the many setTimeout and clearTimeout instead use one setInterval to call a draw function that takes care of drawing everything on your game, all the other function should just update the position of your gameObjects.
Related
I have 2 sets of code in here. One is the simple bounce off code. The other is a function. I've tried to make it a function but it doesn't seem to be working properly.
The bg framerate doesn't clear in the sense that a string of balls show rather than a ball bouncing and animating.
if(this.y_pos > 400) this condition doesn't seem to be working even tho it works when it is drawn in the draw function.
var sketch = function (p) {
with(p) {
p.setup = function() {
createCanvas(800, 600);
// x_pos = 799;
// y_pos = 100;
// spdx = -random(5,10);
// spdy = random(12,17);
};
p.draw = function() {
background(0);
// fill(255);
// ellipse(x_pos,y_pos,50);
// x_pos += spdx;
// y_pos += spdy;
// if(y_pos > 400)
// {
// spdy *= -1;
// }
// for( var i = 0; i < 10; i++)
avalance(799, 100, random(5,10), random(12,17));
};
function avalance(x, y, spdx, spdy)
{
this.x_pos = x;
this.y_pos = y;
this.spdx = spdx;
this.spdy = spdy;
this.x_pos = 799;
this.y_pos = 100;
this.spdx = 1;
this.spdy = 1;
this.movement = function()
{
this.x_pos += -spdx;
this.y_pos += spdy;
if(this.y_pos > 400)
{
this.spdy *= -1;
}
}
this.draw = function()
{
this.movement();
this.drawnRox();
}
this.drawnRox = function()
{
fill(255);
ellipse(this.x_pos,this.y_pos,50);
}
}
}
};
let node = document.createElement('div');
window.document.getElementById('p5-container').appendChild(node);
new p5(sketch, node);
body {
background-color:#efefef;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.js"></script>
<div id="p5-container"></div>
Let's address both issues:
The draw() function is called for each new frame and in it you call avalance which creates a new ball. To fix that you need to
Create a global variable let ball; out of setup() and draw() so that you can reuse that later;
In setup create a new ball and assign it to your ball variable: ball = new avalance(799, 100, random(5,10), random(12,17));
In draw() you want to update the ball and that's what its own draw() function does (I would advise renaming it update() for example, to avoid confusion with the p5 specific draw() function). So you just need to call ball.draw() in draw().
This creates a ball which moves but still don't respect your 400px limit.
The issue is that in movement() you add spdx and spdy to the position but when the ball crosses the limit you update this.spdy, so you need to update the function with this code:
this.x_pos += -this.spdx;
this.y_pos += this.spdy;
And you should be good! Here is a code pend with your code working as you intend.
Also as a bonus advise: You probably want to use some p5.Vector objects to store positions, speeds and accelerations it really makes your code easier to read and to use. You could also rename your function Avalance (capital A) to show that you actually use a class and that this function shouldn't be called without new.
As #statox suggested, do new avalance(799, 100, random(5,10), random(12,17)) in the setup() section and call draw of the ball in draw() section.
You can test the code below by clicking "Run code snippet".
var sketch = function (p) {
with(p) {
var ball;
p.setup = function() {
createCanvas(800, 600);
ball = new avalance(799, 100, random(5,10), random(12,17));
};
p.draw = function() {
background(0);
ball.draw();
};
function avalance(x, y, spdx, spdy)
{
function movement ()
{
x += -spdx;
y += spdy;
if (y > height || y < 0)
{
spdy *= -1;
}
if (x > width || x < 0)
{
spdx *= -1;
}
}
this.draw = function()
{
movement();
drawnRox();
}
function drawnRox ()
{
fill(255);
ellipse(x,y,50);
}
}
}
};
let node = document.createElement('div');
window.document.getElementById('p5-container').appendChild(node);
new p5(sketch, node);
body {
background-color:#efefef;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.js"></script>
<div id="p5-container"></div>
I'm loading image URLs from a json file. I have everything working fine, except displaying the actual images.
It's a simple clik carousel. Hit the click and it moves index onto the next one. I want to make sure the images display at the same time, obviously but it's not working (images are referenced, but don't display).
Anyone know what I am doing wrong?
var w = window.innerWidth;
var h = window.innerHeight;
var xPos = w/2;
var yPos = h/2;
var index = 0;
var imageData;
var imgList = [];
var indexMax;
function preload() {
loadJSON("image_search_result.json", resultLoaded);
}
function resultLoaded(data) {
imageData = data;
indexMax = imageData.items.length;
for (i = 0; i < indexMax; i++) {
imgList.push(imageData.items[i]['link']);
}
}
function mouseReleased() {
index = index + 1;
if (index == indexMax){
index = index - indexMax;
}
}
function setup() {
createCanvas(w,h);
}
function draw() {
background(0);
image(loadImage(imgList[index]),xPos,yPos,w,h);
text(index,20,60); // index counter
text(imgList[index],80,60); // image list number
textSize(20);
fill(255);
}
I think the problem is that you're trying to upload images every call to the drawing function. As you wrote the code, even if the images to be uploaded will always be the same, p5.js will reload them from scratch. You should load them before starting the program. As I did below:
var w = window.innerWidth;
var h = window.innerHeight;
var xPos = w / 2;
var yPos = h / 2;
var index = 0;
var imageData;
var imgList = [];
var indexMax;
function preload() {
loadJSON("img.json", resultLoaded);
}
function resultLoaded(data) {
imageData = data;
indexMax = imageData.items.length;
for (i = 0; i < indexMax; i++) {
url = imageData.items[i]["link"];
imgList.push(loadImage(url));
}
}
function mouseReleased() {
index = index + 1;
if (index == indexMax) {
index = index - indexMax;
}
}
function setup() {
createCanvas(w, h);
}
function draw() {
background(0);
image(imgList[index], xPos, yPos, w, h);
text(index, 20, 60);
textSize(20);
fill(255);
}
P.S. #George Profenza gave the same answer while I was writing the code. Sorry
Finally I got this to work by adding a callback in loadImage. I was unaware you could do this (hadn't seen it referenced in any documentation), but it works very efficiently.
function draw() {
nextImg = loadImage(imgList[index], imageLoaded);
text(index,20,60); // index counter
text(imgList[index],80,60); // image list number
textSize(20);
fill(255);
}
function imageLoaded() {
background(0);
image(nextImg,xPos,yPos,w,h);
imageMode(CENTER);
}
I am making a game with html and javascript. Just for clarification, this is not a duplicate or anything. Nothing has the answer I need. Also before I explain, I want to say I have no trouble with the key listener, my game knows when a key is pressed and when it is released. Okay, I have 5 frames of a character walking. I have a while loop that basically says while the key D is pressed or Right arrow is pressed, then increment the frames to make it look like the character is walking. Then it has a setTimeout function that pauses for 1/10 of a second. This should make it look like the character is walking. I know it has something to do with the setTimeout() function. Here is the while loop:
while (keys[68] || keys[39]) {
charFrame++;
setTimeout(function() {
}, 100);
}
Then here is my code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Sparring Spartans</title>
<style type="text/css">
</style>
</head>
<body>
<canvas id="canvas" width="1000" height="600"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var width = canvas.width;
var height = canvas.height;
var groundX = 0, groundY = 400;
var playerx = width/2, playery = groundY-120;
var charFrame = 1;
var speed = 4;
var keys = [];
window.addEventListener("keydown", function(e) {
keys[e.keyCode] = true;
}, false);
window.addEventListener("keyup", function(e) {
delete keys[e.keyCode];
}, false);
var spartan1 = new Image();
spartan1.src = "spartan1.png";
var spartan2 = new Image();
spartan2.src = "spartan2.png";
var spartan3 = new Image();
spartan3.src = "spartan3.png";
var spartan4 = new Image();
spartan4.src = "spartan4.png";
var spartan5 = new Image();
spartan5.src = "spartan5.png";
var stone = new Image();
stone.src = "stone.png";
function game() {
update();
render();
}
function player() {
if (charFrame === 1) {
context.drawImage(spartan1, playerx, playery);
} else if (charFrame === 2) {
context.drawImage(spartan2, playerx, playery);
} else if (charFrame === 3) {
context.drawImage(spartan3, playerx, playery);
} else if (charFrame === 4) {
context.drawImage(spartan4, playerx, playery);
} else if (charFrame === 5) {
context.drawImage(spartan5, playerx, playery);
}
}
function ground() {
for (var i = 0; i <= 1000; i += 55) {
context.drawImage(stone, i, groundY);
}
for (var i = 0; i <= 1000; i += 55) {
context.drawImage(stone, i, groundY+55);
}
for (var i = 0; i <= 1000; i += 55) {
context.drawImage(stone, i, groundY+110);
}
for (var i = 0; i <= 1000; i += 55) {
context.drawImage(stone, i, groundY+165);
}
}
function manager() {
ground();
while (keys[68] || keys[39]) {
charFrame++;
setTimeout(function() {
}, 100);
}
player();
}
function update() {
manager();
player();
}
function render() {
context.fillStyle = "#AFE4FF";
context.fillRect(0, 0, width, height);
manager();
}
setInterval(function() {
game();
}, 1000/30);
</script>
</body>
</html>
What am I doing wrong? I know it HAS to be the setTimeout, but I have tried to fix this problem many times. The images don't even change.
Because your manager function gets called 30 times per second, you should check your keypress once per frame using an if statement instead of a loop:
function manager() {
ground();
if (keys[68] || keys[39]) {
charFrame++;
}
}
In addition, your manager function is getting called twice per frame, once in the update function and once in the render function. Also, your player function is called both in update and in manager, again twice per frame. Your code will need some refactoring in order to work properly, to make sure nothing gets called twice per frame.
I am recently creating a Game using html5 canvas .The player have multiple state it can walk jump kick and push and multiple other states my question is simple but after some deep research i couldn't find the best way to deal with those multiple states
this is my jsfiddle : http://jsfiddle.net/Z7a5h/5/
i managed to do one animation but i started my code in a messy way ,can anyone show me a way to deal with multiple state animation for one sprite image or just give a useful link to follow and understand the concept of it please .I appreciate your help
if (!this.IsWaiting) {
this.IsWaiting = true;
this.lastRenderTime = now;
this.Pos = 1 + (this.Pos + 1) % 3;
}
else {
if (now - this.lastRenderTime >= this.RenderRate) this.IsWaiting = false;
}
This is my animation class, which let's you set an animation and create the animation as object. I personally like to place the animations in an array such as playerAnimations[], and run the animations according to what the player does.
var toPix = function(n) {
return n*TILE; //tile is basically the same as sh or sw, but I used Tilesizes to draw things.
};
// Animations
var Sprite = function(image, sx, sy, sw, sh) {
this.img = image;
this.sx = sx;
this.sy = sy;
this.sw = sw;
this.sh = sh;
Sprite.prototype.draw = function(ctx, x, y) {
this.x = x;
this.y = y;
this.ctx = ctx;
this.ctx.drawImage(this.img, this.sx, this.sy, this.sw, this.sh, this.x, this.y, this.sw, this.sh);
};
};
var Animation = function(url, ctx, startingRow, rows, columns, sw, sh) {
this.ctx = ctx;
this.url = url;
this.startRow = toPix(startingRow - 1);
this.rows = rows;
this.columns = columns;
this.sprites = [];
animImg = new Image();
animImg.addEventListener('load', function() {});
animImg.src = this.url;
for(var i = 0; i < columns; i++) {
sprite = new Sprite(animImg, i*sw, this.startRow, sw, sh);
this.sprites.push(sprite);
}
this.spriteToDraw = 0;
this.drawSprite = 0;
this.drawSpriteTime = 10;
Animation.prototype.start = function() {
this.stopAnimation = false;
};
Animation.prototype.stop = function() {
this.stopAnimation = true;
};
Animation.prototype.draw = function(x, y) {
if(!this.stopAnimation) {
if(this.spriteToDraw < this.sprites.length) {
var sprite = this.sprites[this.spriteToDraw];
} else {
this.spriteToDraw = 0;
var sprite = this.sprites[this.spriteToDraw];
}
sprite.draw(this.ctx, x, y);
if(this.drawSprite > this.drawSpriteTime) {
this.spriteToDraw++;
this.drawSprite = 0;
} else {
this.drawSprite += 1;
}
}
};
};
//var animation = new Animation('theSprite.png', 5, 5, 45, 45);
//playerAnimations.push(animation);
And then this would be a sample player.draw() function.action.
What it does is: it checks which state the player is in, stops all other animations and runs the correct animation for that state.
player.prototype.draw = function() {
//player.draw function
if(this.playerRight) {
if (this.playerAnimation = playerAnimations[0]) {
this.playerAnimation.stop();
}
if (this.playerAnimation = playerAnimations[2]) {
this.playerAnimation.stop();
}
this.playerAnimation = playerAnimations[1];
this.playerAnimation.start();
this.playerAnimation.draw(this.x, this.y);
} else if(!this.playerRight && !this.playerLeft) {
if (this.playerAnimation = playerAnimations[1]) {
this.playerAnimation.stop();
}
if (this.playerAnimation = playerAnimations[2]) {
this.playerAnimation.stop();
}
this.playerAnimation = playerAnimations[0];
this.playerAnimation.start();
this.playerAnimation.draw(this.x, this.y);
} else {
if(this.playerLeft) {
if (this.playerAnimation = playerAnimations[0]) {
this.playerAnimation.stop();
}
if (this.playerAnimation = playerAnimations[1]) {
this.playerAnimation.stop();
}
this.playerAnimation = playerAnimations[2];
this.playerAnimation.start();
this.playerAnimation.draw(this.x, this.y);
}
};
I hope this is able to help you. This is my way of doing these kind of animations and it works for me, good luck!
So I have these functions to fade a canvas in and out that aren't working the way I expect them to. Here's what I'm working with at the moment:
function fade_out ()
{
var canvas = document.getElementById("builder");
var context = canvas.getContext('2d');
console.log(context.globalAlpha);
context.globalAlpha -= 0.01;
if(context.globalAlpha > 0)
{
setTimeout(fade_out, 5);
}
}
function fade_in ()
{
var canvas = document.getElementById("builder");
var context = canvas.getContext('2d');
context.globalAlpha += 0.01;
if(context.globalAlpha < 1)
{
setTimeout(fade_in, 5);
}
}
My intent was to make it a half second fade. What I ended up with was it just blinking in and out in a flash. The console.log in the first function tells me it's not even close to working the way I expect it to. What went wrong here?
EDIT: There seems to be an endless loop going, and the context.globalAlpha is getting into 20 significant digits, even though I didn't use numbers like that.
function fade_in() {
setTimeout( function() {
var cn = document.getElementById("builder");
var ct = cn.getContext('2d').globalAlpha;
ct += 0.02;
if(ct >= 1) {
ct=1;
}
if (ct < 1) {
fade_in();
}
else {
return false;
}
}, 30);
}
function fade_out() {
setTimeout( function() {
var cn = document.getElementById("builder");
var ct = cn.getContext('2d').globalAlpha;
ct -= 0.02;
if(ct <= 0) {
ct=0;
}
if (ct > 0) {
fade_out();
}
else {
return false;
}
}, 30);
}