How to initialise and use array in game assignment


#1

Hi there, my assignment this time is an extension on my previous one (in the link above).

It consists of 2 parts (I have done the first one):

Scoring (use functions and loops)

Every time an invader gets obliterated, the player gets five points. Points are silently accumulated until the game is over. When an invader reaches the danger zone, the game stops and displays the score. The screen no longer goes red, it just displays the score on the right hand side of the screen.

Many Invaders (use arrays and strings)

As the one invader moves to the left, new invaders come in behind it. A new invader should appear as soon as the first one is 70 pixels to the left. Every 70 pixels that the invaders move, another appears to the right. When the cannon is fired, the left-most matching invader is obliterated. To obliterate more than one of the same number you have to hit ‘j’ multiple times. Every time an invader is obliterated, the space it occupied is taken up by the invader to its left. i.e. obliterating an invader causes all the invaders to the left of it to move rightwards into the empty space.

This is what I have done so far:

int invader;
int gap;
int x;
int y;
int weapon;
int boundary;
int score;
int scoreDigits;
int[] invaderHorde = {invader};

void showDangerZone(int w){
  rectMode(CORNER);
  stroke(166, 25, 46);
  fill(166, 25, 46);
  rect(0,0,w,height);
}

void showNumber(int x, int y, int n){
  stroke(214, 210, 196);
  fill(55, 58, 54);
  if (n == 0){
    a(x,y);b(x,y);c(x,y);d(x,y);e(x,y);f(x,y);
  } else if (n == 1){
    b(x,y);c(x,y);
  } else if (n == 2){
    a(x,y);b(x,y);d(x,y);e(x,y);g(x,y);
  } else if (n == 3){
    a(x,y);b(x,y);c(x,y);d(x,y);g(x,y);
  } else if (n == 4){
    b(x,y);c(x,y);f(x,y);g(x,y);
  } else if (n == 5){
    a(x,y);c(x,y);d(x,y);f(x,y);g(x,y);
  } else if (n == 6){
    a(x,y);c(x,y);d(x,y);e(x,y);f(x,y);g(x,y);
  } else if (n == 7){
    a(x,y);b(x,y);c(x,y);
  } else if (n == 8){
    a(x,y);b(x,y);c(x,y);d(x,y);e(x,y);f(x,y);g(x,y);
  } else if (n == 9) {
    a(x,y);b(x,y);c(x,y);d(x,y);f(x,y);g(x,y);
  }
}

void a(int x, int y) {
  beginShape();
  vertex(x+10, y+10);
  vertex(x+20, y+ 0);
  vertex(x+40, y+ 0);
  vertex(x+50, y+10);
  vertex(x+40, y+20);
  vertex(x+20, y+20);
  endShape(CLOSE);
}

void b(int x, int y) {
  beginShape();
  vertex(x+50, y+10);
  vertex(x+60, y+20);
  vertex(x+60, y+40);
  vertex(x+50, y+50);
  vertex(x+40, y+40);
  vertex(x+40, y+20);
  endShape(CLOSE);
}

void c(int x, int y) {
  beginShape();
  vertex(x+50, y+50);
  vertex(x+60, y+60);
  vertex(x+60, y+80);
  vertex(x+50, y+90);
  vertex(x+40, y+80);
  vertex(x+40, y+60);
  endShape(CLOSE);
}

void d(int x, int y) {
  beginShape();
  vertex(x+10, y+ 90);
  vertex(x+20, y+ 80);
  vertex(x+40, y+ 80);
  vertex(x+50, y+ 90);
  vertex(x+40, y+100);
  vertex(x+20, y+100);
  endShape(CLOSE);
}

void e(int x, int y) {
  beginShape();
  vertex(x+10, y+50);
  vertex(x+20, y+60);
  vertex(x+20, y+80);
  vertex(x+10, y+90);
  vertex(x+ 0, y+80);
  vertex(x+ 0, y+60);
  endShape(CLOSE);
}

void f(int x, int y) {
  beginShape();
  vertex(x+10, y+10);
  vertex(x+20, y+20);
  vertex(x+20, y+40);
  vertex(x+10, y+50);
  vertex(x+ 0, y+40);
  vertex(x+ 0, y+20);
  endShape(CLOSE);
}

