millis() Not Resetting Properly in rolling() Method

I’m working on a game in Processing and facing an issue where millis() is not resetting as expected in my rolling() method within the Player class. The method is triggered by pressing the down arrow, and it’s supposed to reset the rolling timer. However, the values of roll and rollingTimer are not updating correctly. The stamina += 3 line in the same method works fine, indicating that the method is executing. I’ve added println statements for debugging, which suggest the issue is around the millis() reset. Here’s the relevant portion of my code: below are the relevant classes of my code



Player knight;
King king;
Demon demon;
God god;

Gameworld throne;
Gameworld2 hell;

mainPage main;

Character character;

int gameState;
final int TITLE_PAGE = 0;
final int TUTORIAL = 1;
final int LEVEL_ONE = 2;
final int LEVEL_TWO = 3;
final int LEVEL_THREE = 4;
final int WON = 5;
final int LOST = 6;

void setup(){
  size(1000,1000);
  loadAssets();
  
  main = new mainPage();
  
  knight = new Player(new PVector(width/2,height/2), 10, 1, 1);
  king = new King(new PVector(50,50), 10, 1, 1);
  demon = new Demon(new PVector(50,50), 15, 1, 1);
  god = new God(new PVector(50,50), 20, 1, 1);
  throne = new Gameworld();
  hell = new Gameworld2();
 
}

void draw(){
   background(255);
   switch(gameState){
   case TITLE_PAGE:
     main.display();
     break;
   case LEVEL_ONE:
     stage(king, throne);
       break;
   case LEVEL_TWO:
     stage(demon, hell);
       break;
   case LEVEL_THREE:
     stage(god, throne);
       break;
   }
}

void stage(King opponent, Gameworld gw){
   gw.display();
   
   knight.drawMe();
   knight.update();
   
   opponent.drawMe();
   opponent.update();
   
   if (knight.combos.size() >= 3){
     knight.attackingAnimation();
     playSound(audioAttack);
     knight.attack = true;
     if (knight.combos.get(2) == 1 && knight.stamina >= 1){
       knight.damage = 1;
       knight.stamina --;
       println(king.health);
       king.drawDamage();
       if (millis() - opponent.attackTimer >= 6000){
         opponent.attackTimer = 6000;
       }
     } else if (knight.combos.get(2) == 2 && knight.stamina >= 2){
       knight.damage = 2;
       knight.stamina -= 2;
       king.drawDamage();
       println(king.health);
       if (millis() - opponent.attackTimer >= 6000){
         opponent.attackTimer = 5000;
       }
     } else if (knight.combos.get(2) == 2 && knight.stamina < 2 || (knight.combos.get(2) == 1 && knight.stamina < 1)){
     }  knight.staminaTimer = millis();
     if (opponent.nullify == false){
       knight.hit(opponent, knight.damage);
   }else if (opponent.nullify == true){
     opponent.blockTimer = millis();
     opponent.nullify = false;
   }
   knight.clearCombos();
   knight.attack = false;
   opponent.sideBlock = random(0,2);
   opponent.elementBlock = random(0,2);
   println("action");
   }
}
void keyPressed() {
  knight.keyPressed();
}

void keyReleased() {
  knight.keyReleased();
}

class King extends Character{
  float sideBlock;
  float attackBuffer;
  boolean miss;
  float attackTimerEnd;
  float elementBlock;
  float deathTimer;
  float animationTimer;
  float blockTimer;
  float missTimer;
  
  King(PVector pos, int health, float attackTimer, int damage){
    super(pos, health, attackTimer, damage);
    sideBlock = 0;
    MAX_HEALTH = 10;
    attackTimer = millis();
    attackBuffer = -1;
    miss = false;
    attackTimerEnd = 10000;
    deathTimer = -1;;
    activeKingImg = kingDefault;
    blockTimer = -1;
    missTimer = -1;
  }
  
  void drawMe(){
    pushMatrix();
    translate(pos.x, pos.y);
    scale(3,3);
    rect(50,50,50,50);
    popMatrix();
  }
  
  void death(){
    attackTimer = millis();
    knight.health = 10;
    gameState = LEVEL_TWO;
  }
  
  void drawDeath(){
    activeKingImg = kingDeathAnimation;
    playSound(audioDefeat);
  }
  
  void attackingAnimation(){
    activeKingImg = kingAttack;
    animationTimer = millis();
  }
  
  void displayMiss(){
    if (millis() - missTimer < 500){
    translate(pos.x + 50, pos.y-100);
    strokeWeight(1);
    fill(0);
    textSize(20);
    text("Miss!", width/4, width/3);
    }
  }
  
