Arrow Keys and Death counter

Guys i need some help with player movement and death counter, here’s my code

Main code:

 Player Player;
 enemy enemy;
 int score;
 int deaths;



void setup() {
  size ( 640, 480);
  noStroke();
  enemy = new enemy();
  Player = new Player();
}


void draw() {
  background(126);
  enemy.display();
  Player.display();
  Player.keyPressed();
  fill (0);
  text ("Score: " + score, 10, 460);
  text ("Deaths: " + deaths, 570, 460);
  if (Player.checkHit()){
  Player.die();
  }

}


  

Classes code:

  class enemy {
  color c;
  float xposr;
  float yposr;
  float xspeed;

    enemy(){
    c = color (0);
    xposr = width/2;
    yposr = height/2;
    xspeed = 0;
  }
  
  void display(){
   rectMode(CENTER);
   fill(c);
   rect(xposr, yposr, 33, 33);
  }
}








class Player {

  color c;
  float xposb;
  float yposb;
  float xspeed;

    Player(){
    c = color (255);
    xposb = 33/2;
    yposb = height/2;
    xspeed = 0;
  }
  
  void display(){
   ellipseMode(CENTER);
   fill(c);
   ellipse(xposb, yposb, 33, 33);
  }

boolean checkHit() {
   return (xposb >= enemy.xposr-33 &&  
    yposb >= enemy.yposr-33 &&
    xposb <= enemy.xposr+33 &&
    yposb <= enemy.yposr+33);
  }

void keyPressed()
{
  if (key == CODED)
  {
    if (keyCode == LEFT)
    {
       
      xposb= xposb -2;
      yposb= yposb +0;
      
    }

    if (keyCode == RIGHT)
    {
      xposb=xposb+2;
      yposb=yposb+0;
    }
    
 
    
    if (keyCode == UP)
    {
      yposb=yposb-2;
      xposb=xposb+0;
    }
   
    if (keyCode == DOWN)
    { 
      yposb=yposb+2;
      xposb=xposb+0;
      
    }

  }
}
void die(){
  deaths++;
  score = 0;
}

}

So, i was able to change the player movement to arrow keys instead of mousey and mousex values, but how do i make the ball stop everytime i release the keys or hit the scene limits (640x480).

And also, i tried with the

boolean checkHit() {
   return (xposb >= enemy.xposr-33 &&  
    yposb >= enemy.yposr-33 &&
    xposb <= enemy.xposr+33 &&
    yposb <= enemy.yposr+33);

}


  if (Player.checkHit()){
  Player.die();
  }

to make it count only 1 death instead of 17 everytime i passed through the enemy, but it did not worked… any thoughts?

2 Likes

i made some changes in the classes code, but got the same results.

instead of making a boolean function, i made a void one with boolean variables… don’t really knew how this was gonna help, but i had to try it hahah

void checkHit(){
  if (xposb >= enemy.xposr-33 &&  
    yposb >= enemy.yposr-33 &&
    xposb <= enemy.xposr+33 &&
    yposb <= enemy.yposr+33){
    
      checkHit = true;  
      if (checkHit == true){
      deaths++;
      }
    }
  }


and in the main coide i just called the function with Player.checkHit() in draw()

but still, the death triggers 33 times instead of 1 hahaha

1 Like

Hello @Prantzz
for arrow key problem, you need to check if the key is being pressed by using built-in global variable keyPressed in the player class

if(keyPressed){
    if (key == CODED){
         //evaluate key
    } 
}

and then to limit player movement to not go outside canvas, use constrain()
like x = constrain(x + someIncreement, 0, width)

then for the third problem,

you need to check if previous state has changed. if changed, and hit then call “death()
what i mean by state is if the player hit the enemy or not

3 Likes

and how could i check if the state has changed? cause for hitchk i’m using the coordinates of the rect enemy, and if those are equal to the coordinates of the player, i make a death++;… isn’t that checking if a state has changed?

btw, thanks for the other 2 problems, solved without a problem :slight_smile:
but i got a new one regarding the arrow keys - when i’m moving the player by holding the arrows down, and change from one arrow to another (change direction), it changes, but with a little bit of input lag :confused: is this a processing limitation, or am i doing something wrong? haha i’ll leave the code here anyways…

