Animate a flying bird in p5.js - javascript

I want to create an animation of a bird with p5 js. I have 6 pictures of the bird - when the wings are up, in the middle, and so on... When I press 'space bar' on the keyboard, the bird should fly - so all the pics should be shown as an animation (as if the bird is really flying). I want to build this code snippet without spritemap.
This is my code, but somehow it doesn't work..
let time = 0;
let frame = 0;
let img = [];
function preload() {
img.push(loadImage("assets/Bird/bird-1.png"));
img.push(loadImage("assets/Bird/bird-2.png"));
img.push(loadImage("assets/Bird/bird-3.png"));
img.push(loadImage("assets/Bird/bird-4.png"));
img.push(loadImage("assets/Bird/bird-5.png"));
}
function draw() {
function keyPressed() {
if (key == ' ') {
const speed = 1;
const numImage = img.length;
let current = frame % numImage;
let display = img[current];
image(display, width / 2, height / 2, display.width, display.length);
time += speed;
if (time > 5) {
time = 0;
frame++;
}
}
}
}
Looking forward to reading some ideas! Thank you in advance.

First things first you should not need to handle frames and such things. It is better to use keyPressed function outside of scope draw since it is a special event function and automatically called when a key is pressed.
It is better to use setup functionality instead of preload since preload is a little bit more early function then we needed. Setup is more relevant in such things like loading an array and so on.
I see that you forgot to create a canvas to draw an image on it. I added that on setup and also set the framerate of canvas regarding the img array's size.
function setup() {
createCanvas(400, 400);
background(51);
img.push(loadImage("1.png"));
img.push(loadImage("2.png"));
img.push(loadImage("3.png"));
img.push(loadImage("4.png"));
frameRate(img.length * 2); // double speed on animate sprites
}
From this point it is only a matter of checking the keyCode and looping through array.
function draw() {
if (keyIsDown(32)) {
background(51);
const numImage = img.length;
let current = frameCount % numImage;
let display = img[current];
image(display, width / 2 - display.width , height / 2 - display.height , display.width, display.length);
}
}
Here in the keyIsDown(32) check, 32 represents spacebar. You can check others from here easily : http://keycode.info/
You want to re-set the background of canvas on each sprite display. If not, they will still be showing on each render.
You can see the working version of your code in here :
https://editor.p5js.org/darcane/sketches/rVl22hkv7

Related

Matter.js: Method to count how many times that an object has rotated?

I am creating a project in which a body is picked up and thrown by the user (with a mouse constraint). The body is set so that it can pivot about the constrain point. I need to find out, from the moment that it is let go, how many times it fully rotates (+-360 degrees) before landing. Reading the documentation, the only thing that I could find regarding the rotation was Matter.Body.rotate() which actually just sets the rotation of a body instead of recording it. How should I go about this?
Basically: How can I count an objects rotations?
This worked for me tbh:
var rad = 6.28;
var nrad = -6.28;
Events.on(engine, "tick", function () {
if(boxA.angle > rad){
rad+=6.28;
nrad+=6.28;
hrt +=1;
//hrt is the rotation c0unter
}
if (boxA.angle < nrad){
nrad-=6.28;
rad-=6.28;
hrt +=1;
}
rnum.innerHTML = "Spins: " + hrt;
fnum.innerHTML = fcounter; });

Have particles appear OnClick function in p5.js