  void displayBlocked(){
    if (millis() - blockTimer < 500){
    pushMatrix();
    translate(pos.x + 50, pos.y-100);
    strokeWeight(1);
    fill(0);
    textSize(50);
    text("Blocked!", width/4, width/3);
    popMatrix();
    }
  }
  
  void nullifyLeft(){
   if (sideBlock < 1 && health >= 0 && millis() - animationTimer > 1100){
   pushMatrix();
   translate(pos.x,pos.y);
   activeKingImg = kingLeftBlock;
   popMatrix();
   }
 }
 
  void nullifyRight(){
   if (sideBlock >= 1 && health >= 0 && millis() - animationTimer > 1100){
   pushMatrix();
   translate(pos.x,pos.y);
   activeKingImg = kingRightBlock;
   popMatrix();
   }
 }
  
  void autoAttack(){
    if(health >= 0){
    if (millis() - attackTimer >= attackTimerEnd) {
    attackTimer = millis();
    attackBuffer = millis();

  }

  if (attackBuffer >= 0 && millis() - attackBuffer <= 1000) {
    if (millis() - knight.roll <= 500) {
      println("missing");
      miss = true;
      missTimer = millis();
    }
    attackingAnimation();
    playSound(audioAttack);
  }

  if (attackBuffer >= 0 && millis() - attackBuffer >= 1000) {
    println(miss);
    if (miss == false) {
      hit(knight,1);
      activeKingImg = kingAttackFinish;
      animationTimer = millis();
      println(knight.health);
      knight.clearCombos();
    }
    miss = false;
    println(knight.health);
    attackBuffer = -1;
  }
    }
  }
  void drawDamage(){
    activeKingImg = kingTakeDamage;
    animationTimer = millis();
  }
  
  void update(){
   super.update();
   if (health <= 0){
     drawDeath();
     if (deathTimer <= -1){
       deathTimer = millis();
     }
     if (millis() - deathTimer >= 1000){
     death();
   }
   }
  if (millis() - animationTimer < 1000) {
    return;
  }
   nullifyLeft();
   nullifyRight();
   nullify();
   autoAttack();
   
   displayBlocked();
   displayMiss();
  }
 
  void drawHealthBar(){
    super.drawHealthBar();
  }
  
  void nullify(){
    if (knight.combos.size() >= 1){
      if (sideBlock < 1 && knight.combos.get(0) == 1){
        nullify = true;
    }else if (sideBlock >= 1 && knight.combos.get(0) == 2){
        nullify = true;
    }
    }
  }
}

class Player extends Character{
  boolean prep, dodge;
  float roll;
  int stamina;
  float preppingTimer;
  float rollingTimer;
  float animationResetTimer;
  float staminaTimer;

  
  ArrayList<Integer> combos = new ArrayList<Integer>();
  
  Player(PVector pos, int health, float attackTimer, int damage){
    super(pos, health, attackTimer, damage);
    prep = false;
    dodge = false;
    roll = millis();
    attackTimer = millis();
    stamina = 6;
    preppingTimer = -1;
    rollingTimer = -1;
    MAX_HEALTH = 10;
    activeFrames = defaultSword;
    animationResetTimer = millis();
    staminaTimer = -1;

  }

  void updateFrame() {
   super.updateFrame();
   
  }

  void clearCombos(){
    combos.clear();
  }
  
  void notEnoughStamina(){
    if (millis() - staminaTimer < 500);
    pushMatrix();
    translate(pos.x, pos.y);
    strokeWeight(1);
    fill(0);
    textSize(50);
    text("Not enough \nstamina!", width/2 + width/4 + 50, width/3 + width/3);
    popMatrix();
  }
  
  void restingSword(){
    activeFrames = defaultSword;
  }
  
  void attackingAnimation(){
    activeFrames = swingSword;
    animationResetTimer = millis();
  }
  
  void swordDodge(){
    activeFrames = swordDodge;
    animationResetTimer = millis();
  }
  
  void drawDamage(){
    activeFrames = swordDamage;
    animationResetTimer = millis();
  }
  
  void animationReset(){
    if (activeFrames != defaultSword && millis() - animationResetTimer > 500){
      restingSword();
    }
  }
  
  void rolling(){
    stamina += 3;
    if (stamina > 6){
      stamina = 6;
    }
    roll = millis();
    clearCombos();
    rollingTimer = millis();
    println(roll);
    println(rollingTimer);
    println("rolling");
  }
  
