This site requires JavaScript, please enable it in your browser!
Greenfoot back
DaRafster
DaRafster wrote ...

2020/4/12

Removing timer

DaRafster DaRafster

2020/4/12

#
I have a timer for an asteroid in the world, once the timer is done, the game starts and the asteroid starts to move, and when it touches the edge, it wraps. I've made it so every single time the asteroid wraps, a new asteroid is added into the world. This will force the player to destroy them instead of dodging them once I add a shooting functionality. However, once a new asteroid is added into the world, the new asteroid has to go through the timer again until it could move. How would I make the new asteroids being added into the world, not have to go through this same timer? Here is my asteroid code:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class Asteroid here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class Asteroid extends EnemyObjects
{
    private int time = 500;
    private int time2 = 2350;
    int speed = 5;
    public Asteroid()
    {
        GreenfootImage myImg = getImage();
        myImg.scale(myImg.getWidth()/15, myImg.getHeight()/15);
        setImage(myImg);
    }
    
    public void asteroidMovement()
    {
        time--;
        if(time <= 0)
        {
            move(-speed);
        }
    }
    
    public void wrapAtEdge()
    {
        time2--;
        if(time2 > 0 && getX() < 0)
        {
            setLocation(getWorld().getWidth(),Greenfoot.getRandomNumber(600));
            Asteroid newAsteroid = new Asteroid();
            getWorld().addObject(newAsteroid, getWorld().getWidth(),Greenfoot.getRandomNumber(600));     
        }
    }
    
    public void act()
    {
        asteroidMovement();
        wrapAtEdge();
    }
}
danpost danpost

2020/4/12

#
You could add a boolean parameter to the constructor to indicate timer use and set the initial time value based on that boolean value.
DaRafster DaRafster

2020/4/12

#
danpost wrote...
You could add a boolean parameter to the constructor to indicate timer use and set the initial time value based on that boolean value.
I've attempted what you just said, but I did it incorrectly. I've created a boolean value and threw it into the asteroid constructor, I made the first asteroid have the boolean value of true so the if statement in the asteroidMovement method would run. But, I've made the new asteroids being added into the world when wrapped false, yet it still has to go through the timer. So, where did I go wrong in the code? Or did I misinterpret what you suggested?
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class Asteroid here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class Asteroid extends EnemyObjects
{
    private int time = 500;
    private int time2 = 2350;
    private boolean timerUse = true;
    public Asteroid(int speed, boolean timerUse)
    {
        GreenfootImage myImg = getImage();
        myImg.scale(myImg.getWidth()/15, myImg.getHeight()/15);
        setImage(myImg);
    }
    
    public int getRandomNumber(int start,int end)
    {
        int normal = Greenfoot.getRandomNumber(end-start+1);
        return normal+start;
    }
    
    public void asteroidMovement()
    {
        time--;
        if(time <= 0 && timerUse == true)
        {
            move(-getRandomNumber(5,10));
        }
    }
 
    public void wrapAtEdge()
    {
        time2--;
        if(time2 > 0 && getX() < 0)
        {
            setLocation(getWorld().getWidth(),Greenfoot.getRandomNumber(600));
            Asteroid newAsteroid = new Asteroid(getRandomNumber(5,10), false);
            getWorld().addObject(newAsteroid, getWorld().getWidth(),Greenfoot.getRandomNumber(600));     
        }
    }
    
    public void act()
    {
        asteroidMovement();
        wrapAtEdge();
    }
}
danpost danpost

2020/4/12

#
Add to constructor:
if ( ! timerUse) time = 0;
set the initial time value based on that boolean value.
Remove line 15 and timerUse condition on line 30.
danpost danpost

2020/4/12

