Displaying from an array

Hello guys, so I’m trying to make this counter sort of thing where a function takes in an input and then it shows it back in reverse like a countdown. But I’m unable to get it working properly as the numbers tend to just get drawn on top of one another.

I’ve tried setting the background but it isn’t working. The approach I’ve taken is that my function populates the array and then sets the text. I’m not sure if its a problem with the nesting loop or something else

var range = [];

function setup() {
  createCanvas(400, 400);
  textAlign(CENTER, CENTER);
  textSize(24);
  sequence(10);
  
}

function draw() {

}

function sequence(number) {

  for (i = number; i >= 0; i--) {  
    for(j = 0; j < range.length; j++) {
     text(range[j], width / 2, height / 2);
    }
    range.push(i);
  }

}
1 Like

Your issue is that you are looping through a set amount of times and calling text(...) each iteration causing each text() call to draw on top of each other.

You can use the frameCount and modulo to get a close representation of a timer, though this is not an accurate account of time … but it may help to get you started. Essentially this is assuming that every 60 frames equals 1 second, in theory p5 runs 60 frames per second, but that is not always true.

const timer = {
  start: 7,
  current: 7,
  canReset: false
};

function setup() {
  createCanvas(400, 400);
  textAlign(CENTER);
}

function draw() {
  background(220);
  textSize(100);
  text(timer.current, width / 2, height / 2);

  if (frameCount % 60 == 0 && timer.current > 0) timer.current--;


  if (timer.current == 0) {
    textSize(20);
    text("click to restart", width / 2, height * 0.7);
    timer.canReset = true;
  }
}

function mouseClicked() {
  if (timer.canReset) timer.current = timer.start;
  timer.canReset = false;
}

I would suggest eventually looking into utilizing millis() to get a more accurate account of time.

3 Likes

Hi, thank you for the response but I really wanna see it done using arrays if that’s possible… And I’m sorry if I didn’t mention this in the question but I’m not really looking at it as a timer but rather as a function that takes in a value, counts it down to 0 and that’s all!

I have managed to work around and get it to just go through the array and display the last entry of the array, so now I’ve to find a way to make the loop not run instantaneously?

var range = [];
var indexCounter;

function setup() {
  createCanvas(400, 400);
  textAlign(CENTER, CENTER);
  textSize(24);
  sequence(10);
}

function draw() {
 
}

function sequence(number) {
  for (i = number; i >= 0; i--) {  
       range.push(i);
  }
  
  for (j = range.length; j >= 0; j--) {
        indexCounter = range[j];
    }
  text(range[indexCounter], width / 2, height / 2);
}

Not fully sure what you are trying to accomplish with the array, but you can create a function delay using setTimeout()

https://www.w3schools.com/jsref/met_win_settimeout.asp

function setup() {
  createCanvas(400, 400);
  textAlign(CENTER);
  textSize(42);
  fill(33);

  timer(5);
}

const timer = (startTime) => {
  startTime++;
  for (let i = 0; i < startTime; i++) {
    setTimeout(i => {
      background(220), text(--startTime, width * 0.5, height * 0.5)
    }, 1000 * i);
  }
}
3 Likes

Oh wow, thank you and here I was just about to hit the bed all defeated…

So, I was just sticking to using arrays cause it’s like this learning thing where I must absolutely work within the constraints given, or it’s just plain stupidity sorry!

Although I’ve got the result, I’ve also managed to confuse myself a bit and I’m not entirely sure if it works exactly in the way I wanted, but along the way, I’ve also learned about intervals.

I’m sure it’d all clear up once I get more experience with all that intervals stuff I guess. Anyway, here’s the abomination I came up with :grin:

var range = [];

function setup() {
  createCanvas(400, 400);
  textAlign(CENTER, CENTER);
  textSize(24);
  populateArray(10);
  sequence();
}

function populateArray(limit) {
  for (i = limit; i > 0; i--) {
    range.push(i);
  }
}

var sequence = function() {
  for (var j = 20; j >= 0; j--) { // j = 20 is arbitrary, just wanted to knw if the loop was running in relation to the array and not something else!
    setTimeout(j => {
      background(204),
        text(range.length--, 200, 200)
    }, 1000 * j);
  }
}
1 Like

j is being used to create the delay in each iteration, otherwise it will happen instantaneously.

also your sequence() expression will return a RangeError

1 Like

Here’s an alternative using a function* Generator instead of an array: :wink:

It also sets frameRate() to 1 FPS in place of setTimeout():

3 Likes

Python Mode version using 3 types of generator: :snake:

  1. countdownYield() -> Function generator via yield keyword
  2. countdownComprehension() -> Function which returns a comprehension generator made by using xrange().
  3. countdownIterRange() -> Function which returns an iterator generator made by passing xrange() to iter().