void g(int x, int y) {
  beginShape();
  vertex(x+20, y+40);
  vertex(x+40, y+40);
  vertex(x+50, y+50);
  vertex(x+40, y+60);
  vertex(x+20, y+60);
  vertex(x+10, y+50);
  endShape(CLOSE);
}

void weaponChanging(char w) {
  if (key == w) {
    weapon = (weapon + 1) % 10;
  }
}

void weaponFiring(char w) {
  if (key == w) {
    if (weapon == invader) {
      x = 8*width/9;
      invader = (int)random(0, 10);
      score = score + 5;
    } else {
      boundary = boundary + width/7;
    }
  }
}

void showScore(int a, int b) {
  if (x <= boundary) {
    fill(214, 210, 196);
    rectMode(CORNER);
    rect(0, 0, width, height);
    noLoop();
    if (a != 0) {
      while (a != 0) {
        showNumber(b, height/4, a%10);
        a = a/10;
        b = b - 70;
      }
    } else {
      showNumber(b, height/4, 0);
    }
  }
}

void setup() {
  size(800, 200);
  invader = (int)random(0, 10);
  weapon = 0;
  x = 8*width/9;
  y = height/4;
  boundary  = width/7;
  score = 0;
  scoreDigits = width - 60;
  gap = 70;
}

void draw() {
  background(214, 210, 196);
  showDangerZone(boundary);
  showNumber(width/25, height/4, weapon);
  showNumber(x, y, invader);
  x--;
  showScore(score, scoreDigits);
}

void keyPressed() {
  weaponChanging('f'); 
  weaponFiring('j');
}


I don’t know how to properly initialise and make use of the array (in this case “invaderHorde”) , as well as the “gap” variable to satisfy the second requirement of my assignment.

Can anyone be so kind as to help me with this?


#2

Have you learned about for loops in this class yet?


#3

Yeah but I don’t know how to use it here. I know there’s a way to assign values to an array using for loop but I don’t know how to apply it to this case


#4

Have you been given a tutorial or readings on how to use an array and a for loop?


#5

Yes I read Learning Processing chapter 9 but I seriously don’t know how to apppy to this assignment. The assignment requires to have many invaders at a time on the screen but at first there is only one, and then the next one appears after the first one has moved 70 pixels to the left, then the same happens again. If the player obliterates one, then the ones to the right will move forwards to the gap. I don’t know how to initialize the array in this case as this is an array of “showNumber” function, and the length is undefined.


#6

Maybe defining a length for your array would be a good start. How many invaders would be enough? Hint: How many invaders can there ever be at once before the player has lost?

Next, you’re going to need to fill those potential spaces up. Obviously your invaders are represented by the numbers 0 to 9. So what would be a good number to use to represent a spot with no invader? You start with no invaders, right? So then you can use a loop to put a “no-invader” number in every possible spot.

Can you use a loop to draw all the invaders now? Does it matter if you always draw all of them? Do you always have to draw something for every value?

When does a new invader appear? How can you add a new invader to your array of invaders?

When does an invader disappear from the array? What happens to the value for that invader? How about the values after it in the array?

When an invader disappears, does the forward-most invader’s drawn position have to move back?

All these questions are meant to promote thinking about the problem, but feel free to try to write out your answers and post them so we can see your thought process…


#7

I know there are append and shorten functions to do this but I have trouble coding them here. Also, I don’t know what should be the class of a void function such as showNumber.


#8

I have added these commands in the declaration part and the void draw() function but nothing has changed

int noInvader;
int[] invaderHorde = new int[8];
for (int i = 0; i <= 7; i++) {
    invaderHorde[i] = noInvader;
    if (gap == width - x) {
      invaderHorde = append(invaderHorde, invader);
    }
  }

#9

Okay, follow along with me.

First, we are not going to mess about and use append or shorten at all. We are going to have one array, of a specific, fixed size.

This array will be an array of numbers, where each number will represent an invader.

Thus, the first number in the array represents the first invader.
The second number represents the second invader. And so on.

So, the first question is, how big does this array need to be? Well, because each invader is 70 pixels apart, and the game ends well before the entire screen is filled with invaders, it’s a safe bet that we will never have more than width/70 invaders on the screen at any time. To be extra safe, since this number isn’t very large, we can simply double it.