#
I guess, to make it more versatile, you could just pass the initial time itself:
public Asteroid(int speed, int delay)
{
    time = delay;
    ...
DaRafster DaRafster

2020/4/12

#
Thanks, it worked. However, I may have found a possible preferred way I would like my game to be, to make things more randomized. Here is the following code I tried in a copy:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class MyWorld here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class Galaxy extends World
{
    private int time, time2;
    private int asteroidDelayCount = 0;
    public Galaxy()
    {    
        super(1000, 600, 1, false); 
        time = 500;
        time2 = 2000;
        prepare();
    }

    private void prepare()
    {
        Spacecraft spacecraft = new Spacecraft();
        addObject(spacecraft,150,getHeight()/2);
        createNewAsteroid();  
    }
    
    private void createNewAsteroid()
    {
        Asteroid[] asteroids = new Asteroid[25];
        for(int i = 0; i < asteroids.length; i++)
        {
            asteroids[i] = new Asteroid();
            int asteroidX = getWidth() + Greenfoot.getRandomNumber(2000);
            int asteroidY = Greenfoot.getRandomNumber(getHeight());
            newAsteroidDelay();
            if(asteroidDelayCount > 0)
            {
                asteroidDelayCount--;
                if(asteroidDelayCount == 0)
                {
                    addObject(asteroids[i], asteroidX, asteroidY);
                }
            }
        }
    }   
        
    private void newAsteroidDelay()
    {
        asteroidDelayCount = 100;
    }

    private void showFirstTimer()
    {
        showText("Game starts in: " + time, getWidth()/2,75);      
    }

    private void showSecondTimer()
    {
        showText("Time left: " + time2, getWidth()/2, 75);

        if(time2 <= 0)
        {
            showText("You survived! Proceed to the next level!", getWidth()/2, 75);
        }
    }

    private void startGameTimer()
    {
        if(time > -1)
        {
            time--;
            showFirstTimer();
        }  

        if(time <= 0)
        {
            time2--;
            showSecondTimer();
        }        
    }

    public void act()
    {
        startGameTimer(); 
    }
}
The idea is to spawn these asteroids beyond the edge and have them move to the left until visible, but when I added in the delay/timer code in the createNewAsteroid method, the asteroids no longer spawned into the world. Why is this the case? Shouldn't it have counted down to 0 then spawned an asteroid, then the cycle continues until all 24 asteroids are in the world?
danpost danpost

2020/4/13

#
asteroidDelayCount will never be 0 at line 40. Line 36 sets it to a value of 100; line 37 will always be true, so line 39 executes and reduces the value to 99. It will always be 99 when line 40 executes.
DaRafster DaRafster

2020/4/13

#
So how would I make the delay happen? Is there a way to have it countdown all the way down to 100 then add the asteroid?
danpost danpost

2020/4/13

#
Start count at 2500 and spawn when count%100== 0. No for loops needed. Remove line 25 and change line 28 to:
public void act()
which should continue with:
{
    if (count > 0 && (--count)%100 == 0) ... // add one asteroid
DaRafster DaRafster

2020/4/13

#
Sorry, I had trouble understanding where exactly I should put my code. I've removed the for loop and changed it into an act method, but everything else you said got me lost. Here's what I did so far:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
 
/**
 * Write a description of class MyWorld here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class Galaxy extends World
{
    private int time, time2;
    private int asteroidDelayCount = 0;
    public Galaxy()
    {    
        super(1000, 600, 1, false); 
        time = 500;
        time2 = 2000;
        prepare();
    }
 
    private void prepare()
    {
        Spacecraft spacecraft = new Spacecraft();
        addObject(spacecraft,150,getHeight()/2);
    }
     
    public void act()
    {
            startGameTimer(); 
            Asteroid asteroids = new Asteroid();
            int asteroidX = getWidth() + Greenfoot.getRandomNumber(2000);
            int asteroidY = Greenfoot.getRandomNumber(getHeight());
            newAsteroidDelay();
            if(asteroidDelayCount > 0)
            {
                asteroidDelayCount--;
                if (asteroidDelayCount > 0 && (--asteroidDelayCount)%100 == 0)
                {
                    addObject(asteroids, asteroidX, asteroidY);
                }
            }
            
    }   
         
    private void newAsteroidDelay()
    {
        asteroidDelayCount = 2500;
    }
 
    private void showFirstTimer()
    {
        showText("Game starts in: " + time, getWidth()/2,75);      
    }
 
    private void showSecondTimer()
    {
        showText("Time left: " + time2, getWidth()/2, 75);
 
        if(time2 <= 0)
        {
            showText("You survived! Proceed to the next level!", getWidth()/2, 75);
        }
    }
 
    private void startGameTimer()
    {
        if(time > -1)
        {
            time--;
            showFirstTimer();
        }  
 
        if(time <= 0)
        {
            time2--;
            showSecondTimer();
        }        
    }

}
What did I do wrong? Also, after you tell me what to correct, would it be alright if you explained what it meant? I'm putting all this code in that I don't have a full understanding of. Thank you for all the help though, appreciate it.
danpost danpost

2020/4/13

#
Move line 33 to before line 18. Remove line 34 thru 36 and line 41. Then move lines 30 thru 32 to before line 39.
danpost danpost

2020/4/13

#
Line 2 in what I game above -- namely:
if (count > 0 && (--count)%100 == 0)
says if the count is greater than zero (if it not, do nothing), then subtract one from its value and see if 100 divides into it evenly (the "%100" means to get the remainder when dividing by 100; the "--count" means to subtract one from its value immediately -- before getting the remainder). This will happen 25 times as it goes from 2500 to 0. If true, then add a new asteroid.
DaRafster DaRafster

2020/4/13

#
danpost wrote...
Line 2 in what I game above -- namely:
if (count > 0 && (--count)%100 == 0)
says if the count is greater than zero (if it not, do nothing), then subtract one from its value and see if 100 divides into it evenly (the "%100" means to get the remainder when dividing by 100; the "--count" means to subtract one from its value immediately -- before getting the remainder). This will happen 25 times as it goes from 2500 to 0. If true, then add a new asteroid.
Thanks, this will help me in future projects!
danpost danpost

2020/4/13

#
danpost wrote...
Move line 33 to before line 18.
That is not something you want to do every act step. Only when you want to initiate adding more asteroids.
Remove line 34 thru 36 and line 41.
Those actions are done in line 37.
Then move lines 30 thru 32 to before line 39.
You only need to do them when you know you are going to add an asteroid (after the conditions on line 37 are met).
You need to login to post a reply.