  void keyPressed(){
    if (millis() - roll >= 250){
    if (key==CODED && millis() - attackTimer >= 250) {
      if (keyCode==UP) prep=true;
      if (keyCode==DOWN) {println("rolling happening");rolling();swordDodge();playSound(audioRoll);}
    if (prep == true) {
      if (keyCode==LEFT) combos.add(1);
      if (keyCode==RIGHT) combos.add(2);
    }
    } else if (key==CODED && millis() - attackTimer <= 500) {
    preppingTimer = millis();
  }
  attackTimer = millis();
  dodge = false;
  println("Combos: " + combos);
  }else if (millis() - roll <= 500){
    dodge = true;
    rollingTimer = millis();
  }
}

  void keyReleased(){
  if (key==CODED) {
    if (keyCode==LEFT) prep=false;
    if (keyCode==RIGHT) prep=false;
    }
}
  void drawMe(){
    pushMatrix();
    translate(pos.x, pos.y);
    scale(3,6);
    rect(width/50,height-50,50,50);
    
    popMatrix();
  }
  
  void drawDeath(){
    super.drawDeath();
  }
  
  void update(){
   super.update(); 
   displayRolling();
   displayPrepping();
   updateFrame();
   animationReset();
  }
  
  void displayRolling(){
    if (rollingTimer >= 0 && millis() - rollingTimer <= 1000){
      strokeWeight(1);
      fill(0);
      textSize(20);
      text("rolling!", width/2 + width/4 + 50, width/3 + width/3);
    }
  }
  void displayPrepping(){
    if (preppingTimer >= 0 && millis() - preppingTimer <= 1000){
      strokeWeight(1);
      fill(0);
      textSize(20);
      text("performing an \naction!", width/2 + width/4 + 50, width/3 + width/3);
    }
  }
  void drawHealthBar(){
    super.drawHealthBar();
  }
}
class Character{
  int health;
  float attackTimer;
  int damage;
  PVector pos;
  boolean isAlive;
  boolean nullify;
  boolean attack;
  int MAX_HEALTH;
  float deathMovement;
  PImage img;
  int animationRate;
  int currFrame;
  float damageText;
  
  Character(PVector pos, int health, float attackTimer, int damage){
    this.pos = pos;
    this.health = health;
    this.attackTimer = attackTimer;
    this.damage = damage;
    nullify = false;
    attack = false;
    deathMovement = 0;
    this.img = img;
    currFrame = 0;
    animationRate = 3;
    damageText = -1;
  }
  
  void hit(Character opponent, int damage){
    opponent.health -= damage;
    opponent.drawDamage();
    playSound(audioTakeDamage);
    damageText = millis();
    opponent.damageNumber(damage);
  }
  
  void attackingAnimation(){
  }
  
  void updateFrame() {
   if (frameCount % animationRate == 0) { 
      if (currFrame < activeFrames.length-1) 
         currFrame++;                    
      else 
         currFrame = 0; 

      img = activeFrames[currFrame];
  }
  }
  
  void damageNumber(int damage){
    if (millis() - damageText < 500){
    pushMatrix();
    translate(pos.x, pos.y-100);
    strokeWeight(1);
    fill(0);
    textSize(50);
    text("-"+damage, width/4, width/3);
    popMatrix();
    }
  }
  
  void drawMe(){
    if(health > 0){
    pushMatrix();
    translate(pos.x,pos.y);
    fill(255,125,58);
    rect(0,0,200,200);
    popMatrix();
    }
  }
  
  void drawDeath(){
    if(health <= 0){
    pushMatrix();
    fill(255,125,58);
    rect(pos.x,pos.y+deathMovement,200,200);
    if (deathMovement <= 100){
      deathMovement += 0.5;
    }
    popMatrix();
    }
  }
  void drawHealthBar() {
   if (health >= 0){
   int max=200;
   pushMatrix();
   translate(pos.x + 150, pos.y);
   noStroke();
   fill(255, 0, 0);
   float playerHealthPercentage=(float) health/MAX_HEALTH; 
   rect(0, 0, max*playerHealthPercentage, 20);             
   popMatrix();     
   }
  }
  
  void drawDamage(){
  }
  
