From doing research and asking for help I have so far built an animation moving from left to right using the code in the JSFiddle below. This loops every 20 seconds.
http://jsfiddle.net/a9HdW/3/
However now I need a second image that moves from right to left and for this to automatically trigger straight after the first image has completed its animation.
If you could do this that would be amazing.
Thanks In Advance
<canvas id="canvas" width="1600" height="300"></canvas>
<script>
window.requestAnimFrame = (function(){
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
var canvas = document.getElementById("canvas"),
cx = canvas.getContext("2d");
function Card(x,y){
this.x = x || -300;
this.y = y || 0;
this.width = 0;
this.height = 0;
this.img=new Image();
this.init=function(){
// this makes myCard available in the img.onload function
// otherwise "this" inside img.onload refers to the img
var self=this;
this.img.onload = function()
{
// getting width and height of the image
self.width = this.width;
self.height = this.height;
self.draw();
loop();
}
this.img.src = "f15ourbase.png";
}
this.draw = function(){
cx.drawImage(this.img, this.x, this.y);
}
}
var myCard = new Card(50,50);
myCard.init();
function loop(){
if((myCard.x + myCard.width) < canvas.width){
requestAnimFrame(loop);
} else {
setTimeout(function() {
// resetting card back to old state
myCard.x = 50;
myCard.y = 50;
// call the loop again
loop();
}, 20000);
}
cx.clearRect(0, 0, canvas.width, canvas.height);
myCard.x = myCard.x + 15;
myCard.draw();
}
This is little bit complicated, however, it boils down to formatting your Card function to understand which direction it is going to. Therefore you will need direction parameter and more complicated draw function which updates your card movement to direction it is supposed to go, like this:
// Updating own position, based on direction
if(this.direction === 1) {
this.x = this.x + this.stepSize; // we move to right
// if I am over canvas at right, I am done animating
if(this.x >= canvas.width) {
this.finishedAnimation = true;
}
} else {
this.x = this.x - this.stepSize; // we move to left
// if I am over canvas at left, I am done animating
if(this.x <= -this.width) {
this.finishedAnimation = true;
}
}
Also, because timing is important - you will need to trigger other card movement only after the first one is completed. Like this:
// We won't draw next card before previous is finished
if(!cardToRight.finishedAnimation) {
cardToRight.draw();
} else {
// Card at right is finished, we move the left card now
cardToLeft.draw();
}
To summarize my points, I made a code which has code comments to explain it's contents, go it through carefully:
// Animation frame gist
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
// Variable declarations
var canvas = document.getElementById("canvas"),
cx = canvas.getContext("2d"),
// Handlers for both of the cards
cardToRight,
cardToLeft;
/**
* Card declaration
*
*/
var Card = function(x, y, direction) {
// how many pixels we move
this.stepSize = 5;
// x and y position on canvas
this.x = x;
this.y = y;
// Copy values are used when reset is done
this.xCopy = this.x;
this.yCopy = this.y;
// handle to specify if animation finished
this.finishedAnimation = false;
// 1 means move to right, 0 means move to left
this.direction = direction;
// Image of the card
this.img = undefined;
// Image url for this card
this.imgSrc = "http://placehold.it/350x150"; // for your image: "f15ourbase.png"
// Image width
this.width = 0;
};
/**
* Initialize
*
*/
Card.prototype.init = function(callback) {
// self refers to this card
var self = this;
this.img = new Image();
// onload success callback
this.img.onload = function() {
// Setting own width
self.width = this.width;
// triggering callback on successfull load
return callback();
};
// onload failure callback
this.img.onerror = function() {
// Returning error message for the caller of this method
return callback("Loading image " + this.imgSrc + " failed!");
};
// Triggering image loading
this.img.src = this.imgSrc;
};
/**
* Draw self
*
*/
Card.prototype.draw = function() {
// Updating own position, based on direction
if(this.direction === 1) {
this.x = this.x + this.stepSize; // we move to right
// if I am over canvas at right, I am done animating
if(this.x >= canvas.width) {
this.finishedAnimation = true;
}
} else {
this.x = this.x - this.stepSize; // we move to left
// if I am over canvas at left, I am done animating
if(this.x <= -this.width) {
this.finishedAnimation = true;
}
}
// cx (context) could be also passed, now it is global
cx.drawImage(this.img, this.x, this.y);
};
/**
* Reset self
*
*/
Card.prototype.reset = function() {
// Using our copy values
this.x = this.xCopy;
this.y = this.yCopy;
// handle to specify if animation finished
this.finishedAnimation = false;
};
/**
* Main loop
*
*/
function loop() {
// Clear canvas
cx.clearRect(0, 0, canvas.width, canvas.height);
// We won't draw next card before previous is finished
// Alternatively, you could make getter for finishedAnimation
if(!cardToRight.finishedAnimation) {
cardToRight.draw();
} else {
// Card at right is finished, we move the left card now
cardToLeft.draw();
}
// If cardToLeft not yet animated, we are still pending
if(!cardToLeft.finishedAnimation) {
// Schedule next loop
// "return" makes sure that we are not executing lines below this
return requestAnimFrame(loop);
}
// Animation finished, starting again after 5 seconds
setTimeout(function() {
// Resetting cards
cardToRight.reset();
cardToLeft.reset();
// Start the loop again
loop();
}, 5000); // 5000 milliseconds = 5 seconds
};
/**
* Main program below
*
*/
// Card to right (1 denotes it's direction to right)
cardToRight = new Card(50, 50, 1);
// Card to left (0 denotes it's direction to left)
cardToLeft = new Card(1000, 50, 0);
// Initialize cardToRight & cardToLeft
// Because using only two cards, we can do a bit nesting here
cardToRight.init(function(err) {
// If error with image loading
if(err) {
return alert(err);
}
// Trying to initialize cardToLeft
cardToLeft.init(function(err) {
// If error with image loading
if(err) {
alert(err);
}
// All ok, lets do the main program
loop();
});
});
As a special note: If you wan't your cards appear outside the canvas remember to change values of below accordingly:
// Card to right (1 denotes it's direction to right)
cardToRight = new Card(50, 50, 1); // 50 <- x position of right card
// Card to left (0 denotes it's direction to left)
cardToLeft = new Card(1000, 50, 0); // 1000 <- x position of left card
Finally, here is working JsFiddle example
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>
When we create multiple sprites, the function mouseover is called when any hover in hitArea polygon. Regardless, whether applied to another object.
Visibility of sprite governed by sorting the array. The later was added to the sprite in stage.children, the higher it will be. Here is an example in which one rectangle superimposed on the other. At the same time, when we put things on the upper left corner of the bottom sprite, at the top of the object function mouseover will work call, although it is under the other.
How to solve this problem? hitarea not suitable, since the facilities will be constantly dragging.
Thanks in advance for your reply!
var stage = new PIXI.Stage(0x97c56e, true);
var renderer = PIXI.autoDetectRenderer(window.innerWidth, window.innerHeight, null);
document.body.appendChild(renderer.view);
renderer.view.style.position = "absolute";
renderer.view.style.top = "0px";
renderer.view.style.left = "0px";
requestAnimFrame( animate );
var texture = new PIXI.RenderTexture()
r1 = new PIXI.Graphics()
r1.beginFill(0xFFFF00);
r1.drawRect(0, 0, 400, 400)
r1.endFill()
texture.render(r1);
var texture2 = new PIXI.RenderTexture()
r1 = new PIXI.Graphics()
r1.beginFill(0xDDDD00);
r1.drawRect(0, 0, 300, 300)
r1.endFill()
texture2.render(r1);
createBunny(100, 100, texture)
createBunny(120, 120, texture2)
function createBunny(x, y, texture) {
var bunny = new PIXI.Sprite(texture);
bunny.interactive = true;
bunny.buttonMode = true;
bunny.anchor.x = 0.5;
bunny.anchor.y = 0.5;
bunny.scale.x = bunny.scale.y = 0.5;
bunny.mouseover = function(data) {
console.log('mouse over!')
}
bunny.mousedown = bunny.touchstart = function(data) {
this.data = data;
this.alpha = 0.9;
this.dragging = true;
this.sx = this.data.getLocalPosition(bunny).x * bunny.scale.x;
this.sy = this.data.getLocalPosition(bunny).y * bunny.scale.y;
};
bunny.mouseup = bunny.mouseupoutside = bunny.touchend = bunny.touchendoutside = function(data) {
this.alpha = 1
this.dragging = false;
this.data = null;
};
bunny.mousemove = bunny.touchmove = function(data) {
if(this.dragging) {
var newPosition = this.data.getLocalPosition(this.parent);
this.position.x = newPosition.x - this.sx;
this.position.y = newPosition.y - this.sy;
}
}
bunny.position.x = x;
bunny.position.y = y;
stage.addChild(bunny);
}
function animate() {
requestAnimFrame( animate );
renderer.render(stage);
}
http://jsfiddle.net/sD8Tt/48/
I know this is old thread, but for those who come to this page, the issue can be fixed by extending the PIXI's Sprite Class, Look at the following code.
PIXI.Sprite.prototype.bringToFront = function() {
if (this.parent) {
var parent = this.parent;
parent.removeChild(this);
parent.addChild(this);
}
}
And call above method in mousedown event like this
this.bringToFront();
Working JSFiddle
http://jsfiddle.net/6rk58cqa/
I am currently developing a Javascript game (almost everything is based on a tutorial yet, so I am not worried of sharing the code).
The problem is, I can't get the character to jump after pressing the Space button. Please, can someone look at the code and help me?
// EDIT: Sorry for lack of information I provided. The thing is - code is written, the game is in the state, that the character is animated (=is running) and the backgrounds are moving. Yesterday, I tried to implement some basic controls, such as jump by pressing spacebar. The thing is, the player won't jump at all, and browser console is not giving me any error statements.
Character is defined as Player on line 5. and 321. in the code provided below.
The jumping is defined in the following examples:
Pressing the Space button
var KEY_CODES = {
32: 'space'
};
var KEY_STATUS = {};
for (var code in KEY_CODES) {
if (KEY_CODES.hasOwnProperty(code)) {
KEY_STATUS[KEY_CODES[code]] = false;
}
}
document.onkeydown = function(e) {
var keyCode = (e.keyCode) ? e.keyCode : e.charCode;
if (KEY_CODES[keyCode]) {
e.preventDefault();
KEY_STATUS[KEY_CODES[keyCode]] = true;
}
};
document.onkeyup = function(e) {
var keyCode = (e.keyCode) ? e.keyCode : e.charCode;
if (KEY_CODES[keyCode]) {
e.preventDefault();
KEY_STATUS[KEY_CODES[keyCode]] = false;
}
};
Other jump information (please, read the comments in the code)
this.update = function() {
// jump, if the characted is NOT currently jumping or falling
if (KEY_STATUS.space && this.dy === 0 && !this.isJumping) {
this.isJumping = true;
this.dy = this.jumpDy;
jumpCounter = 12;
assetLoader.sounds.jump.play();
}
// longer jump if the space bar is pressed down longer
if (KEY_STATUS.space && jumpCounter) {
this.dy = this.jumpDy;
}
jumpCounter = Math.max(jumpCounter-1, 0);
this.advance();
// gravity
if (this.isFalling || this.isJumping) {
this.dy += this.gravity;
}
// change animation is-falling
if (this.dy > 0) {
this.anim = this.fallAnim;
}
// change animation is-jumping
else if (this.dy < 0) {
this.anim = this.jumpAnim;
}
else {
this.anim = this.walkAnim;
}
this.anim.update();
};
/**
* Update the Sprite's position by the player's speed
*/
this.update = function() {
this.dx = -player.speed;
this.advance();
};
/**
* Draw the current player's frame
*/
this.draw = function() {
this.anim.draw(this.x, this.y);
};
}
Player.prototype = Object.create(Vector.prototype);
Everything seems just fine to me, but the player just won't move. :(
Any help?
If you are curious about the full code, go here: http://pastebin.com/DHZKhBMT
EDIT2:
Thank you very much for your replies so far.
I have moved the RequestAnimFrame to the end of the function - will keep that in mind, thanks.
I have also implemented the simple jumping script Ashish provided above, but the character is still not jumping.
This is what it looks like now:
/** JUMP KEYS DEFINITION **/
$(document).keypress(function(e){
if(e.which==32){
$('Player.prototype').css({'top':"0px"});
}
setTimeout(function(){
$('Player.prototype').css({'top':"200px"});
},350);
});
/** DEFINING CHARACTER **/
function Player(x, y) {
this.dy = 0;
this.gravity = 1;
this.speed = 6;
this.jumpDy = -10;
this.isJumping = false;
this.width = 60;
this.height = 96;
this.sheet = new SpriteSheet('imgs/normal_walk.png', this.width, this.height);
this.walkAnim = new Animation(this.sheet, 4, 0, 11);
this.jumpAnim = new Animation(this.sheet, 4, 3, 3);
this.fallAnim = new Animation(this.sheet, 4, 3, 3);
this.anim = this.walkAnim;
Vector.call(this, x, y, 0, this.dy);
var jumpCounter = 0; // Maximalna dlzka drzania tlacidla skakania
}
Player.prototype = Object.create(Vector.prototype);
Where am I wrong?
I've tried in http://jsfiddle.net/Ykge9/1/
and you have an infinite loop in animate, the requestAnimFrame should be at the end of the function:
/**
* Loop cykly hry
*/
function animate() {
background.draw();
for (i = 0; i < ground.length; i++) {
ground[i].x -= player.speed;
ctx.drawImage(assetLoader.imgs.grass, ground[i].x, ground[i].y+250);
}
if (ground[0].x <= -platformWidth) {
ground.shift();
ground.push({'x': ground[ground.length-1].x + platformWidth, 'y': platformHeight});
}
player.anim.update();
player.anim.draw(64, 260);
requestAnimFrame( animate );
}
I am trying to change the position of a circle inside a canvas using random x and y when hitting the space bar but i am stuck to figure out how I should implement a gravity effect so when the circle change it's position it come back down to the ground in a smoothy way
my jsfiddle :http://jsfiddle.net/seekpunk/efcnM/5/
how can i modify my update function to succeed my gravity effect
function update() {
$(window).keydown(function (e) {
var spacebarHit = e.which == 32 || e.keyCode == 32 ? true : false;
if (spacebarHit) {
Bluecircle.y -=1;// RandomPos;
Draw();
}
});
}
Why not use the real-world equations of motion?
if (spacebarHit) {
var oldPos = Bluecircle.y;
var u = 50;
var g = 9.81;
var t = 0;
var handle = setInterval(function () {
t++;
Bluecircle.y = oldPos-(((u)*t-(g/2)*t*t));
console.log(Bluecircle.y);
if (Bluecircle.y>oldPos) {
Bluecircle.y = oldPos;
clearInterval(handle);
}
}, 100);
Draw();
}
DEMO
Use Newtonian integration:
function mainLoop(dt) {
circle.acc.x = 0
circle.acc.y = 9.81 // positive is down
circle.vel.x += circle.acc.x * t
circle.vel.y += circle.acc.y * t
circle.pos.x += circle.vel.x * t
circle.pos.y += circle.vel.y * t
// check if the bottom of the screen has been hit, and
// clamp circle.poa to he within the world
// do bounces by flipping the sign of components of circle.vel
}
function jump() {
circle.vy = -20; // or something
}
I have created fixed city having few path.
On that I want to make specific path where I can move characters from start to and point.
Here is the canvas map
When I tried this http://jsfiddle.net/nathggns/HG752/light/ example code move on map Iy just show white background instead of canvas city map.
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
// Grab our context
var context = canvas.getContext('2d');
// Make sure we have a valid defintion of requestAnimationFrame
var requestAnimationFrame =
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame ||
function(callback) {
return setTimeout(callback, 16);
};
// Let's define our square
var square = {
'x': 50,
'y': 50,
'width': 10,
'height': 10,
'fill': '#000000'
};
var render = function() {
// Clear the canvas
context.clearRect(0, 0, canvas.width, canvas.height);
// Draw the square
context.beginPath();
context.rect(square.x, square.y, square.width, square.height);
context.fillStyle = square.fill;
context.fill();
// Redraw
requestAnimationFrame(render);
};
// Start the redrawing process
render();
var animate = function(prop, val, duration) {
// The calculations required for the step function
var start = new Date().getTime();
var end = start + duration;
var current = square[prop];
var distance = val - current;
var step = function() {
// Get our current progres
var timestamp = new Date().getTime();
var progress = Math.min((duration - (end - timestamp)) / duration, 1);
// Update the square's property
square[prop] = current + (distance * progress);
// If the animation hasn't finished, repeat the step.
if (progress < 1) requestAnimationFrame(step);
};
// Start the animation
return step();
};
animate('x', 0, 1000);
setTimeout(function() {
animate('y', 0, 1000);
setTimeout(function() {
animate('x', 50, 1000);
animate('y', 50, 1000);
}, 1000);
}, 1000);
var meta = function(e) {
// Set some initial variables
var distance = 100;
var prop = 'x';
var mult = 1;
// Just return false if the key isn't an arrow key
if (e.which < 37 || e.which > 40) {
return false;
};
// If we're going left or up, we want to set the multiplier to -1
if (e.which === 37 || e.which === 38) {
mult = -1;
}
// If we're going up or down, we want to change the property we will be animating.
if (e.which === 38 || e.which === 40) {
prop = 'y';
};
return [prop, mult * distance];
};
document.body.addEventListener('keydown', function(e) {
var info = meta(e);
if (info) {
e.preventDefault();
animate(info[0], square[info[0]] + info[1], 1000);
};
});
document.body.addEventListener('keyup', function(e) {
var info = meta(e);
if (info) {
e.preventDefault();
animate(info[0], square[info[0]], 1000);
};
});
};
Thanks in advance !
i will not give you full code, but will show you the way. Do not forget to use several layers. It is 100x faster. http://jsfiddle.net/HG752/7/
Also think about having digital smarter version of map, that you can check on every move. Like matrix where 1 block is 10x10 pixels having true/false. Also on redraw do just minimal things. For example calculating var img_back and var imgData on each redraw is big mistake. But this is just example :)
var canvas = document.getElementById('canvas');
var canvas_back = document.getElementById('canvas_back');
...
var img_back = canvas_back.getContext('2d').getImageData(0, 0, W, H);
var imgData = img_back.data;
var x = (Math.round(square.x) + Math.round(square.y)*W) * 4;
//get background color where i am
document.getElementById('log').innerHTML = imgData[x]+'+'+imgData[x+1]+'+'+imgData[x+2];