Java game - run code sequentially in the game loop - java

I am creating a Java game within which the user can enter the commands of up, left, right, or down to move the character in that location for a certain amount of pixels. Within the Player class I am receiveing the commands from the user in an ArrayList of JTextFields after they have pressed the start button. I then use a for loop to go through all the inputs from the user and create x and y targets within a multi-dimensional array for the x and y amount of distance that the player needs to move. Finally I have a function called updatePosition() which is called within the main game loop. Within this function I loop through the multi-dimensional array of targets and have an if statement to check if the target has been reached or not. However when this method is executed and the user has input the commands of up and right for example, then the character moves diagonally up. I want a way which will move the character in the direction that the user has specified, executing them one after another.
Here is the code:
moveSpeed = 1;
private double moveAmt = 20;
private Double[][] targetCoordinates = null;
private ArrayList<JTextField> userInputTextFields = new ArrayList<JTextField>();
With method below I acquire the ArrayList of JTextFields within which the user has entered the commands and store it in a local ArrayList. I also instatiate an Array in the size of the amount of JTextFields that the user has entered the commands in. This array will be used to store the x and y targets for the character. I then lastly call the moveChar(); method which will set the target x and y.
public void getInputText(ArrayList<JTextField> textFields){
this.userInputTextFields = textFields;
targetCoordinates = new Double[userInputTextFields.size()][2];
moveChar();
}
This method will check if the commands that the user has enetered and set the x and y targets within the targetCoordinates array.
private void moveChar(){
for (int i = 0; i < userInputTextFields.size(); i++) {
if(userInputTextFields.get(i).getText().equals("up")){
targetCoordinates[i][0] = x;
targetCoordinates[i][1] = y - moveAmt;
} else if(userInputTextFields.get(i).getText().equals("down")){
targetCoordinates[i][0] = x;
targetCoordinates[i][1] = y + moveAmt;
} else if(userInputTextFields.get(i).getText().equals("left")){
targetCoordinates[i][0] = x - moveAmt;
targetCoordinates[i][1] = y;
} else if(userInputTextFields.get(i).getText().equals("right")){
targetCoordinates[i][0] = x + moveAmt;
targetCoordinates[i][1] = y;
}
}
}
Finally, this is the method which gets called within the main game loop. It goes through the targetCoordinates array and checks if the targets have been met. If not then incriment or decrement the character's x and y position accordingly.
public void updatePosition(){
if(targetCoordinates != null){
for (int i = 0; i < targetCoordinates.length; i++) {
if(y >= targetCoordinates[i][1]) {
moveCharacter(x, y - moveSpeed);
} else if(y < targetCoordinates[i][1]) {
moveCharacter(x, y + moveSpeed);
} else if(x > targetCoordinates[i][0]) {
moveCharacter(x - moveSpeed, y);
} else if(x <= targetCoordinates[i][0]) {
moveCharacter(x + moveSpeed, y);
}
}
}
}

At present you use all the available commands to create a single target position and use that to direct your motion (or possibly move towards all target positions simultaneously).
Instead you want a "hopper" of commands that survive beyond a specific game loop and a new command is only fetched after the current one is completed. New commands go in the top and out the bottom to be excecuted.
This would most likely look something like this
public class Player {
//holding commands as strings is a little bug prone, consider creating a custom class or enum
ArrayList<String> commandsHopper=new ArrayList<String>();
//replace with some sort of Vector2i as improvement
double[] targetCoOrdinates=new double[2];
public void addCommand(String command){
commandsHopper.add(command); //commands added at the top of arraylist
}
public void update(double timeSlice){
//Called once, every game loop
if (isAtTarget()){
getNextTarget();
}
moveTowardsTarget(timeSlice);
}
public void getNextTarget(){
if (commandsHopper.isEmpty()==false){
//commands used from bottom of the arraylist
targetCoOrdinates=determineTargetFromCommand(commandsHopper.get(0));
commandsHopper.remove(0); //inefficient with arraylist, consider other collections
}
}
}

Related

How would I move a blank space in a 2d array?