Now we take a minute to write the code for this.

int[] invaders;

void setup(){
  size(800,300);
  invaders = new int[width/35]; // width * 2 / 70 => width / 35
}

void draw(){}

Next, we need to put some numbers in that array! We know the invaders are going to be represented by numbers. The lowest number that represents an invader is 0. The highest number is 9. If we pick a number outside of the 0-9 range, we can use that number to mean “no invader”. A good choice for this number is -1.

We can use a for loop to fill the array up now.

int[] invaders;

void setup(){
  size(800,300);
  invaders = new int[width/35]; // width * 2 / 70 => width / 35
  for( int i = 0; i < invaders.length; i++){
    invaders[i] = -1; // fill up with no invaders.
  }
}

void draw(){}

Next, we need to draw the invaders. We need a second loop that draws them. For now, let’s put the first invader as x = 0.

int[] invaders;

void setup() {
  size(800, 300);
  invaders = new int[800/35];
  for ( int i = 0; i < invaders.length; i++) {
    invaders[i] = 6;
  }
}

void draw() {
  background(0);
  for ( int i = 0; i < invaders.length; i++) {
    if ( invaders[i] != -1 ) { // If this number does not represent "no invader",
      // Draw it.
      rectMode(CENTER);
      fill(255);
      rect(0 + 70 * i, height/2, 40, 40);
      fill(0);
      text( invaders[i], 0 + 70 * i, height / 2);
    } // End of if not a non-invader
  } // End of for loop.
} // End of draw()

If you run this, you should see invaders, right? Try it!

… Nope. Nothing. So what’s wrong? Nothing is wrong! All the invaders in our array have values of -1, so nothing is drawn for them.

Try changing the value they get set to in the loop!


#10

Next, what we really want is for our invaders to start off the right edge of the screen and move towards the left. You may have noticed that when I drew the invaders, they are spaced 70 pixels apart and they all have an offset in the x direction of 0.

If we change this 0 to something else - a variable that controls how far along they are, they will all move together, but kill 70 pixels spacing. Actually, since we are drawing multiple things at this position, it makes a lot more sense to use translate(), like so:

int[] invaders;
float offset;

void setup() {
  size(800, 300);
  invaders = new int[800/35];
  for ( int i = 0; i < invaders.length; i++) {
    invaders[i] = 6;
  }
}

void draw() {
  background(0);
  offset = mouseX;
  // Draw all invaders.
  for ( int i = 0; i < invaders.length; i++) {
    if ( invaders[i] != -1 ) {
      rectMode(CENTER);
      pushMatrix();
      translate(width - offset + i * 70, height/2);
      fill(255);
      rect(0, 0, 40, 40);
      fill(0);
      text(invaders[i], 0, 0);
      popMatrix();
    }
  }
}

Run this and verify for yourself that changing the mouseX amount changes the offset variable which controls where the invaders are drawn. Now we change the offset variable a bit, and it looks like our invaders are moving in from the right:

int[] invaders;
float offset;

void setup() {
  size(800, 300);
  invaders = new int[800/35];
  for ( int i = 0; i < invaders.length; i++) {
    invaders[i] = 6;
  }
  offset = -70;
}

void draw() {
  background(0);
  offset++;
  // Draw all invaders.
  for ( int i = 0; i < invaders.length; i++) {
    if ( invaders[i] != -1 ) {
      rectMode(CENTER);
      pushMatrix();
      translate(width - offset + i * 70, height/2);
      fill(255);
      rect(0, 0, 40, 40);
      fill(0);
      text(invaders[i], 0, 0);
      popMatrix();
    }
  }
}

#11

Next, we need a couple of functions to deal with the two actions we can do to our array of invaders. First, we need a function to add a new invader. Then we need a function to remove the first invader that matches a given number.

void add_invader(int new_number){

}

void remove_invader(int which_number){

}

How should these functions work? Well, for adding a new invader, if we can add it at position 0, we’re done.

void add_invader(int new_number){
  if( invaders[0] == -1 ){ // If there is no invader here,
    // We can add one!
    invaders[0] = new_number;
  }
}

But what if the first space in the array is occupied? Well, we could try the next space…

