Multidimensional Array Movement

I’m making a space invaders-esk game and i have 3 rows of 11 aliens. I’ve down this by creating a multi-dimensional array of aliens As this is supposed to be an invasion the aliens need to move down the screen every so often, currently i’m using this:

 // update the game
    public void update()
    {    	
    	// schedule the aliens to move down
    	alienTimer.schedule(new TimerTask(){

			public void run() 
			{
		    	// move the aliens row by row
		    	moveAliens();
			}
    		
    	}, 1000, 2000);
		
    }

    // move the aliens row by row
    private void moveAliens()
    {
    	for(int i = (aliens.length -1); i > -1; i--)
    	{
    		for(int j = 10; j > -1; j--)
    		{
    			if(aliens[i][j] == null)
    			{
    				// Do nothing alien doesn't exist
    			}
    			else
    			{
    				// move the alien down
    				aliens[i][j].moveDown();
    			}
    		}
    	}
    }

// Alien Move Down method
// move the alien
	public void moveDown()
	{
		getPosition().y += 5;
	}

but when i run the game the after the second delay all the aliens just move down the screen without stopping for the 2 second period. I’ve also tried scheduleAtFixedRate, but it had the same result.

Anyone have any ideas, and whilst your here, how could i go about having different rows move in opposite directions left and right, eg row 1 would move left, hit the screen bounce then move right, row 2 would move right, it the screen bounce, then move left.

Thanks for any help

With every call to update() (which happens at 60Hz or so) you schedule a new task.

So after 60 updates, you have scheduled 60 tasks that call moveAliens() after 2000ms.

After the initial 2000ms, every update/frame will effectively be calling moveAliens(), because the enormous amount of scheduled tasks.

What you need to do is call scheduleAtFixedRate and call that method only once, not for every update.

That works wonders, now however, if the level changes i want the period variable to decrease so that there is less time between each movement, is there anyway to do that?

Cancel the TimerTask and reschedule a new TimerTask.

Keep in mind however that [icode]java.util.Timer[/icode] uses a new Thread behind the scenes, and you will run into all kinds of trouble due to concurrency issues. It’s better (or… mandatory for non-experts) to handle all logic on the same thread.

If there is only one timer will it cause an issue creating multiple timertasks?
oh and in the timertask’s run method, i will want to change the speed every 5 levels, so could i use

if( level.getLevel() % 5 )
{
 this.cancel();
}

then have a variable that is changed in the period parameter

The rendering and all other logic is happening on another thread, so yes, it will cause the weirdest bugs and crashes, if you let multiple threads manipulate the same objects.

Is there a better way for me to handle the movement of the rows of aliens down the screen in a way so that i change the period between each movement?

I use my own timer class for these purposes. The idea is to move the aliens after counting the time.


public class GTimer
{
    public int elapsedTime;

    public void update(long elapsedTime)
    {
        this.elapsedTime = elapsedTime;
    }

    public void reset()
    {
        elapsedTime = 0;
    }
}

And use the timer like this.


timer.update(elapsedTime);

if (timer.elapsedTime >= frequencyToMove)
{
    moveAliensDown();
    timer.reset();
    // Increase frequency in bits
    frequencyToMove-=100;
}

Hope this helps.

It does :slight_smile: Thanks a lot :slight_smile:

Question , how have you implemented that timer? the second part of the code could be placed in the main gameloop and call a function such as sectick();.

i havent put it in yet, im still trying to work out how to pass the elapsed time variable, im not sure whether system.currentTimeMilliseconds() will work or not

I use this method.


public long getCurrentTime()
{
    return (long)(System.nanoTime()/1000000);
}

Hope this helps.

SHC do you just pass getCurrentTime() to the update() eg. update(getCurrentTime);?

No, you should be passing the delta into the update method. The currentTime method literally gives you the current time. You should always use the delta when updating your graphics because its time it takes to change frames. You should be passing elapsedTime I believe.

No, it’s just a method to calculate the time. Just use the time difference between the frames or simply called, the delta time. I just posted it since you asked about the System.currentTimeMillis() method.

My gameloop dosnt have an elapsed time, how will i do about getting that :confused:

Fixed time-step game loop? Then you can use [icode]UPDATES_PER_SECOND[/icode] as the elapsed time.

You mean 1.0 / UPDATES_PER_SECOND

Err… I’m not too sure :S
This is my game loop code:


		
	// constants for the game loop, fps etc
	final int TICKS_PER_SECOND = 30;
	final int SKIP_TICKS = 1000 / TICKS_PER_SECOND;

	// longs to control the interpolation
	long next_game_tick = System.currentTimeMillis();
	
	long sleep_time = 0;

	// Boolean to say game is running
	boolean game_is_running = true;


	// game loop class
    private class Logic extends Thread
    {
    	// constructor for game loop
    	public Logic() 
    	{
    		// start the thread
  	      start();
  	    }
    	// what to do when the thread starts
  	    public void run() 
  	    {
  	    	// the loop itself
  	    	while( game_is_running )
  			{
  	    		// run the update method
  				update();
  				//  repaint the screen
  				invalidate();
  			
  				// interpolation code
  				next_game_tick += SKIP_TICKS;
  				sleep_time = next_game_tick - System.currentTimeMillis();
  				
  				if( sleep_time >= 0 )
  				{
  					try
  					{	// stop the thread for a short period of time so that it isn't always running
  						Thread.sleep(sleep_time);
  					}
  					catch(InterruptedException e)
  					{
  						e.printStackTrace();
  					}
  				}
  				else
  				{
  					// Running behind
  				}
  			}
  	    }
    }

Yes. You can pass [icode]SKIP_TICKS[/icode] to the update method and use it as elapsed time.