New to p5.js and trying to learn more every day. Basically, I am currently learning about particle systems and objects, and getting confused by the amount of code. Anyways, I'd like that on function mousePressed(), an array of particles (particle system) that I've created appears. It'd also be awesome if the particle system could trail the position of the mouse. So, basically, if you click your mouse on the screen particles appear in that position, and also trail your mouse.
I can't figure out what I'm missing in the code. I feel kind of lost about what half of it is even doing (my professor wrote a lot of it). When I add in the mousePressed function, everything goes to pot. I feel like I'm too overwhelmed to even know what's missing. Any help, plus detailed insight into what I need to do and why that solution works would be super appreciated. Thank you!
var particles = [];
var now = null;
function setup() {
createCanvas(windowWidth, windowHeight);
}
function draw() {
background(255, 25, 25);
function mousePressed() {
particles.push(new Particle(new p5.Vector(mouseX, mouseY)));
//particles.push(new Particle(new p5.Vector(width / 2, height / 1.5)));
for (var i = 0; i < particles.length; i++) {
// if our particle is dead, remove it
if (particles[i].lifespan <= 0) {
//splice is a way of removing a specific
//element from an array
particles.splice(i, 2);
} else {
particles[i].update();
particles[i].display();
}
//this.particle = new ParticleSystem(createVector(mouseX, mouseY));
// patricles.push(p);
}
}
}
function Particle(loc) {
this.loc = loc;
this.acc = new p5.Vector();
this.vel = new p5.Vector(random(-100, 100), random(-2, 0));
this.lifespan = 555;
}
Particle.prototype = {
constructor: Particle,
update: function() {
this.vel.add(this.acc);
this.loc.add(this.vel);
this.lifespan -= 4.0;
},
display: function() {
stroke(random(0), this.lifespan);
fill(random(255), random(255), random(255))
ellipse(this.loc.x, this.loc.y, 20, 20);
}
}
First of all, your mousePressed() function is inside your draw() function. That doesn't make a ton of sense. You want your mousePressed() function to be at the same level as your draw() function.
function draw(){
//draw code here
}
function mousePressed(){
//mousePressed code here
}
If I were you, I would start smaller. Can you create a program that draws a single ellipse? Can you then make it so that single ellipse appears when you click the mouse? Then can you have that ellipse follow the mouse? Only if you can get that working perfectly by itself, then you should start thinking about adding multiple ellipses.
You're trying to go from your end goal and work backwards, which is just going to confuse you. Instead, start from the simplest sketch possible and take one small step at a time. Then if you get stuck you can post an MCVE along with a specific question, and it'll be easier to help you.

life decrease on collision

