Constructor not working properly in p5 js - javascript

I am having problems with p5 js.
I am trying to add two ellipse objects that spin around the circumference of a circle.
The code below represents the constructor function of the object :
function Obj(){
this.ang = TWO_PI;
this.x = w/2 + cos(ang)*r;
this.y = h/2 + sin(ang)*r;
this.fil = 255;
this.size = 28;
this.show = function(){
noStroke();
fill(this.fil);
ellipse(this.x,this.y,this.size,this.size);
}
this.update = function(){
this.ang+=.02;
}
}
And this is the main file :
let w = innerWidth;
let h = innerHeight;
let xd = [];
let r = 200;
function setup() {
createCanvas(w, h);
for (let i = 0; i < 2; i++)
xd[i] = new Obj();
}
function draw(){
background(0,70,80);
noFill();
strokeWeight(7);
stroke(255);
ellipse(w/2, h/2, r*2, r*2);
xd[0].update();
xd[0].show();
}
The problem is that it says that ang is not defined even though i did clearly define it with this.ang = TWO_PI;. And if I declare it in the main file and in setup() I say ang = TWO_PI; the object stays in place. Can anyone help ?
Thank you.

The problem in the constructor function in this code, it should be like this :
this.x = w/2 + cos(this.ang)*r;
this.y = h/2 + sin(this.ang)*r;
Because you are using a property from the constructor function itself

Related

Use p5js functions with node, npm minification

