Creating and removing one object from an array

This is probably a really silly question, but I can’t seem to find an answer. If you want to create one object and then delete it, what is the typical way to do this? Since I only have one object I don’t want to push it to an array, and I have to check if the object is alive or functioning. I’m using this check for “undefined” below, but it seems very verbose.

		if(picker == 99) {

			let colorPicker=int(random(0,this.colorArray.length));

			this.blackhole = new BlackHole(this.position.x, this.position.y, this.colorArray[colorPicker]) ;

		}

  if(this.blackhole!=undefined) {
    if(this.blackhole.alive) {
  			this.blackhole.render(isBeat); //render it while alive
  		} else {
  			this.blackhole=undefined; // remove it
  		}
  }

If you make sure you always create a BlackHole inside that class’ constructor() you won’t need to check for undefined.

No need to assign undefined to property blackhole, b/c checking for the BlackHole::alive property is pretty enough.

You can just replace the whole thing above with this very simple check-for-action statement:
this.blackhole.alive && this.blackhole.render(isBeat);

P.S.: What does that isBeat come from? Is it a method parameter?

It can’t work like that because if the blackhole is not birthed yet (it is randomly generated) it will try to check to see if it is alive and then throw an error. That’s why I have:

 if (this.blackhole != undefined) {

The way I had it before it was pushing the blackhole object to an array. It just seems kind of silly to push one object to an array, run a loop to check it and then remove it. On top that, you have the chance of two or more blackholes being “alive” in the same array, which I guess is ok, but other way just replaces the first one entirely. It’s sort of a weird problem to have, that’s why I was asking. The “isBeat” is a true or false value from the beatDetection thing I was working on (see other post) that gets passed into the constructor. I’ll probably take that out and just have the blackhole check the value in the beatDetect constructor instead, because it’s really annoying passing a value through a chain of functions, and probably not the best idea I would think.

Just have a dummy BlackHole w/ its property alive set to false: :bulb:

  constructor() {
    (this.blackhole = new BlackHole).alive = false;
  }

I’m starting to believe you dunno much about formal class creation in JS: :thinking:

I am not an expert. But I am trying to learn, that’s why I’m asking questions. The dummy blackhole method will work, thanks for that. I have some classes in my program with inheritance. Not sure what you are trying to say, but it makes me feel like you are making fun of me or taking a dig. I’m in school for computer science and we are doing a bunch of work in p5, and I think I’ve made some decent stuff. Obviously I have a lot to learn.

I’m here for more than a decade and I don’t make fun of folks I’m trying to help.

  • I’m not talking about inheritance but just classes.
  • I don’t even know what’s the name of the class the property blackhole belongs to.
  • What’s the name of the method your posted code belongs to?
  • Or do you just use the old style of having a function acting like a constructor?
2 Likes

Blackhole is a constructor. When the random number hits 99 it makes an instance of the blackhole object. The class is declared like this:

function BlackHole(xpos, ypos, colorVal) {
//vars here

this.render = function(isBeat) {
//drawing stuff in here
}
}

Not sure if this is what you are calling the old style, it probably is. This is what they showed us in school. They never showed us another way of doing it. We have not got to a formal understanding of proto, super, etc. I am unsure if this is a flaw in the curriculum, but it is an intro to programming course ii, and we were asked to make a music visualizer. One of my visualizers is a marching squares topography that reacts to music and also rotoscopes a cartoon in real time. It also edits the video in real time depending on the acceleration of the waveform. The black holes are literally some object that show up during video cuts that grow / expand, like a graphical element.

Stuff is extended like this in my program:

class CellVideo extends Cell {
  constructor(colID, rowID, resY, resX, cellSize) {
    super(colID, rowID, resY, resX, cellSize)
  }

  render(cut) {
	//stuff
	}

}```

Yup, that’s the old deprecated style. :lizard:

This is how we’d write the code by today’s standards: :nerd_face:

class BlackHole {
  constructor(xpos, ypos, colorVal) {
    this.xpos = xpos, this.ypos = ypos, this.colorVal = colorVal;
    (this.blackhole = new BlackHole).alive = false;
  }

  render(isBeat) {
    this.blackhole.alive && this.blackhole.render(isBeat);
  }
}

The 1 using class is the modern style. :spiral_calendar:

Seems like they end up using the current style in order to avoid the pain of teaching students how to extend a class via the old approach. :stuck_out_tongue:

1 Like

Thanks, I have to review what the difference is. Maybe you can briefly explain the advantage. I have most of my variables properly encapsulated, so maybe it’s an easy change. Another question I had for the professor, which he really didn’t answer sufficiently is why this does not work:

class CellStar extends Cell {

  constructor(colID, rowID, resY, resX, cellSize) {
    super(colID, rowID, resY, resX, cellSize)

    //black hole colors
  	this.colorArray = [ color(245,188,206), //pink
  								      color(26,46,171), //blue
  								      color(135,206,250), //cornflower blue
  								      color(51,17,82), //purple
  							        color(214,133,176) ]; //magenta

    this.blackhole;
    var x = "testing";

  }

  render() {
console.log(x);
}
}

x is inaccessible. it is only accessible if it is declared as “this.x” in the extended class. maybe this ties in with the old method of declaration.

I also tried your blackhole.isAlive trick but it won’t work for me :frowning: . The reason being is that the blackholes are “birthed” out of a rather large grid, so it’s a lot of processing to check a dummy object like that. I think it might be more efficient to birth them and then check if it exists at all, because the birth rate is low vs. having a placeholder birthed at every cell in the grid. They also have to stay in this area of program because they are birthed behind some objects in other grid, which gives this really cool overlaid effect with the marching squares. If it was just birthing objects at a higher level like the main constructor, this is much simpler. What I was originally hoping is that I could just use something like .delete() or .remove() but I don’t think this exists for an object. I think in processing you can do something like that with arraylists, but not p5 from what I researched.

I’ll share my project with you when it’s done, I think you’ll like it. Thanks for your help, really appreciate it.

When we declare a variable, that variable is only accessible within its constructor/method/function.

Or within nested functions/classes. In such case the variable becomes a closure to them.

The x in this case is neither declared nor even a variable, but it’s created as an object’s property.

The difference between a variable & a property is subtle, but it’s important to be aware of.

P.S.: Function parameters are also local variables. The difference is that the former are initialized by passed arguments, while the latter are initialized inside the function’s body after.

That’s a pretty valid approach. But then you should drop its property alive b/c it’s redundant.

No reason to check for both undefined & alive. Pick 1 or the other.

If you choose undefined or null, assign that value to property blackhole in place of alive = false.

A JS object indeed doesn’t have such methods; but JS got a delete operator instead:

But it’s rarely used. Just assigning undefined or null to a property is the popular procedure.

I think I may have got into a bad practice of declaring a few things in the constructor as variables instead of properties. Like take a counter for example - I want “counter” to start at zero when the object is made, but then available to many functions in the constructor which is doing things with it. If I set var counter=0 or let counter=0 in a looping function it will be zero every frame. If I declare it in the constructor it is 0 and then I can start incrementing it…

I have to use both because the “blackhole” is doing something (a circle in there has to reach a certain size that is oscillating with a sine function). If it doesn’t get set back to undefined and die off it will keep doing that action. And if I don’t check for undefined first, then it checks an object that doesn’t exist, which throws an error. The other method with the dummy works fine, but then I have a lot of these objects in a grid which is how this whole birth / unbirth question came into being. Originally I was pushing them into an array, but I don’t really need more than one object for any given cell. It’s a problem of NOT having one master control birthing stuff, I have many masters deciding whether or not to make something, which is why I don’t want to waste performance. And I have to keep it like that because I’m overlaying / underlaying these things in a grid where squares may or may not overlap depending on what the marching squares are doing.

I’m intrigued then!

Does a BlackHole object do other things when its property alive is currently set to false? [Yes or No]

In your code logic the same BlackHole object once set its property alive to false would it ever revert to true at a later point? [Yes or No]

If both answers are “No” then the property BlackHole::alive would be equivalent to property blackhole set to non-undefined or non-null.

In other words, if there’s a BlackHole object currently assigned to property blackhole it would already mean it’s “alive”.

Thus no need for an extra property named alive in such case.

But then how would the oversëer class, which owns the blackhole property, be notified that it’s no longer “alive”?

So now I see why you’d need to have the BlackHole::alive property regardless.

My advice then is to check for the BlackHole::alive property in one place within its manager class for each cycle.

Something like the method below which would be invoked before the other methods:

  disposeWhenDead() {
    if (this.blackhole && !this.blackhole.alive)  this.blackhole = null;
  }

From then on you’d only need to check for this.blackhole rather than both this.blackhole & this.blackhole.alive.

As an example, you could replace the double check below:

  if (this.blackhole && this.blackhole.alive)  this.blackhole.render(isBeat);

With something much shorter:

  this.blackhole && this.blackhole.render(isBeat);

B/c now checking for just this.blackhole is already enough to imply it’s “alive”.

However I’d still prefer the idea of a dummy placeholder for a BlackHole object instead until it’s replaced by the real 1, which then guarantees that this.blackhole is never undefined nor null, and relying to check for the BlackHole::alive property only.

P.S.: If we use the optional chaining operator ?. we can shorten the checks even more:

  disposeWhenDead() {
    // if (this.blackhole && !this.blackhole.alive)  this.blackhole = null;
    if (!this.blackhole?.alive)  this.blackhole = null;
  }
    // this.blackhole && this.blackhole.render(isBeat);
    this.blackhole?.render(isBeat);

This is super helpful. The answer to both questions is “no.” This is what I came up with (and thank you for showing me that if syntax, I did not know you could do that and was always using the ternary ifs with : false :

  render() {

		noStroke();
		//flicker the dots like stars
		fill(255,255,0,random(198,255));
		ellipse(this.position.x+this.w2,this.position.y+this.h2, 1, 1);

    let picker = int(random(0,35000));

    //state == 1 means cell is filled in, we only want to birth on filled in cells
    //if the state is 0 then 0 * picker = 0
    if (vis.selectedVisual.birthAllowed && this.state * picker == 99) {
      let colorPicker=int(random(0,this.blackHoleColors.length));
      // console.log(this.colID);
      if(!this.blackhole) this.blackhole = new BlackHole(this.position.x, this.position.y, this.blackHoleColors[colorPicker]);
    }

    //does it exist?
    if(this.blackhole) this.blackhole.render(); //render it while alive

	 }

} //END CELLSTAR CLASS EXTENSION

in blackhole it just re-inits the size on death:

//black holes
function BlackHole(xpos, ypos, colorVal) {


	this.position=createVector(xpos,ypos);

	let size = 0;
	let maxSize = random(150,600);
	let speed = random(0.5, 1.25);

	let angle=0;
	let angle2=0;
	let angSpeed=random(.01,.05);	//outer oscillation speed
	let angSpeed2=random(.01,.025); //inner oscillation speed


	//re-init size on death
	this.init = function() {

		size = 0;
		maxSize = random(150,600);
	  speed = random(0.5, 1.25);

		angle=0;
	  angle2=0;
		angSpeed=random(.01,.05);	//outer oscillation speed
		angSpeed2=random(.01,.025); //inner oscillation speed

	}


	this.render = function() {

		size+=speed;
		angle+=angSpeed; //outer oscillation
		angle2+=angSpeed2; // inner oscillation
		let offset = size/35;

		noStroke();

		fill(red(colorVal),green(colorVal),blue(colorVal));

		//colored portion
		ellipse(this.position.x,this.position.y,sin(angle)*size,sin(angle)*size);

		//ofset moon
		fill(5);
		ellipse(this.position.x-offset,this.position.y+offset,sin(angle2)*size,sin(angle2)*size);

		//middle dot
		fill(100,149,237);
		ellipse(this.position.x,this.position.y,4,4);

		//clock line
		stroke(15);
		line(this.position.x,this.position.y,this.position.x+(size/2*sin(angle*3)),this.position.y+(size/2*cos(angle*3)) );

		if(size >= maxSize) this.init(); //it has died, re-init the size

	}

} //END BLACKHOLE

I have to upload a video to show you the program since you’ve been so gracious with your time and help. In the blackhole class is an example where the properties have to be re-initialized. Perhaps you have advice about this? I am suspecting my idea is not very smart as it replicates the properties in the object, and related to my other question about declaring variables in the constructor which are more like variables than properties, but see what you think.

You may delegate a separate method to initialize all the class’ properties to their default state.

Seems like you already have 1 called init().

But in order to avoid the repeatable variable assignments in 2 places you’re gonna need to turn them into properties instead.

By default variables & parameters cease to exist once their function ends.

Unless that function has other nested functions or classes inside it.

Any variable or parameter accessed inside nested functions or classes become a closure:

In general we should avoid making nested functions b/c that creates a hidden static state and also wastes some memory to store that state.

Instead move those nested functions into their constructor’s prototype object:

function BlackHole(xpos, ypos, colorVal) {
  this.position = createVector(xpos, ypos);
  this.colorVal = color(colorVal);

  this.init();
}

BlackHole.prototype.init = function () {
  this.size = this.angle = this.angle2 = 0;
  this.maxSize = random(150, 600);
  this.speed = random(.5, 1.25);
  this.angSpeed = random(.01, .05);   // outer oscillation speed
  this.angSpeed2 = random(.01, .025); // inner oscillation speed
}

Notice the method init() is now defined a single time outside BlackHole’s constructor body; thus it’s not a nested function anymore.

Also all closure variables were converted into BlackHole’s properties.

And there’s no need to repeat code inside both BlackHole’s constructor & its init() method.

Method init() is now invoked from within BlackHole’s constructor instead.

However the best strategy is to completely abandon this ancient way of creating classes in JS and just use actual class syntax.

This is how I’ve remade your BlackHole constructor function as a JS class:

class BlackHole {
  constructor(xpos, ypos, colorVal) {
    this.position = createVector(xpos, ypos);
    this.colorVal = color(colorVal);
    this.colorVal2 = color(100, 149, 237);

    this.init();
  }

  init() {
    this.size = this.angle = this.angle2 = 0;
    this.maxSize = random(150, 600);
    this.speed = random(.5, 1.25);
    this.angSpeed = random(.01, .05);   // outer oscillation speed
    this.angSpeed2 = random(.01, .025); // inner oscillation speed

    return this;
  }

  update() {
    this.size += this.speed;
    this.angle += this.angSpeed;
    this.angle2 += this.angSpeed2;

    // If it has died re-init the size:
    this.size > this.maxSize && this.init();

    return this;
  }

  render() {
    const { size, angle, angle2, colorVal, colorVal2, position } = this,
          { x, y } = position,
          offset = size / 35,
          half = size * .5,
          angle3 = angle * 3;

    // Colored portion:
    fill(colorVal).noStroke().circle(x, y, sin(angle) * size);

    // Offset moon:
    fill(5).circle(x - offset, y + offset, sin(angle2) * size);

    // Middle dot:
    fill(colorVal2).circle(x, y, 4);

    // Clock line:
    stroke(15).line(x, y, x + half * sin(angle3), y + half * cos(angle3));

    return this;
  }
}