I'm working on a Slider puzzle game and I'm not sure how I would go about moving a "blank" around the array. The puzzle would something like this but randomized. Each method has a prerequisite indicating if it can move a certain direction or not.
- 2 3
4 5 6
7 8 9
// Modifies the puzzle by moving the blank up
// pre: canMoveUp()
public void up() {
}
// Modifies the puzzle by moving the blank down
// pre: canMoveDown()
public void down() {
}
// Modifies the puzzle by moving the blank left
// pre: canMoveLeft()
public void left() {
}
// Modifies the puzzle by moving the blank right
// pre: canMoveRight()
public void right() {
}
Here is an example of how you could implement right(), the rest of the methods would follow very similarly. I am assuming, as your comments imply, that the legality of the move has already been verified.
/*
represent the board in a 2-dimensional array with the following coordinate system
x --->
y
|
\/
*/
int x, y = 0; // keeping track of the blank position
int[][] board = ... // initialize the board as needed (sequentially? randomly?), assume -1 represents the blank space
public void right() { // move the blank in the positive x direction
// get the value currently in the position that the blank must move to, as it will need to be swapped
int tmp = board[x + 1][y];
board[x + 1][y] = -1; // move the blank here
board[x][y] = tmp; // complete the swap
x = x + 1; // the new x position of the blank needs to be updated
}

ArrayList throwing error: "Concurrent Modification Exception" from code in different class

