user4778178
user4778178

Reputation:

Java: Moving objects at the same time

I apologize if my code is bit primitive, I'm still new to programming.

I am currently working on little java game where I need to have objects scroll in from the right edge towards the left.

The objects then need to be caught by a player on the left which scrolls up and down with the mouse or keyboard.

I am having a problem with getting the objects to move at the same, I can get the player to move perfectly when no objects are scrolling. But the moment objects begin to move I have issues where to implement the move() function for the player so that it constantly moves with input, without being dependent on the objects scrolling left.

Currently I'm trying to update the movement of the player in three places, which are not working without moving the player relative to the scollers. In the game loop:

public void play()
{
    while (!isGameOver())
    { 
        StdDraw.clear(StdDraw.BLACK);   
        grid.moveAll();
        grid.draw(0, 10);
        StdDraw.setPenColor(StdDraw.WHITE);
        StdDraw.text(100, 5, "Score: " + game.getScore());
        //Grid.U.move(Grid.playerR, Grid.playerC);
        StdDraw.show(20);
        //Grid.U.move(Grid.playerR, Grid.playerC);
        if (msElapsed % 300 == 0)
        {
            grid.populateRightEdge();
        }
        msElapsed += 20;
    }
}

In the grid file when object G(one of the scrollers) is told to be drawn:

public void draw(int atX, int atY) {

    for (int r = 0; r < num_Cols; r++) {
        for (int c = 0; c < num_Rows; c++) {
            //System.out.println("test1");
            if (grid[r][c] == U) {
                U.draw(c, r, grid_CellSize);
            }    if (grid[r][c] == A) {
                A.draw(c, r, grid_CellSize);;
            } if (grid[r][c] == G) {
                //Grid.U.move(Grid.playerR, Grid.playerC);
                G.draw(c, r, grid_CellSize);
            }
        }
    }

And in the class where object G is moved:

  public Location move(int r, int c) {
 //Grid.U.move(Grid.playerR, Grid.playerC);
 Grid.grid[r-1][c] = Grid.grid[r][c];
 Grid.grid[r][c] = null;
//Grid.U.move(Grid.playerR, Grid.playerC);
 try {
    TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
return null;

} }

The commented text shows the command to read the movement of the player. I need a way to do this without it being dependent on the scrollers, what other methods could I implement in my code to do this?

Edit: After moving the code to within the thread.sleep function an encounter that the program slows down as the scrolling objects increases, the more objects that scroll, the slower they all scroll. How can I prevent this?

Upvotes: 0

Views: 2620

Answers (1)

ankhzet
ankhzet

Reputation: 2568

Look here for more/less complete example.


Explanations:

First, make use of OOP and inheritence, like, all yours processable entities must have (and inherit) some void process() method, and renderable - void render() method. Like Grid:

class Grid {

  int w;
  int h;

  public Entity[][] cells;

  public Grid(int w, int h) {
    this.w = w;
    this.h = h;
    cells = new Entity[h][w];
  }

  public void process(long timemillis) {
    // here you can process grid

    // like, change some tiles, progress animations, etc
  }

  public void render(long timemillis) {
    // here you can draw grid
  }

}

Also, player and G entities follow the same rule:

class Entity {

  public void process(long timemillis) {

  }

  public void render(long timemillis) {

  }

}

Thus:

class G extends Entity {

  // override parent process() method
  @Override
  public void process(long timemillis) {
    moveLeft(speed); // we should move left by amount, specified by "speed" 
  }

  @Override
  public void render(long timemillis) {
    // here goes rendering code for G entities
  }
}

class Enemy extends Entity {

  @Override
  public void render(long timemillis) {
    // here goes rendering code for Enemy entities
  }
}

class Bonus extends Entity {

  @Override
  public void render(long timemillis) {
    // here goes rendering code for Bonus entities
  }
}

class Player extends G {

  // override processing method if needed...
  @Override
  public void process(long timemillis) {
  }

  @Override
  public void render(long timemillis) {
    // here goes rendering code for player
  }
}

Why like this? Because now you can do like this:

class Game {

  Grid grid;
  ArrayList<Entity> entities;
  long lastProcess;

  public Game() {
    grid = new Grid(30, 20);
  }

  public void newGame() {
    lastProcess = 0;
    entities = new ArrayList<>();
  }

  public void render(long timemillis) {
    grid.render(timemillis);

    for (Entity entity : entities)
      entity.render(timemillis);
  }

  public void process(long timemillis) {
    grid.process(timemillis); // process grid (like, some animation)

    for (Entity entity : entities) // process entities
      entity.process(timemillis);

    if (timemillis - lastProcess > 300) { // each 300 msec ()
      lastProcess = timemillis;

      Entity spawn;

      // choose and spawn some random object
      switch (((int)(Math.random() * 10)) % 4) {
      case 0: // spawn G
        spawn = new G(this); break;
      case 1: // spawn Enemy
        spawn = new Enemy(this); break;
      case 2: // spawn Bonus
        spawn = new Bonus(this); break;
      case 3: // spawn Secret
        spawn = new Secret(this); break;
      }

      // spawn it at right grid edge (grid.w - 1) at random y position
      spawn.moveTo(grid.w - 1, (int)(Math.random() * 9999) % grid.h);
      entities.add(spawn);
    }
  }

}

In order to make processing/rendering asynchronous, use threads (Thread class):

public class Launcher extends Application {

  Thread gameThread;

  int renderFPS = 30; // 

  int processPPS = 10;
  // five processings per second (around 1000 / 10 = 100 msec between each)

  boolean running;

  Game game;

  public static void main(String[] args) {
    // here goes the initialization
    Launcher launcher = new Launcher();
    launcher.launch();
  }

  public void launch() {
    running = false;

    // instantiating game object
    game = new Game();

    // creating thread
    gameThread = new Thread(new Runnable() {

      @Override
      public void run() {
        // this code will be executed in thread

        running = true;
        // here goes the rendering/processing "meat";
        long lastIteration = System.currentTimeMillis();
        long lastRender = lastIteration;
        long lastProcess = lastIteration;

        long msecPerRender = 1000 / renderFPS;
        long msecPerProcess = 1000 / processPPS;

        // main game loop
        while (running) {
          long now = System.currentTimeMillis();

          // should we draw next frame?
          long delta = now - lastRender;
          if (delta >= msecPerRender) {
            lastRender = now - (delta - msecPerRender);
            game.render(lastRender);
          }

          // is it time for processing next game iteration?
          delta = now - lastProcess;
          if (delta >= msecPerProcess) {
            lastProcess = now - (delta - msecPerProcess);
            game.process(lastProcess);
          }
        }
      }
    });

    // start the thread
    gameThread.start();

    // in order to keep app running, we should wait for thread execution finished
    try {
      gameThread.join();
    } catch (InterruptedException ex) {
    }
  }

  // to stop the application execution
  public void stop() {
    running = false;
  }

  // here you can move yours player
  public void movePlayer() {
    boolean moveUp = true; // calc direction
    if (moveUp)
      game.player.moveVertically(1);
    else
      game.player.moveVertically(-1);
  }

}

Notice: code at pastebin uses swing library for simplicity.

Upvotes: 1

Related Questions