I am trying to convert a sketch to use node and bundle a distribution js file. My guess is that some of the function names in p5js must be reserved (to combat this I was going to use a development flag so as not to obfuscate the code at least for testing).
In order to encapsulate the code I am using this method:
let sketch = function(p) {
p.setup = function() {
...
}
let myp5 = new p5(sketch);
Everything seems to work fine except I cannot call the show function from inside my particle Class (ReferenceError: noStroke is not defined)
Here is the full js:
let canvasBG;
let particles = [];
let audioFile;
let amplitude;
let vol;
let loaded = false;
let x = 0;
let xoff = 0;
let yoff = 0;
let sketch = function(p) {
p.setup = function() {
canvasBG = p.createCanvas(p.windowWidth, p.windowHeight);
audioFile = p.loadSound("audio/mom.mp3", p.audioLoaded);
amplitude = new p5.Amplitude();
p.rectMode(p.CENTER);
p.frameRate(30);
canvasBG.background(255);
}
p.audioLoaded = function() {
audioFile.play();
audioFile.loop();
loaded = true;
}
p.draw = function() {
let nx = p.noise(xoff) * p.windowWidth;
let ny = p.noise(yoff) * p.windowHeight;
xoff = xoff + 0.01;
yoff = yoff + 0.02;
vol = amplitude.getLevel();
let volumeGate = p.map(vol, 0, 1, p.random(5,12), p.random(80, 550));
if (loaded) {
let b = new Particle(nx, ny, volumeGate);
particles.push(b);
if (volumeGate > 75) {
canvasBG.background(p.random(255), p.random(255), p.random(255));
}
for (let particle of particles) {
particle.show();
}
if (particles.length >= 10) {
particles.splice(0, 1);
}
} else {
x+= 0.05;
p.translate (p.windowWidth - 30, 30);
p.rotate(x);
p.noStroke();
p.rect(0, 0, 2, 40, 0.1);
p.fill(0, 0, 0, x * 3);
}
}
}
class Particle {
constructor(x, y, r) {
this.x = x;
this.y = y;
this.r = r;
}
show() {
noStroke(); // this is throwing an error
fill(random(0, 255), random(0, 255), random(0, 255), random(100,255));
ellipse(this.x, this.y, this.r * 2);
}
}
let myp5 = new p5(sketch);
You can run the current full demo here: https://editor.p5js.org/lharby/sketches/wPF908tqX
I've tried converting the class to a function and passing in arguments, similarly an object and then attaching a function to the object, but can't seem to get anything to work plus I would rather keep the Class as it is.
How is the best way to go about this?
You're super close!
Because you're using p5 in instance mode, p5 functions (such as noStroke(), fill(), ellipse()) won't be available in the global scope, but through the p reference.
In your class you simply need to pass p as well, similar to how you've already used it with the rest of the code:
class Particle {
constructor(x, y, r) {
this.x = x;
this.y = y;
this.r = r;
}
show(p) {
p.noStroke();
p.fill(p.random(0, 255), p.random(0, 255), p.random(0, 255), p.random(100,255));
p.ellipse(this.x, this.y, this.r * 2);
}
}
and in draw pass the reference to p5:
//...
for (let particle of particles) {
particle.show(p);
}
//...

How to constantly generate a moving shape with Javascript and Canvas

I'm currently developing a small game for my capstone project. In the game, the user tries to avoid rectangles of random sizes the move from the right side of the screen to the left at a set speed.
It's built using object-oriented Javascript, and I've assigned it an anonymous function, however, I can't seem to get it to generate a shape and animate it more than the initial time the function is called. The problem can be solved if I create more than one object, but I would like this function to run automatically and generate more than just the first rectangle.
I've tried to call the function with an interval to force it to re-run the function with no results. I also attempted to separate the initialization function to call it with a parameter to generate the number of shapes given to it.
This is the function that generates the shape with the initial call, and determines the color, size, and location as well as draws it on the canvas.
var randomRectangle = function(){
this.init = function() {
this.speed = 4;
this.x = canvas.width-50;
this.y = Math.floor(Math.random()*280) + 40;
this.w = Math.floor(Math.random()*200) + 50;
this.h = Math.floor(Math.random()*150) + 20;
this.col = "#b5e61d";
}
this.move = function(){
this.x -= this.speed;
}
this.draw = function(num){
draw.rectangles(this.x, this.y, this.w, this.h, this.col);
}
};
This is where the object is initialized and the loop generates all objects and animations on the canvas.
randRecs = new randomRectangle();
randRecs.init();
function loop(){
draw.clear();
player.draw();
player.move();
wall1.draw();
wall2.draw();
randRecs.draw();
randRecs.move();
}
var handle = setInterval(loop, 30);
I expected the rectangle to continuously be generated at a new y-coordinate with a new size, then move from the right side of the screen to the left. However, only one rectangle is created and animated.
var list = [];
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
var randomRectangle = function() {
this.init = function() {
this.speed = 4;
this.x = canvas.width - 50;
this.y = Math.floor(Math.random() * 280) + 40;
this.w = Math.floor(Math.random() * 200) + 50;
this.h = Math.floor(Math.random() * 150) + 20;
this.col = "#b5e61d";
}
this.move = function() {
this.x -= this.speed;
// restart x position to reuse rectangles
// you can change the y value here to a new random value
// or you can just remove with array.splice
if (this.x < -50) this.x = canvas.width - 50;
}
this.draw = function(num) {
draw.rectangles(this.x, this.y, this.w, this.h, this.col);
}
};
function loop() {
draw.clear();
//player.draw();
//player.move();
//wall1.draw();
//wall2.draw();
// call the methods draw and move for each rectangle on the list
for (var i=0; i<list.length; i++) {
rec = list[i];
rec.draw();
rec.move();
}
}
// spawn any number of new rects in a specific interval
var rectsPerSpawn = 1;
function addRects() {
for (var i=0; i<rectsPerSpawn; i++) {
if (list.length < 100) {
var rec = new randomRectangle();
list.push(rec);
rec.init();
}
}
}
// every half second will spawn a new rect
var spawn = setInterval(addRects, 500);
var draw = {
clear: function () {
ctx.clearRect(0,0,canvas.width,canvas.height);
},
rectangles: function (x, y, w, h, col) {
ctx.fillStyle = col;
ctx.fillRect(x,y,w,h);
}
}
var handle = setInterval(loop, 30);
<canvas></canvas>

javascript and html canvas animation image emitter

Hello I have been watching some tutorials on HTML canvas and animations and I wanted to create my own. I am having trouble though. :/
I am trying to create some clouds that start on the left side of the screen and move to the right side of the screen, and will eventually disappear when they get to a certain point. I don't have that code yet. I don't know how to handle transparency. But, that is not where my troubles lie.
Currently, my clouds do not move. I can generate 20 different clouds in different locations but they are failing to move. I have checked my code with other tutorials and I can not seem to find why it's not working. Maybe because I am using an image?? If I could find some help I would really appreciate it. Thank you.
$(function(){
var leftcloudsrc = "ls/pics/cloud1.png";
var rightcloudsrc = "ls/pics/cloud2.png";
var canvas = document.getElementById('cloud');
var cw = canvas.width;
var ch = canvas.height;
var cloudsArray = [];
createclouds();
function createclouds(){
for (var i=0; i < 20; i++){
var x = Math.random() * 150;
var y = Math.random() * 300;
var v = Math.random() * 4;
cloudsArray.push(new Cloud(x, y, v));
}
animate();
console.log(cloudsArray);
}
function animate(){
requestAnimationFrame(animate);
for (var i = 0; i<cloudsArray.length; i++){
cloudsArray[i].move();
//new Cloud(x, y, v).create();
}
}
function Cloud(x, y, v){
this.x = x;
this.y = y;
this.v = v;
this.create = function(){
img = new Image,
ctx = document.getElementById('cloud').getContext('2d');
img.src = leftcloudsrc;
var iw = img.naturalWidth;
var ih = img.naturalHeight;
ctx.drawImage(img, x, y);
}
this.move = function(){
this.x += this.v;
this.create();
}
}
// var cloud = new Cloud(0,0,0);
// cloud.create();
});
i have tried writing to the console to make sure the information is saving and sticking, and yes, it is. i have even tried writing the .move() function to console to make sure the data changes, and it does. but it does not reflect visually???
ctx.drawImage(img, x, y); // wrong
ctx.drawImage(img, this.x, this.y); // right
You arent updating x and y. You are updating this.x and this.y
full code
// test
var leftcloudsrc = "http://www.freepngimg.com/download/cloud/10-cloud-png-image.png";
var rightcloudsrc = "ls/pics/cloud2.png";
var canvas = document.getElementById('cloud');
// you dont have to define ctx again and again
var ctx = canvas.getContext('2d');
var cw = canvas.width;
var ch = canvas.height;
var cloudsArray = [];
createclouds();
function createclouds() {
for (var i = 0; i < 20; i++) {
var x = Math.random() * 150;
var y = Math.random() * 300;
var v = Math.random() * 4;
cloudsArray.push(new Cloud(x, y, v));
}
animate();
console.log(cloudsArray);
}
function animate() {
requestAnimationFrame(animate);
ctx.clearRect(0, 0, cw, ch)
for (var i = 0; i < cloudsArray.length; i++) {
var c = cloudsArray[i]
c.move();
// remove when crosses the canvas width
if(c.x >= 500) {
cloudsArray.splice(i, 1);
}
//new Cloud(x, y, v).create();
}
}
function Cloud(x, y, v) {
this.x = x;
this.y = y;
this.v = v;
this.create = function() {
// invoke the constructor
var img = new Image;
img.src = leftcloudsrc;
var iw = img.naturalWidth;
var ih = img.naturalHeight;
ctx.drawImage(img, this.x, this.y);
}
this.move = function() {
this.x += this.v;
this.create();
}
}
<canvas id="cloud" width="500" height="400"></canvas>

How to make multiple elements in a canvas

I'm trying to show multiple pipes in the canvas of same height but even after using a for loop it is showing a single pipe and not a lot of it
<script>
var tryCanvas = document.getElementById("myCanvas");
var c = tryCanvas.getContext("2d");
var myCall = [];
function Squares() {
for(var i =0; i < 10; i++){
this.x = Math.random()* tryCanvas.clientWidth;
this.y = 0;
this.w = 20;
this.h = 60;
this.counter = 0;
this.draw = function() {
c.beginPath();
c.rect(this.x, this.y, this.w, this.h)
c.fill();
}
}
this.update = function() {
if(this.x < 0){
this.x = 0;
}
this.x -= 1;
this.draw();
}
}
var holder = new Squares;
setInterval(callFun, 10);
function callFun() {
c.clearRect(0,0,tryCanvas.clientWidth, tryCanvas.clientHeight);
holder.update();
}
</script>
If I push the constructor function in an array it's not showing anything in the canvas and in the console it's giving undefined or NaN.
But if I do it without "this" its generating the number of rects.
What am I doing wrong here?
Updated to move the bars along the screen
See this working example:
https://codepen.io/bkfarns/pen/braWQB?editors=1010
This.draw will only get created with the values from the last iteration of the for loop.
Also as a side node, usually instead of new Squares you call the constructor like new Squares(). When you call the constructor you are calling a method.
But I think the code below fixes your issues. Try it out:
<body>
<canvas id="myCanvas"/>
</body>
<script>
var tryCanvas = document.getElementById("myCanvas");
var c = tryCanvas.getContext("2d");
var myCall = [];
function Squares() {
this.draw = function(xOffset) {
for(var i =0; i < 10; i++){
this.x = (i * xOffset) + (5*i)//Math.random()* tryCanvas.clientWidth;
this.y = 0;
this.w = 20;
this.h = 60;
c.beginPath();
c.rect(this.x, this.y, this.w, this.h)
c.fill();
}
}
}
var holder = new Squares();
var xOffset = 20;
setInterval(function() {
c.clearRect(0,0,tryCanvas.clientWidth, tryCanvas.clientHeight);
holder.draw(xOffset)
xOffset--;
}, 1000)
</script>

Matter.js Collision Not Detecting

I'm trying to practice using matter.js to create top down levels Bomberman style.
Right now I want to get my circle, which is controlled by arrow keys to move and bump into static squares but it is just going through them. Did I set it up incorrectly? I have been coding for three months, so I might be quite slow sorry!
var Engine = Matter.Engine,
World = Matter.World,
Bodies = Matter.Bodies;
var engine = Engine.create();
var world = engine.world;
var player;
var rocks = [];
var cols = 7;
var rows = 7;
function setup() {
createCanvas(750, 750);
Engine.run(engine);
player = new Player(300, 300, 25);
var spacing = width / cols;
for (var j = 0; j < rows; j++) {
for (var i = 0; i < cols; i++) {
var r = new Rocks(i * spacing, j * spacing);
rocks.push(r);
}
}
}
function draw() {
background(51);
Engine.update(engine);
for (var i = 0; i < rocks.length; i++) {
rocks[i].show();
}
player.show();
player.move();
}
function Player(x, y, r) {
this.body = Bodies.circle(x, y, r);
this.r = r;
World.add(world, this.body);
this.show = function () {
ellipse(x, y, this.r * 2);
}
this.move = function () {
if (keyIsDown(RIGHT_ARROW))
x += 10;
if (keyIsDown(LEFT_ARROW))
x -= 10;
if (keyIsDown(UP_ARROW))
y -= 10;
if (keyIsDown(DOWN_ARROW))
y += 10;
x = constrain(x, this.r, height - this.r);
y = constrain(y, this.r, width - this.r);
}
}
function Rocks(x, y, w, h, options) {
var options = {
isStatic: true
}
this.body = Bodies.rectangle(x, y, h, w, options);
this.w = w;
this.h = h;
this.size = player.r * 2;
World.add(world, this.body);
this.show = function () {
rect(x, y, this.size, this.size);
}
}
I think the problem is that you player is not drawn in the same position that the physics engine thinks its at.
in your Player function after the initialization of x and y the rest all need to be this.body.position.x and this.body.position.y. Otherwise you're changing where the picture is drawn at but not where the player actually is.
I'm not entirely sure what all you want me to point out besides that but also I think you want to disable gravity with engine.world.gravity.y = 0 and I was trying to fix the constrain function because as I tested it it wasn't working, I wasn't able to fix it but I'd recommend just making static boundary objects for the walls and just don't draw them.
Also matter.js processes the locations of objects from their centers. When drawing the objects you either have to take that into consideration or switch the mode to ellipseMode(CENTER);, 'rectMode(CENTER);` .. etc.
I hope this helps

Categories