void add_invader(int new_number){
  if( invaders[0] == -1 ){ // If there is no invader here,
    // We can add one!
    invaders[0] = new_number;
  } else {

  if( invaders[1] == -1 ){ // If there is no invader here,
    // We can add one!
    invaders[1] = new_number;
  }

  }
}

But what if both of those spaces are full?

void add_invader(int new_number){
  if( invaders[0] == -1 ){ // If there is no invader here,
    // We can add one!
    invaders[0] = new_number;
  } else {

  if( invaders[1] == -1 ){ // If there is no invader here,
    // We can add one!
    invaders[1] = new_number;
  } else {

  if( invaders[2] == -1 ){ // If there is no invader here,
    // We can add one!
    invaders[2] = new_number;
  }

  }
  }
}

Oh no. This is a lot of typing. My fingers hurt. Could we do this with a loop?

void add_invader(int new_number){
  for( int i = 0; i < invaders.length; i++){
    if( invaders[i] == -1 ){
      invaders[i] = new_number;
      return;
    }
  }
}

Removing an invader looks the same:

boolean remove_invader(int which_number){
  for( int i = 0; i < invaders.length; i++){
    if( invaders[i] == which_number ){
      invaders[i] = -1;
      shift_invader(i);
      return(true);
    }
  }
  return(false);
}

void shift_invader(int i){}

Except we are going to report true or false if we found an invader to remove. Also, what the heck is that shift_invader() function?

void shift_invader(int i){
 if( i+1 < invaders.length){
   invaders[i] = invaders[i+1];
   shift_invader(i+1);
  } else {
   invaders[i] = -1;
  }
}

Convince yourself that this moves the remaining invaders in the array towards the front.


#12

Let’s put this all together now, randomize the incoming invaders numbers, and add a keyPressed() method to test killing an invader, and check if offset gets too high:

int[] invaders;
float offset;

void setup() {
  size(800, 300);
  invaders = new int[800/35];
  for ( int i = 0; i < invaders.length; i++) {
    invaders[i] = int( random(10));
  }
  offset = -70;
}

void draw() {
  background(0);
  if( offset > width ){
    background(200,0,0);
  }
  offset++;
  // Draw all invaders.
  for ( int i = 0; i < invaders.length; i++) {
    if ( invaders[i] != -1 ) {
      rectMode(CENTER);
      pushMatrix();
      translate(width - offset + i * 70, height/2);
      fill(255);
      rect(0, 0, 40, 40);
      fill(0);
      text(invaders[i], 0, 0);
      popMatrix();
    }
  }
}

void add_invader(int new_number){
  for( int i = 0; i < invaders.length; i++){
    if( invaders[i] == -1 ){
      invaders[i] = new_number;
      return;
    }
  }
}

boolean remove_invader(int which_number){
  for( int i = 0; i < invaders.length; i++){
    if( invaders[i] == which_number ){
      invaders[i] = -1;
      shift_invader(i);
      return(true);
    }
  }
  return(false);
}

void shift_invader(int i){
 if( i+1 < invaders.length){
   invaders[i] = invaders[i+1];
   shift_invader(i+1);
  } else {
   invaders[i] = -1;
  }
}

void keyPressed(){    
  if( key >= '0' && key <= '9' ){
    if( remove_invader( key - int('0') ) ){
      offset-=70;
      add_invader( int(random(10)) );
    }
  }
}

There. That’s a solid example for you to study. It’s up to you to make it work for your invaders, and to replace my keyPressed() with you number selecting code.

Also notice that killing an invader now causes a new one to be added, and makes the offset jump back a bit.


#13

Almost there, guys.
I only have some 1 problem left with void keyPressed() function:

void keyPressed() {
  if (key == 'f') {
    weapon = (weapon + 1) % 10;
  }
  if (key == 'j') {
    if (weapon == invaders[0]){
      remove_invader (weapon);
      add_invader(int(random(10)));
      score = score + 5;
    } else {
      boundary = boundary + 115;
    }
  }
}

The problem is that I don’t know how to obliterate any matching invaders to the right but only the left-most one.


#14

What is this line saying?


#15

I tried to change it to

for (int i = 0; i < invaders.length; i++) {
  if (weapon == invaders[i]) {
...

but it doesn’t work

The same for

int i = int(random(width/35));
if (weapon == invaders[i]) {
...