I am aware that this is a frequently asked question, but I am stuck on how to solve it with my code.
I have a button on my GUI that allows me to add extra "turtles" to the graphics window, this adds a turtle to an arraylist which is showing flocking behaviour, from a gameloop structure. How can i make it so i can add as many turtles as i wish without this error being shown?
The game loop is as follows:
private void gameLoop()
{
while(true) //The order in which the turtles move, and when which algorithm is executed
{
for (int i = 0; i < turtles.size(); i++) //for each turtle, perform the set algorithm
{
(turtles.get(i)).unDrawTurtle();
(turtles.get(i)).update(1000);
hello.setText("X: " + (turtles.get(i)).getPositionX() + " Y: " + (turtles.get(i)).getPositionY());
}
for (int i = 0; i < turtles.size(); i++) //for each turtle, perform the set algorithm
{
(turtles.get(i)).cohesian(turtles); //MAKE BOIDS ATTRACT
}
for (int i = 0; i < turtles.size(); i++) //for each turtle, perform the set algorithm
{
(turtles.get(i)).drawTurtle();
}
for (int i = 0; i < turtles.size(); i++) //for each turtle, perform the set algorithm
{
(turtles.get(i)).wrapPosition((turtles.get(i)).getPositionX(), (turtles.get(i)).getPositionY());
}
//Here we are making sure the turtles are on the screen
Utils.pause(deltaTime/2);
}
Here is the code for the button adding turtles to the ArrayList:
addTurtleButton.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
turtles.add(new RandomTurtleB(canvas, 400, 300, currentSpeed, 0));
}
} );
removeTurtleButton.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
turtles.remove(turtles.size() - 1);
canvas.removeMostRecentLine();
canvas.removeMostRecentLine();
canvas.removeMostRecentLine();
canvas.removeMostRecentLine();
}
} );
And in a different class is the cohesion method which is adding turtles/changing the contents of the ArrayList:
public void cohesian(ArrayList<DynamicTurtle> turtles)
{
double flockingDistanceLimit = 50;
double numberOfFlockers = 0;
double combinedX = 0;
double combinedY = 0;
double averageCombinedX;
double averageCombinedY;
//ouble moveToFlock;
//double turnToFlock;
double distanceToPotentialFlock;
for (DynamicTurtle t : turtles) //SCAN FOR ALL TURTLES
{
if(this.getPositionX() != t.getPositionX() && this.getPositionY() != t.getPositionY()) //MAKE SURE TURTLE ISNT SCANNING ITS SELF
{
distanceToPotentialFlock = Math.sqrt(Math.pow((this.getPositionX()-t.getPositionX()),2 ) + Math.pow((this.getPositionY()-this.getPositionY()),2)); //FIND DISTANCE TO TURTLE
System.out.println("distanceToPotentialFlock: " + distanceToPotentialFlock); //PRINT TO SCREEN HOW FAR AWAY THE TURTLE IS
if(distanceToPotentialFlock < flockingDistanceLimit) //MAKE SURE THE FOUND TURTLE IS WITHIN RANGE
{
combinedX = combinedX + t.getPositionX(); //FIND SUMMATION OF X POSITIONS
combinedY = combinedY + t.getPositionY(); //FIND SUMMATION OF Y POSITIONS
numberOfFlockers++; //AS A FLOCKER HAS BEEN FOUND INCREMENT THE NUMBER OF FLOCKERS
System.out.println("distanceToPotentialFlock: " + distanceToPotentialFlock);
System.out.println("numberOfFlockers: " + numberOfFlockers);
if(numberOfFlockers > 0)
{
averageCombinedX = (combinedX / numberOfFlockers); //FIND AVERAGE X POSITION
averageCombinedY = (combinedY / numberOfFlockers); //FIND AVERAGE Y POSITION
System.out.println("XFLOCK: " + averageCombinedX + "YFLOCK: " + averageCombinedY);
double angleRad = Math.atan2(averageCombinedY, averageCombinedX);
double angleDeg = Math.toDegrees(angleRad);
// place in 0,360 range
if(angleDeg < 0)
{
angleDeg = 360 - (-angleDeg);
}
this.turn(angleDeg);
this.move(10);
}
}
}
}
I would greatly appreciate any assisance in helping me solving this problem. Regards, James.
You get a concurrent modification exception since you are adding or removing to the main turtles list each time a button is pressed. You should take some time to read Event Dispatch Threads in Java.
Basically, you are actually dealing with a multi-threading application since the click event of the button happens to execute on a different thread and would be modifying a shared variable - the turtles list which currently is not a thread-safe data structure.
Refer the SO query for some context. So one solution here would be to use a thread-safe data structure like CopyOnWriteArrayList.
Would this be slow? My guess would be no - since in your application a lot of time is spent in iterating over the turtles list compared to adding or removing them. This SO query gives a good description of the performance for CopyOnWriteArrayList
Hope this gives you a head start to solve your problem.

comparing and creating Point 2D arrays

So i am still trying to get this to work... I need it to tell me with the users position matches the position of one of the walls in the array.
I output all the coordinates into the console and everything looks right except that when they equal it doesn't work. (this has worked before... it seems if i don't create the walls in the loop it will work but once i declare too many walls it seems to quit working(not exactly sure but i set the map without the loop and it didn't work consistently i couldn't figure out a reason..
The GameObject(user).position is Point2D and `setPosition set the posiion,
public class Map {
public ArrayList<Wall> theseWalls = new ArrayList<Wall>();
private boolean isSomethingThere;
public Boolean somethingIsThere(GameObject user){
for(int i = 0; i < theseWalls.size(); i++){
GameObject a = (Wall) theseWalls.get(i);
if( user.returnPosition().equals(a.returnPosition())){
isSomethingThere= true;
} else {
isSomethingThere= false;
}
}
return isSomethingThere;
}
}
so that checks if they hit a wall
and this makes the walls
public void makeWallWE(double starty, double endy, double x ){
double length = endy - starty;
for(int i = 1; i<=(int)length;i++){
Wall Wallie= new Wall();
Wallie.setPosition(x,starty+i);
Wallie.showPosition();
theseWalls.add(Wallie);
}
}
You have:
public Boolean somethingIsThere(GameObject user){
for(int i = 0; i < theseWalls.size(); i++){
GameObject a = (Wall) theseWalls.get(i);
if( user.returnPosition().equals(a.returnPosition())){
isSomethingThere= true;
} else {
isSomethingThere= false;
}
}
return isSomethingThere;
}
Even if the user's position matches one of the walls, you continue checking through the rest of the walls and end up setting isSomethingThere to false. The only time this works is if the last wall in theseWalls is the one that matches.
You'll want to break out of that loop as soon as you find a wall that matches, to avoid resetting isSomethingThere to false when you check walls later in the list that don't match.

Use array to decide who is active player (turn based guessing game)

I am using a method (as shown below) that allows me to input the amount of players along with a name for each player. Is there a way for me to use this array to decide who is the active player? (turn based guessing game). If you could just point me in the right direction.
public class Program {
String[] playerList;
int playersAmount = 0;
public void inputPlayers() {
playersAmount = Input.readInt();
playerList= new String[playersAmount];
for (int g = 0; g < playersAmount; g++) {
String namePlayer = "player " + (g+1);
playerList [g] = namePlayer;
}
}
}
You should look over the question I had about changing the player number. I think this exactly what you are looking for (or something similar): Java: Changing Player Number
Essentially I used a boolean array to keep track of who is still playing where the array index corresponds to the player number a[0] = Player 0, a[1] = Player 1, etc. If a player gets eliminated mark the corresponding index with false: a[i] = false; You can then use the following method (taken from my question) to switch the player number to the next player still playing:
public static int switchPlayer(int currentPlayer, boolean[] playerList) {
// if the current player + 1 = length (size) of array,
// start back at the beginning and find the first player still playing
if(currentPlayer + 1 == playerList.length) {
for(int i = 0; i < playerList.length; i++) {
if(playerList[i] == true) { // if player is still in the game
currentPlayer = i; // currentPlayer = current index of array
break;
}
}
}
// otherwise the current player number + 1 is not at the end of the array
// i.e. it is less than the length (size) of the array, so find the next player
// still playing
else {
for(int i = (currentPlayer+1); i < playerList.length; i++) {
if(playerList[i] == true) {
currentPlayer = i;
break;
}
}
}
return currentPlayer;
}
Let me know if you have any questions about my code, etc.
You have two different options in my opinion.
create a Player object with instance variables as his name and a boolean that states whether or not he is active.
You can create a boolean array that is sync with the player array that states wether or not the player is active.
ex for 2
boolean[] activeStatus= new boolean[1];
String[] players = new String[1];
activeStatus[0]=true;
players[0]="Joe Smith";
Well, to represent the current player you can use a int
int curplayer = 0;
Every time their round is done you can add one to get the index of the next player.
curplayer++;
As for it returning to the first player after the last player, I suggest you look into the % (modulo) operator.
Keep track of the turn number using an instance variable:
private int turn;
Increment it every turn:
turn++;
The index of the player whose turn it is can be calculated by using the remainder of dividing the turn by the number of players:
int playerIndex = turn % playersAmount;
I leave it to you to work these parts into your code.
My java is a bit rusty, but something like the following should work.
i = 0
while (playing == True)
{
player = playerList[i]
i = (i + 1) % playerList.length
[Do something]
}

Moving an object to another on a random path

I have a program which creates multiple randomly placed objects(balls) at the beginning, now im trying to move the player ball towards the closest object automatically until their centres are the same. I have determined the distance of the closest object stored in an array called distance with index of 'closest', and set the speed as variable delta initialised somewhere else, how do i get the direction right? Right now
It moves just diagonally but not towards the closest ball
coordinatex[closest] and coordinatey[closest] are the x and y coordinates of the closest object.
playerObject.getX and playerObjectgetY gives me the coordinates of the player onject
public void move(int delta) {
for(int i=0; i<distance[closest]; i++) {
if (x<coordinatex[closest] && y<coordinatey[closest]) {
playerObject.setX(playerObject.getX() + 0.1*delta);
playerObject.setY(playerObject.getY() + 0.1*delta);
} else if(x>coordinatex[closest] && y>coordinatey[closest]) {
playerObject.setX(playerObject.getX() - 0.1*delta);
playerObject.setY(playerObject.getY() - 0.1*delta);
} else if(x>coordinatex[closest] && y<coordinatey[closest]) {
playerObject.setX(playerObject.getX() - 0.1*delta);
playerObject.setY(playerObject.getY() + 0.1*delta);
} else if (x<coordinatex[closest] && y>coordinatey[closest]) {
playerObject.setX(playerObject.getX() + 0.1*delta);
playerObject.setY(playerObject.getY() - 0.1*delta);
}
}
}
Something very similar to this:
angle=atan2(ClosestBally-player_y,closestBallx-player_x);
dxperframe = cos(angle);
dyperframe = sin(-angle);
I see your handlers for the four semi-cardinal (diagonal) directions, but not the four cardinal directions. In this game, for example, enemies approach the player in a step-wise manner using the move(int row, int col) method, shown here, from any of eight directions.

Categories

Resources