void keyPressed()
{
  if (keyPressed){
  if (key == CODED)
  {
    if (keyCode == LEFT)
    {
       
      xposb= xposb -1;
      yposb= yposb +0;
      
    }

    if (keyCode == RIGHT)
    {
      xposb=xposb+1;
      yposb=yposb+0;
    }
 
    
    if (keyCode == UP)
    {
      yposb=yposb-1;
      xposb=xposb+0;
    }
  

   
   
    if (keyCode == DOWN)
    { 
      yposb=yposb+1;
      xposb=xposb+0;
      
    }
  }
  }

all you do previously is right. you only need to assign hitState to additional two variable: one for current state and another for previous state.

boolean checkHit() {
    prevState = state;
    state = (xposb >= enemy.xposr-33 &&  
      yposb >= enemy.yposr-33 &&
      xposb <= enemy.xposr+33 &&
      yposb <= enemy.yposr+33);
    return state != prevState && state; //checking if state has changed and current state is true
  }

for me it just works fine with the arrow keys :face_with_monocle:
edit: or is it?

2 Likes

Hey There !

Changing the keyCodes if statements try changing to else if.

2 Likes

It’s me again !

I decided to help you out with your controls and counter and do a bit of optimizing to get it working. Your problem currently which your controls is you are checking if all the keys are being pressed. Which may cause the input lag. Also setting key control like that is quite hacky , I like to use a switch statement or something of sorts. For your death counter , when you are on an enemy you only wanna count the collision once. After that you want to put your player into dead state. And once the player is out of the dead state and touches the enemy again then only should you count again. Also when having collisions between Player and Enemy it is better to pass the variables into the method rather than access the class one’s. Here’s the coding. Anything you can’t understand let me know !

Player Player;
enemy enemy;
int score;
int deaths;



void setup() {
  size ( 640, 480);
  noStroke();
  enemy = new enemy();
  Player = new Player();
}


void draw() {
  background(126);
  enemy.display();
  Player.display();
  fill (0);
  text ("Score: " + score, 10, 460);
  text ("Deaths: " + deaths, 570, 460);
  if (Player.checkHit(enemy.getPos().x, enemy.getPos().y) && !Player.getDead()) {
    Player.die();
    Player.setDead(true);
  } else if(!Player.checkHit(enemy.getPos().x,enemy.getPos().y)) {
    Player.setDead(false);
  }
}
void keyPressed() {
  Player.isMove(keyCode, true);
}
void keyReleased() {
  Player.isMove(keyCode, false);
}
class enemy {
  color c;
  float xposr;
  float yposr;
  float xspeed;

  enemy() {
    c = color (0);
    xposr = width/2;
    yposr = height/2;
    xspeed = 0;
  }

  void display() {
    rectMode(CENTER);
    fill(c);
    rect(xposr, yposr, 33, 33);
  }
  PVector getPos() {
    return new PVector(xposr, yposr);
  }
}
class Player {

  color c;
  float xposb;
  float yposb;
  float xspeed;
  boolean dead;
  boolean isUp, isDown, isLeft, isRight;
  Player() {
    c = color (255);
    xposb = 33/2;
    yposb = height/2;
    xspeed = 1.5;
    dead = false;
  }

  void display() {
    ellipseMode(CENTER);
    fill(c);
    ellipse(xposb, yposb, 33, 33);
    movePlayer();
  }
  void movePlayer() {
    if (isUp) yposb-=xspeed;
    if (isDown) yposb+=xspeed;
    if (isLeft)xposb-=xspeed;
    if (isRight)xposb+=xspeed;
  }
  boolean checkHit(float enemX, float enemY) {
    return (xposb >= enemX - 33 &&  
      yposb >= enemY-33 &&
      xposb <= enemX+33 &&
      yposb <= enemY+33);
  }
  void die() {
    deaths++;
    score = 0;
  }
  boolean isMove(int k, boolean pressed) {
    switch(k) {
    case UP: 
      return isUp = pressed;
    case DOWN: 
      return isDown = pressed;
    case LEFT: 
      return isLeft = pressed;
    case RIGHT: 
      return isRight = pressed;
    default: 
      return false;
    }
  }
  boolean getDead() {
    return dead;
  }
  void setDead(boolean isDead) {
    dead = isDead;
  }
}

Another interesting thing to add could be a short duration of grace after being hit. But that’s up to you !

3 Likes

Genius coding! thanks for the help :smiley:

but i didn’t quite get this part of the code. i mean, i never used “PVector”, but i asume that enemy.getPos().x and enemy.getPos().y are getting the xposr and yposr from the PVector defined in the enemy class… but how can you use they as parameters of a boolean function as Player.checkHit()? what is this function considering, cause this values (xposr and yposr) were never mentioned into the checkHit()… also i need (obviously) some explanation on how does the return, case, switch works and why there’s “!” in front of some class functions, like !Player.getDead()

2 Likes

Hey !

The method:

 PVector getPos() {
    return new PVector(xposr, yposr);
  }

Takes the xposr and yposr variables and mashes them into a PVector for it to be returned. I did this to look more neat as then we can just extract the x and y depending on which one we need or we could even have another method accept a PVector as a parameter and we can just pass in the method as getPos return a full PVector. Note: When we use getPos().x and getPos.y() we extract the x and y variable from the PVector which are part of the PVector object and these are floats which we can use.

To find out more about PVectors check out here.

We can use any variable types as parameters for any method this isn’t dependent on what the method type is. We can use any variable type as those could be crucial essentials to be part of the method to make it work. Where in our case we use in checkHit the position x and y of the enemy by passing it in to checkHit to be able and calculate if our enemy has collided with the enemy.

For example here floats are passed into a void which doesn’t return anything. But because it is void type it doesn’t stop it from using different types of varaibles to be parameters.

The switch is a more neat way of saying:

if()
else if().....

It is the same exact thing but just allows it to be written more compactly then a proper if else if clause. In the switch statement which is present within your code. The keyPressed calls that function aka when a key is pressed isMove is executed. The key which has been pressed ( It’s ascii value aka number ) is checked within the switch statement if that the programmed key being pressed if it is change the according boolean values to the corresponding state of the variable pressed and return. So in this case the UP , DOWN , LEFT , RIGHT are the keys programmed whenever those keys are pressed it flips their variables to be true ( isUp , isDown etc.) This variable remains true until the key is released.

In logic there is 3 important operators the NOT , AND , OR. We can use these within programming languages ( As these are very important ) and give more expansive use of certain methods within our program. So in this case we use the getHIt method . This method returns true if and only if we are on the enemy And false if we aren’t so let’s say we wanted the method to return true when it is actually false in this case so we can know we are not on the enemy so we can get out of the dead state. Well in this case the NOT operator ‘!’ will flip the meaning of the boolean where it was , FALSE now it will be TRUE and where it was TRUE it would flip it to be FALSE, this what is called a negation.

An example of the operators.
An extra read on logic operators.

I think that answers all your questions ? If I missed something please let me know !

3 Likes

Oh i’ll have to take some time to read it and let it sink in hahaha :slight_smile:

But thank you in advance for your amazing help and support. You’re amazing :smiley:

1 Like

Hey there, InferNova - it’s me again!

i need some help once again.

well, i kind of understood what you’ve coded - but there’s this one part that’s not working quite well for me.

i’ve tried to re-do all of the coding for another enemy class - and well… i tried somethings and all of them got me back to the touch per frame counter xD

i’ll show you how the new enemy class is set:

class enemy2 {
  color c;
  float xposr;
  float yposr;
  float xspeed;

  enemy2() {
    c = color (0);
    xposr = 540;
    yposr = height/2;
    xspeed = 0;
  }

  void display() {
    rectMode(CENTER);
    fill(c);
    rect(xposr, yposr, 33, 33);
  }
  PVector getPos() {
    return new PVector(xposr, yposr);
  }
void movement(){
float i;
for (i=yposr; i<=440; i++){
yposr++;
}

}

}

Please, ignore the movement(), i was tryng to make it move for itself from a point to another, but it get instantly to the yposr+440… well maybe that’s something else i could try to learn here.

and here’s what i’ve tried to do, to make the 2nd enemy “hittable”.

if (Player.checkHit(enemy.getPos().x, enemy.getPos().y) || Player.checkHit(enemy2.getPos().x, enemy2.getPos().y) &&!Player.getDead()) {
    Player.die();
    Player.setDead(true);
  } else if(!Player.checkHit(enemy.getPos().x,enemy.getPos().y) || !Player.checkHit(enemy2.getPos().x,enemy2.getPos().y)) {
    Player.setDead(false);
  }

this one make both of the enemy returns the number of frames that the player stays touching the enemy (this sentence may have sounded a little bit confusing , but basically it goes back to my first problem hahah)

the next one, does the same thing, maybe because it means the same thing, but anyways, i had to try it.

 if (Player.checkHit(enemy.getPos().x, enemy.getPos().y) &&!Player.getDead()) {
    Player.die();
    Player.setDead(true);
  } else if(!Player.checkHit(enemy.getPos().x,enemy.getPos().y)) {
    Player.setDead(false);
  }
  
   if (Player.checkHit(enemy2.getPos().x, enemy2.getPos().y) && !Player.getDead()) {
    Player.die();
    Player.setDead(true);
  } else if(!Player.checkHit(enemy2.getPos().x,enemy2.getPos().y)) {
    Player.setDead(false);
  }

well, i guess that’s all my doubts for now… i also would like to see some of the “constraint” syntax to see how it works to set boundaries in the scene - and also think about scene transactions… but for that i think you might charge me hahaha :smiley:

1 Like

Hello again ! Good Sir !

Your creating a new class ! For what ? The same enemy ? When we build a class now we can utilize that class as a ‘mothership’ and can get little alien babies from it which only differ depending on the variable that each object ( baby alien ) can have set within it constructor ( Also a total Area 51 reference right now :stuck_out_tongue: ). There’s no need for making a new class it removes the whole point of a class then !

Also the collision if we are not on the enemy doesn’t work anymore with multiple enemies as this will break the way we negate data as one enemy could be true and then becomes false and one is false and becomes true and breaks the logic. So now we need to employ a different system for checking.

Also I refactored all your code. So it all nice looking. Anything you don’t understand let me know !

Player Player;
Enemy enemies[];



void setup() {
  size (640, 480);
  noStroke();
  //position speed size
  enemies = new Enemy[2];
  Player = new Player(new PVector(10, height/2), 6, 20);
  for (int i = 0; i < enemies.length; i++) enemies[i] = new Enemy( new PVector(width/2, 100*(i+1) ), 3, 20);
}


void draw() {
  background(126);
  showEntities();
  text ("Score: " + Player.getScore(), 10, 460);
  text ("Deaths: " + Player.getDeaths(), 570, 460);
}
void showEntities() {
  Player.display(color(0, 255, 0));
  for ( Enemy i : enemies ) {
    println( Player.checkHit( i.getPos(), i.getSize() ) );
    i.display(color(255, 0, 0));
    if (Player.checkHit( i.getPos(), i.getSize() ) && !Player.getDead() ) {
      Player.die();
      Player.setDead(true);
    } else if ( Player.scanAll( enemies ) ) {
      Player.setDead(false);
    }
  }
}
void keyPressed() {
  Player.isMove(keyCode, true);
}
void keyReleased() {
  Player.isMove(keyCode, false);
}
 public class Enemy {
  PVector pos;
  float speed;
  int size;
  Enemy(PVector pos, float speed, int size) {
    this.pos = pos;
    this.speed = speed;
    this.size = size;
  }
  void display(color enemyColor) {
    fill(enemyColor);
    rect(pos.x, pos.y, size, size);
  }
  void moveAround(float point) {
    for (float x = 0; pos.x < point; x += speed) {
      pos.x += x;
    }
  }
  PVector getPos() {
    return pos;
  }
  int getSize() {
    return size;
  }
}

public class Player {
  PVector pos;
  int size, deaths, score;
  boolean deadState;
  boolean isUp, isDown, isLeft, isRight;
  float speed;
  Player(PVector pos, float speed, int size) {
    this.pos = pos;
    this.size = size;
    this.speed = speed;
    score = 0;
    deaths = 0;
  }
  void display(color playerColor) {
    fill(playerColor);
    ellipse(pos.x, pos.y, size, size);
    movePlayer();
  }
  void movePlayer() {
    if (isUp) pos.y -= speed;
    if (isDown) pos.y += speed;
    if (isLeft) pos.x -= speed;
    if (isRight) pos.x +=speed;
  }
  void die() {
    deaths++;
    score = 0;
  }
  boolean checkHit(PVector enemPos, int enemySize) {
    return (pos.x >= enemPos.x - enemySize && pos.y >= enemPos.y - 
      enemySize && pos.x <= enemPos.x + enemySize && 
      pos.y <= enemPos.y + enemySize);
  }
  boolean isMove(int k, boolean pressed) {
    switch(k) {
    case UP: 
      return isUp = pressed;
    case DOWN: 
      return isDown = pressed;
    case LEFT: 
      return isLeft = pressed;
    case RIGHT: 
      return isRight = pressed;
    default: 
      return false;
    }
  }
  //
  boolean scanAll(Enemy enemies[]) {
    for (int i = 0; i < enemies.length; i++) {
      if ( checkHit( enemies[i].getPos(), enemies[i].getSize() ) ) return false;
    }
    return true;
  }
  boolean getDead() {
    return deadState;
  }
  void setDead(boolean isDead) {
    deadState = isDead;
  }
  int getScore() {
    return score;
  }
  int getDeaths() {
    return deaths;
  }
}

Can you elaborate on this ?