mercredi 4 mars 2015

Java: Running An Animation While Still Letting Everything Else In The Program Still Operate



Right know I am making a game. It's a 2-dimensional game and I'm not having much luck with the animations for player movement. I understand the concept but I can't get it to work because, unfortunately, even with a multi-threaded language, the computer cannot actually do two things at once. So I cannot run a while loop in one thread and still be able to run an event listener to accept keyboard input in another thread.


This is what I need help with: I need a way to call on one method over and over again from one thread. Then I still need to be able to have my key listener in another thread work so that not only will my code do something but I can also use keyboard input to terminate the while loop (or whatever kind of loop I use) which is calling on the method over and over again.


Here's the class containing the method I need to call over and over again (it's the update() method):



public class Screen extends Canvas implements KeyListener {
//variables
//direction the player is moving
private Direction movementDirection;

//the number of entities on the screen
private int quantity;

//the list of entities on the screen
private Entity[] entity;


//constructor
public Screen() {
System.out.println("Constructor Fired:Screen()"); //debug
movementDirection = Direction.IDLE;

quantity = 1;
entity = new Entity[quantity];

//entity[0] should ALWAYS be the player that is being controlled
entity[0] = new Gale(500, 250);
}


//methods
public void paint(Graphics g) {
System.out.println("Method Fired:Screen.paint(Graphics g)"); //debug
CGraphics cg = new CGraphics(g);
for(Entity entity:this.entity) {
cg.drawEntity(entity);
}
}

public void update() {
System.out.println("Method Fired:Screen.run()"); //debug
//set the coordinates of the player
switch(movementDirection) {
case DOWN:
entity[0].setY(entity[0].getY() + 1);
break;
case LEFT:
entity[0].setX(entity[0].getX() - 1);
break;
case RIGHT:
entity[0].setX(entity[0].getX() + 1);
break;
case UP:
entity[0].setY(entity[0].getY() - 1);
break;
case IDLE:
break;
default:
break;
}
Main.refresh();
}


//key listener methods
public void keyTyped(KeyEvent e) {

}

public void keyPressed(KeyEvent e) {
System.out.println("Method Fired:Screen.keyPressed(KeyEvent e)"); //debug
if(e.getKeyCode() == KeyEvent.VK_DOWN) {
entity[0].setState(EntityState.DOWN_WALK);
movementDirection = Direction.DOWN;
}
if(e.getKeyCode() == KeyEvent.VK_LEFT) {
entity[0].setState(EntityState.LEFT_WALK);
movementDirection = Direction.LEFT;
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
entity[0].setState(EntityState.RIGHT_WALK);
movementDirection = Direction.RIGHT;
}
if(e.getKeyCode() == KeyEvent.VK_UP) {
entity[0].setState(EntityState.UP_WALK);
movementDirection = Direction.UP;
}
}

public void keyReleased(KeyEvent e) {
System.out.println("Method Fired:Screen.keyReleased(KeyEvent e)"); //debug
if(e.getKeyCode() == KeyEvent.VK_DOWN) {
entity[0].setState(EntityState.DOWN_STAND);
movementDirection = Direction.IDLE;
}
if(e.getKeyCode() == KeyEvent.VK_LEFT) {
entity[0].setState(EntityState.LEFT_STAND);
movementDirection = Direction.IDLE;
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
entity[0].setState(EntityState.RIGHT_STAND);
movementDirection = Direction.IDLE;
}
if(e.getKeyCode() == KeyEvent.VK_UP) {
entity[0].setState(EntityState.UP_STAND);
movementDirection = Direction.IDLE;
}
if(e.getKeyCode() == KeyEvent.VK_ESCAPE) {
if(Main.pause) {
Main.pause = false;
} else {
Main.pause = true;
}
}
}


}


And here's is the method (which is called on from my main method) that I am using to call on my update() method:



public static void play() {
System.out.println("Method Fired:Main.play()"); //debug
if(!screenConfigured) {
configureScreen();
screenConfigured = true;
}
window.add(screen);
window.addKeyListener(screen);
refresh();

//repeat until the game is paused
pause = false;
while(!pause) {
screen.update();
}
}


Basically what is happening is I have 8 different images which are contained in the Gale class. Then I have my Screen class, which is both a canvas and key listener. I also have two enums, Direction(which is instantiated as movementDirection) and EntityState(which is contained within the Gale class). MovementDirection indicates which direction the Gale object(which is an entity) is moving, while EntityState indicates which of the 8 images to display.


MovementDirection can be: up, down, left, right (you can probably guess what each one means), and it can also be idle, which just indicates that the Gale object isn't moving.


EntityState can be: down_stand, down_walk, up_stand, up_walk, left_stand, left_walk, right_stand, and right_walk. The first word of each possible value indicates which direction the entity is facing. The second word of each possible value indicates whether the entity is standing or is it's walking.


Since the Gale object is the player you need to be able to control it. The key listener part of the Screen class changes the values of EntityState and MovementDirection depending on which arrow keys are pressed and released.


The paint method(by definition of a paint method in any extension of the canvas class) just paints the entity. cg is a custom graphics class i created. The drawEntity method(as you can probably guess) draws the entity given in the parameters at that entity's location(which is represented by an x and a y variable contained in the entity class). the drawEntity method draws one of the 8 different images from the Gale class depending on the value of EntityState.


The update() method changes the coordinates of the Gale object depending on the value of movementDirection.


The refresh() method in my Main class is just a method that refreshes the graphics whenever it is called.


Is there any way I can call on the update() method over and over again from the play() method while still allowing the key listener in the Screen class(along with every other task within my 18 classes) to still operate so I can terminate the play() method by pressing the escape key?


I would prefer to accomplish this task using this method, but I completely understand if it won't work. If it doesn't work (or even if it does but there is better way to accomplish this), what is the most efficient method of doing what I am trying to do?




Aucun commentaire:

Enregistrer un commentaire