  void update(){
    drawMe();
    drawHealthBar();
  }
}


  PImage img;
  
  PImage titlePage;
  PImage playButton;
  PImage tutorialButton;
  
  PImage activeKingImg;
  PImage kingLeftBlock;
  PImage kingRightBlock;
  PImage kingAttack;
  PImage kingAttackFinish;
  PImage kingTakeDamage;
  PImage kingDeathAnimation;
  PImage kingDefault;
  PImage throneWorld;
  
  PImage activeDemonImg;
  PImage demonLeftBlock;
  PImage demonRightBlock;
  PImage demonAttack;
  PImage demonAttackFinish;
  PImage demonTakeDamage;
  PImage demonDeathAnimation;
  PImage demonDefault;
  PImage demonWorld;
  
  PImage activeGodImg;
  PImage godLeftBlockDemon;
  PImage godLeftBlockHoly;
  PImage godRightBlockDemon;
  PImage godRightBlockHoly;
  PImage godAttack;
  PImage godAttackFinish;
  PImage godTakeDamage;
  PImage godDeathAnimation;
  PImage godDefault;
  
  PImage[]  activeFrames;
  PImage[]  defaultSword=new PImage[5];
  PImage[]  swingSword=new PImage[5];
  PImage[]  swordDodge=new PImage[5];
  PImage[]  swordDamage=new PImage[5];
  
  final String audioAttack = "fire.mp3";
  final String audioTakeDamage = "meow.wav";
  final String audioDefeat = "powerup.wav";
  final String audioRoll = "";
  
  
  void loadFrames(PImage[] ar, String fname) {
   for (int i=0; i<ar.length; i++) {
      PImage frame=loadImage(fname+i+".png");
      frame.resize(200, 100);
      ar[i]=frame;
      
   }
  }
  
  void loadAssets(){
    
    titlePage = loadImage("title_screen.png");
    playButton = loadImage("play_button.png");
    tutorialButton = loadImage("tutorial_button.png");
    
    loadFrames(defaultSword, "default_sword_");
    loadFrames(swingSword, "sword_strike_");
    loadFrames(swordDodge, "sword_dodge_");
    loadFrames(swordDamage, "sword_damage_");
    
    kingLeftBlock = loadImage("king_guard_left.png");
    kingRightBlock = loadImage("king_guard_right.png");
    kingAttack = loadImage("king_attack.png");
    kingAttackFinish = loadImage("king_attack_finish.png");
    kingTakeDamage = loadImage("king_take_damage.png");
    kingDeathAnimation = loadImage("king_defeat.png");
    kingDefault = loadImage("king_default.png");
    throneWorld = loadImage("throne.png");
    
    demonLeftBlock = loadImage("demon_guard_left.png");
    demonRightBlock = loadImage("demon_guard_right.png");
    demonAttack = loadImage("demon_attack.png");
    demonAttackFinish = loadImage("demon_attack_finish.png");
    demonTakeDamage = loadImage("demon_take_damage.png");
    demonDeathAnimation = loadImage("demon_defeat.png");
    demonDefault = loadImage("demon_default.png");
    demonWorld = loadImage("hell.png");
    
    godLeftBlockDemon = loadImage("god_guard_left_demon.png");
    godLeftBlockHoly = loadImage("god_guard_left_holy.png");
    godRightBlockHoly = loadImage("god_guard_right_demon.png");
    godRightBlockDemon = loadImage("god_guard_right_holy.png");
    godAttack = loadImage("god_attack.png");
    godAttackFinish = loadImage("god_attack_finish.png");
    godTakeDamage = loadImage("god_take_damage.png");
    godDeathAnimation = loadImage("god_defeat.png");
    godDefault = loadImage("god_default.png");

  }
  
  void playSound(String file) {
   switch(file) {
   case audioAttack:
      //attack.play(0);
      break;
   case audioTakeDamage:
      //takeDamage.play(0);
      break;
   case audioDefeat:
      //defeat.play(0);
      break;
   case audioRoll:
      //roll.play(0);
      break;
   }
}

https://www.Reddit.com/r/processing/comments/188vtl7/millis_not_resetting_properly_in_rolling_method/

2 Likes

Welcome to the forum.

You need to edit your post to remove the second half which is a duplicate of the first half.

You have a lot of code here which cannot be run because it is incomplete - no Character class.

millis() returns the time since the sketch was launched n milliseconds. It cannot be reset so you need to be clearer what you mean. Perhaps you might describe in what you expect the rolling() method to do.

2 Likes

I’ve been using variable = millis() is as a timer in my codes, and it have worked for me in the past for like 3 projects. It’s just this once that is behaving this way.

Obviously it is a bug in your code since millis() behaves as expected.

Unfortunately your code is incomplete and cannot be executed and I don’t have the time or inclination of doing a line-by-line code search looking for an elusive logic error.

I suggest you edit the code in your first post so that it can be executed and remove the excessive duplicate text.

I suggest create a new function that prints all the timers (names and values) then you can call this method from anywhere in your code. This will help identify the unexpected behaviour and locate the problem.

I’ve already tried debugging by printing the values and names at different points and the rolling method is where I ended up. I’ve edited my post and changed the things a little so now it should run if you plug it into processing. Thanks so much for your help.

I copied the code into Processing and it didn’t run. Looks like most of the classes were missing.