I have 2 clients connected to a server, they send new coordinates or spawn new circles and the server updates the position of the circles or creates new ones and draw them. I use a timertask with a delay of 5 seconds and a 5 seconds interval to spawn new circles.
I keep getting IndexOutOfBoundsException at random indexes every time i run the application when i setTranslateX.
private void updateSimulation(ArrayList<String> cl) {
if(cl == translatedCoorsMessage) {
Platform.runLater(() -> {
int x= 1;
for(Circle circle : circlesOnCorridorOfClient) {
circle.setTranslateX(((Double.parseDouble(cl.get(x))) - 20.0)/1000);
x=x+2;
}
circlesOnCorridorOfClient.addAll(newCirclesToAddOnCorridor);
newCirclesToAddOnCorridor.clear();
});
}
else {
Platform.runLater(() -> {
int x= 1;
for(Circle circle : circlesOnCorridorOfClient1) {
circle.setTranslateX(((Double.parseDouble(cl.get(x))) - 967.0)/1000);
x=x+2;
}
circlesOnCorridorOfClient1.addAll(newCirclesToAddOnCorridor1);
newCirclesToAddOnCorridor1.clear();
});
}
}
This error can happen after the second circle spawns or third or the 5th, etc. I set my x = 1 because the first element in the ArrayList i pass to this method is just a small String to know what i will do with the ArrayList. In this case, update. the second is X coordinate and third is Y.
It feels like the foreach loop runs one extra time some times after i add a new circle. I only add new circles after the loop and i do it through another arraylist.
Any tips will be apreciated. thanks for your time.
Im not sure but i think that the problem is that everything i did in Platform.runLater happens in another thread (Application Thread). So my server was updating and adding new circles(this circles are added in a separate ArrayList to avoid ConcurrentModificationException) then i add my new circles to the main ArrayList after i update every circle position. So that was the problem, for a moment i had 1 extra circles.
I "fixed" this problems by adding 2 volatile integers in my Server. i used those integers to check if im done doing everything in Platform.runLater. the server stays in a while loop that does nothing, just waiting until the Platform.runLater part is done and changes the value of this integers so that Server Thread can exit this while loop and continue.
I dont get the IndexOutOfBoundsException any more but the "animation" is really slow.
private void updateSimulation(ArrayList<String> cl) {
if(cl == translatedCoorsMessage) {
Platform.runLater(() -> {
int x= 1;
for(Circle circle : circlesOnCorridorOfClient) {
circle.setTranslateX(((Double.parseDouble(cl.get(x))) - 20.0)/1000);
x=x+2;
}
circlesOnCorridorOfClient.addAll(newCirclesToAddOnCorridor);
newCirclesToAddOnCorridor.clear();
testtest = 1;
});
while(testtest == 0){
//waiting
}
testtest = 0;
}
else {
Platform.runLater(() -> {
int x= 1;
for(Circle circle : circlesOnCorridorOfClient1) {
circle.setTranslateX(((Double.parseDouble(cl.get(x))) - 967.0)/1000);
x=x+2;
}
circlesOnCorridorOfClient1.addAll(newCirclesToAddOnCorridor1);
newCirclesToAddOnCorridor1.clear();
testtest1 = 1;
});
while(testtest1 == 0){
//waiting
}
testtest1=0;
}
}
is an ugly solution.
Related
I am trying to create a snake game where i use arrow keys or WASD to move the snake.
Initially the snake is slow and moves at 2 fps speed (like the classic snake game), i want the snake to move faster when i am holding down one of the keys and set it to original speed when i release it.
i tried changing the movement rate inside onKeyPressed like so:
scene.setOnKeyPressed(event -> {input = event.getCode().toString();
for (String acceptedKey : acceptedKeys) {
if (event.getCode().toString().contains(acceptedKey)) {
movement.setRate(4);
break;
}
}
});
Then changing it to normal rate when i released it:
scene.setOnKeyReleased(event -> movement.setRate(1));
*movement is a Timeline which starts since the beginning of game till stopped or death of snake.
The code works as i intended But every time i hit a key it speeds up for a cycle and then slows down.
I want the speed to change only when i hold a key for a certain duration (say 400 milliseconds) so is there a way i can put an if statement that checks duration of onKeypressed()?
Instead of handling this complicated logic in the listener, set a boolean flag that is flipped on when a key is pressed.
scene.setOnKeyPressed(event -> {input = event.getCode().toString();
for (String acceptedKey : acceptedKeys) {
if (event.getCode().toString().contains(acceptedKey)) {
acceptedKeyBeingPressed = true;
break;
}
}
});
scene.setOnKeyReleased(event -> acceptedKeyBeingPressed = false);
Then keep track of time with some sort of numTicksHeld variable when the flag acceptedKeyPressed is true.
Check if acceptedKeyPressed is true on each tick. Reset the numTicksHeld variable to 0 when acceptedKeyPressed is false. If it is true, increment by one. If numTicksHeld is above some threshold, movement.setRate(4).
I don't know what the tick/update method looks like in your framework but it would be something like:
public void tick() {
if(acceptedKeyPressed) {
numTicksHeld++;
if(numTicksHeld > KEY_HELD_THRESHOLD)
movement.setRate(4)
} else {
numTicksHeld = 0;
movement.setRate(1)
}
}
I have had a persistent issue of my snake game running slowly as the snake gets larger. I have narrowed it down to this block of code that is causing the problems:
for(int i = 0 ; i < snake.size(); i++) {
if(xCoor == snake.get(i).getxCoor() && yCoor == snake.get(i).getyCoor()) {
if(i != snake.size() - 1) {
stop();
tries = 1;
}
}
}
This is the collision detection of the snake's head hitting the snake's body. I haven't been able to think of another way to optimize this besides removing it, which removes the core of the game. I think the issue that this runs each tick. I could change off from using ticks, but I have no idea how to start doing that.
EDIT: Here is how I have my game timing set up:
public void tick() {
if(snake.size() == 0) {
b = new BodyPart(xCoor, yCoor, 10);
snake.add(b);
}
ticks++;
if(ticks > 750000) {
}
}
EDIT2: Thread.sleep(60) worked wonders! My stop() method just doesn't work anymore, but all it really did was set running to false, so I just did that manually on anything that ended the game.
You could try the following approaches:
1.You could create a Map or Set of (x,y) co-ordinates which are already occupied and check against it. This would be updated much less frequently than access.
2.You could create a two-dimensional array of boolean for each board position. Checking would be very fast. Updating would take some time. It depends on the relative frequencies on which the two occur.
float x = 0;
void setup() {
size(200,200);
frameRate(60);
background(255);
}
int v = (int)random(0,width);
int b = (int)random(0,height);
void draw() {
drawCar(v,b,50,0);
secondDelay(5);
v = (int)random(0,width);
b = (int)random(0,height);
}
void drawCar(int x, int y, int thesize, int col) {
int offset = thesize/4;
//draw main car body
rectMode (CENTER);
stroke(200);
fill(col);
rect(x,y,thesize, thesize/2);
//draw wheel relative to car body center
fill(0);
rect(x-offset,y-offset,offset,offset/2);
rect(x+offset,y-offset,offset,offset/2);
rect(x+offset,y+offset,offset,offset/2);
rect(x-offset,y+offset,offset,offset/2);
}
void secondDelay(int aSecond){
int aS;
aS = aSecond * 60;
while(aS > 0) {
aS--;
}
}
what I'm trying to do is make the secondDelay() function work as a way of delaying the draw function (which is a loop that updates every frame). also the frameRate itself is 60, so 60 frames per second is what draw() is running at.
This is done by giving the amount of seconds I want as the argument of secondDelay(amountofseconds). then inside that secondDelay() function
it multiplies the amount of seconds by the amount of frames per second which is 60. Now i have the amount of frames that i need to wait which i put in a variable called aS. What i do then inside the secondDelay() function, is make a while loop that runs everytime it sees that variable aS is bigger than 0. Then i just subtract 1 from aS everytime it loops until it is no longer bigger than 0. That's when the amount of seconds u wanted it to delay has been delayed and then it does the whole draw() loop again.
That's how I explain the code that i made, but it doesn't work. Instead it is just acting like secondDelay(5); doesn't exist so it just creates new cars every frame.
How would i go about fixing this?
For what you want to do, you have to count the frames. It the number of frames exceeds a number, which is equal the delay time span, then you have to draw a new car.
You don't need a function that delays, waits or sleeps for a while, but you need a function that tells and signals you that a period of time has passed.
Create a global frame counter (frame_count) and count the frames in the secondDelay function. If the counter exceeds 60*aSecond then the function reset the counter to 0. If the counter is 0, then this is signaled by returning the boolean value true.
int frame_count = 0;
boolean secondDelay(int aSecond){
boolean signal = frame_count==0;
if ( frame_count >= 60*aSecond ) {
frame_count = 0;
} else {
frame_count ++;
}
return signal;
}
Every time when the secondDelay returns true and so gives you the signal, then you have to draw a new car in the draw function:
void draw() {
if ( secondDelay(5) ) {
drawCar(v,b,50,0);
v = (int)random(0,width);
b = (int)random(0,height);
}
}
I'm developing a game with JavaME and I need to count the number of collisions in my game.
I'm using the collidesWith() method, and I'm doing something like this:
private void checkCollision()
{
if (spBoy.collidesWith(spBall, true)) {
this.collides++;
if (this.collides == 3) {
//here I will show a Game Over image.
}
}
}
As you can see, if the number of collisions is 3, the game is over, but I can't count the number of collisions, because when I increment this.collides, automatically I have 3 collisions in one time.
I'm assuming you're calling checkCollision() inside your main loop. This means it gets called 30-60 times per second.
If the two sprites doesn't move at all during that second, there will be 30-60 collisions - because it's true in each cycle.
What you wanna do is add a timer where your spBoy sprite can't be hurt.
int safeTimer = 0;
int timeSinceLastLoop; // Add this calculation to your loop
private void checkCollision() {
safeTimer-= timeSinceLastLoop;
if (spBoy.collidesWith(spBall, true) && safeTimer<=0) {
this.collides++;
safeTimer=3000; // Wait 3 seconds till vulnerability
if (this.collides == 3) {
//here I will show a Game Over image.
}
}
}
i have a game(like super jumper, this game is a jumping game) that our character has life. after collision with enemies, his life reduce. and i want to after 1 sec , calculate the collisions. i mean in this 1 sec, if my character contact with enemies , nothing happen and he continue his way.
for this , i define a boolean variable in my GameScreen class, name "collision" and another in Wolrd class, name "collBirds". after one contact with enemy collision and collBirds change to true. but i want after 1 sec collistion change to false. i use several things like System.currentTimeMillis() and "for loop",and nothing happen. i'm not so good in java.
this is my condition:
if(World.collBirds == true && collition == false){
life -= 1;
lifeString = "Life : " + life;
World.collBirds = false;
collition = true;
for (??? "need to stay here for 1 sec" ???) {
collition = false;
}
}
In some cases you could also want to use com.badlogic.gdx.utils.Timer
Example usage:
float delay = 1; // seconds
Timer.schedule(new Task(){
#Override
public void run() {
// Do your work
}
}, delay);
When the first collision occurs, set a float timeSinceCollision = 0;
Then each loop, you will need to add the time since last check to the variable, and check if it's more than a second.
timeSinceCollision += deltaTime;
if(timeSinceCollision > 1.0f) {
// do collision stuff
} else {
// ignore the collision
}
If you want to do this in same thread than you can use Thread.sleep(). But in this case your current thread will freeze and if this is single thread game, than your whole game will freeze. If you don't want your game to freeze for 1 second, than you should spawn the thread and in that thread call the sleep and after sleep, change the flag