I am making a little game using HTML5 Canvas and javascript. I am so far that I have a kite moving some sort of power up on collision and an obstacle on collision.
Now I'm at the point I want to add lives and when you hit an obstacle your life will decrease 1.
I tried some stuff and when you hit an obstacle the life decreases but it decreases constantly and the player image gets removed instead of the obstacle image.
here is the life thing you can check all the code there.
http://nickzijlstra.com/kite
Here the code I think is the most important for the problem.
function hitObject(player, obj){
var a = (obj.x - player.x),
b = (obj.y - player.y),
c = Math.sqrt(a*a + b*b),
r0 = player.image.width/2,
r1 = obj.image.width/2;
if (c < r0+r1) {
player.drawable = false;
lifes -=1;
window.location.reload(true);
}
}
If someone sees the problem or knows the solution I would really appreciate it!
The reason the player disappears is because of this line in the hitObject function:
player.drawable = false;
This will cause the player to not be drawn because of this condition in your drawing function:
if (player.drawable == true) {
context.drawImage(player.image, player.x, player.y, player.image.width, player.image.height);
}
I presume you actually want to move the obj back to a random spot on the top of the screen if the player gets hit. It doesn't do this at the moment, which is why the lives go down rapidly: the object hits the player, it removes a life, and then the next frame it hits the player again (even though the player isn't visible).
What you might want is something like:
...
if (c < r0+r1) {
lifes -=1;
// Respawn the object.
obj.y = -50;
obj.x = Math.random() * canvas.width;
...
At a guess, I'd say that you should replace the
player.drawable = false;
with
obj.drawable = false;
and wrap the whole collision detection inside of an if obj.drawable=true so that removed obstacles won't collide with the kite.

JS Canvas Collision-Detection using getImageData

As a very inexperienced programmer, I'm trying to code a game that detects when the player collides with certain colors on the canvas. I have a black square with coordinates "player.x" and "player.y" and dimensions 50x50 that moves around when you press the arrow keys. I also have a stationary red (255,0,0) square elsewhere on the canvas.
The function below is supposed to grab a slightly larger square around the "player" square and find out if there's any red in it. If there is, it will send up an alert. The problem is, this doesn't seem to be working.
function collideTest(){
var canvas = document.getElementById("canvas");
var c = canvas.getContext("2d");
var whatColor = c.getImageData(player.x - 5, player.y - 5,60,60);
for (var i = 0; i < 3600; i++) {
if (whatColor.data[i] == 255) {
alert("red");
}
}
}
I'm semi-aware that this is not the most efficient way to detect red pixels, but I wanted to simplify the code before posting it here. Is there something obviously wrong with the function?
The problem could lie in the way the function is called. It gets called at the end of another function that detects user-input and changes the coordinates of the "player" square. THAT function gets called right before everything is drawn on the canvas.
Thanks in advance for any help!
var whatColor = c.getImageData(player.x - 5, player.y - 5,60,60);
player.x and player.y must not be decimal, make sure they are rounded or getImageData will be angry and not play nice.
For each single pixel on the canvas, the whatColor.data array holds 4 sequential pieces of color information: red,green,blue,alpha(opacity). So the whatColor.data looks like this for each pixel:
whatColor.data[i] is the red component of the color.
whatColor.data[i+1] is the green component of the color.
whatColor.data[i+2] is the blue component of the color.
whatColor.data[i+3] is the alpha(opacity) component of the color.
So your iteration would look like this (4 indexes per pixel):
for(var i = 0, n = whatColor.data.length; i < n; i += 4) {
var red = whatColor.data[i];
var green = whatColor.data[i + 1];
var blue = whatColor.data[i + 2];
var alpha = whatColor.data[i + 3];
if(red==255){ ... it's a hit, do your thing! ... }
}
See here for a mini-tutorial on the imageData.data array: http://www.html5canvastutorials.com/advanced/html5-canvas-get-image-data-tutorial/
By the way, you might look at one of the canvas libraries that simplify game making with canvas. Here are just a few: easelJs, KineticJs, FabricJs, and more!

HTML5 Canvas image rotation with dynamic values and images

I have the following code -
for(var i = 0; i < treesLength; i++){
var tmpTree = trees[i];
tmpTreeX = 1+Math.random()*($("#gameBoard").width()-95);
tmpTreeY = 1+Math.random()*($("#gameBoard").height()-90);
var imgTreeFile = new Image();
imgTreeFile.onload = function() {
context.save();
context.translate(tmpTreeX,tmpTreeY);
context.rotate(47 * Math.PI / 180);
context.translate(-tmpTreeX,-tmpTreeY);
context.drawImage(imgTreeFile, tmpTreeX, tmpTreeY);
context.restore();
};
imgTreeFile.src = 'img/tree.png';
}
What I am trying to achieve is to add 'n' amount of images to the canvas (That happen to be trees) I want to rotate the images a random amount of radians. Currently just to get it working I have set this number rather than randomly generate the radians.
If I do no try to rotate the images, I successfully get all the images in the loop randomly placed throughout the canvas. When I try to rotate I just get all of the images in the same place with no rotation.
Can anyone point me in the right direction, my searching has only left me frustrated as I "appear" to be doing it correctly (Clearly I am not!)
In a quick test here there doesn't seem to be an issue: http://jsfiddle.net/ZZ7MQ/
But I do notice two weird things about your code:
.width() and not .width seems weird, but maybe thats a jQuery thing? it should be canvas.width in any case.
You are using a loop variable inside of code called asynchronously, which is 99% likely your problem. I highly recommend that you refactor your code so that all the images are loaded before the loop ever happens. If they are all the same image, that makes this very easy:
var imgTreeFile = new Image();
imgTreeFile.onload = function() {
for(var i = 0; i < treesLength; i++){
var tmpTree = trees[i];
tmpTreeX = 1+Math.random()*($("#gameBoard").width()-95);
tmpTreeY = 1+Math.random()*($("#gameBoard").height()-90);
context.save();
context.translate(tmpTreeX,tmpTreeY);
context.rotate(47 * Math.PI / 180);
context.translate(-tmpTreeX,-tmpTreeY);
context.drawImage(imgTreeFile, tmpTreeX, tmpTreeY);
context.restore();
}
};
imgTreeFile.src = 'img/tree.png';

Categories