libgdx-Actions create stuttering - java

I try to improve the movement of my figures but i dont find the real reason why they stutter a bit. I am moving them with an SequenceAction containing an MoveToAction and an RunnableAction that does reset the moveDone flag so there can be started a new move.
The game itself is gridbased so if a move is done the squence starts a move to the next grid depending on the direction. So here is how it looks like:
note that this is inside of the Act of the figure
....//some more here
if (checkNextMove(Status.LEFT)) //check if the position is valid
{
status = Status.LEFT; //change enum status
move(Status.LEFT); // calls the move
screen.map.mapArray[(int) mapPos.x][(int) mapPos.y] = Config.EMPTYPOSITION;
screen.map.mapArray[(int) (mapPos.x - 1)][(int) mapPos.y] = Config.CHARSTATE;
mapPos.x--;
moveDone = false;
}
//... same for the up down right and so on.
//at the end of this checking the updating of the actor:
// methode from the absctract to change sprites
updateSprite(delta);
super.act(delta); // so the actions work
//end of act
And here is the move Method that does add the Actions
protected void move(Status direction)
{
// delete all old actions if there are some left.
clearActions();
moveAction.setDuration(speed);
//restart all actions to they can used again
sequence.restart();
switch (direction)
{
case LEFT:
moveAction.setPosition(getX() - Config.TILE_SIZE, getY());
addAction(sequence);
break;
case RIGHT:
moveAction.setPosition(getX() + Config.TILE_SIZE, getY());
addAction(sequence);
break;
case UP:
moveAction.setPosition(getX(), getY() + Config.TILE_SIZE);
addAction(sequence);
break;
case DOWN:
moveAction.setPosition(getX(), getY() - Config.TILE_SIZE);
addAction(sequence);
break;
default:
break;
}
}
The figures dont really move smothy.
Anyone does see a misstake or isnt it possible to let them move smothy like this?
It always stutter a bit if a new move is started. So i think this might not work good. Is there a differnt approach to move them exactly from one Grid to an nother? (Tried it myself with movementspeed * delta time but this does not work exactly and i struggeled around and used the Actionmodel)
it seems to make troubles with the one Frame where it does not move for example.
Here is an mp4 Video of the stuttering:
stuttering.mp4
just to mention, the camera movement is just fine. it's smothy but the figure stutters as you can see i hope

If you use your moveAction each move, you should call moveAction.restart() to reset the counter inside it:
// delete all old actions if there are some left.
clearActions();
sequence.reset(); // clear sequence
// add movementspeed. Note it can change!
moveAction.restart();
moveAction.setDuration(speed);
UPDATE:
Now issue occurs, because you call restart of SequenceAction after clearActions(). If your clearActions() removes all actions from SequenceAction then restart will be called for empty SequenceAction. So, do this instead:
//restart all actions to they can used again
sequence.restart();
// delete all old actions if there are some left.
clearActions();
moveAction.setDuration(speed);

Okay so i solved it myself. It has nothing todo with changing sequences around. It has something todo with the updatefrequency of the act() of the figures. The MoveToAction interpolates between the 2 points given by time. So if the last update, updates the MoveToAction by "to much time" it would need to go over the 100% of the action. So it would move to far but the action does not do this it set the final position and thats what it should do. Thats why it does not look fluent.
So how to solve this issue?
By decreasing the updatetime the "to far movement" decreases too because the steplength is getting smaller. So i need to increase the updatespeed above the 60fps. Luckily i got an thread for my updating of the figures and positions and so on. GameLogicThread. This ran on 60fps too. So i solved the stuttering by increasing it's frequence. up to around 210fps at the moment so the "overstep" is minimal. You can't even notice it.
To Show how my thread works:
public class GameLogicThread extends Thread
{
private GameScreen m_screen;
private boolean m_runing;
private long m_timeBegin;
private long m_timeDiff;
private long m_sleepTime;
private final static float FRAMERATE = 210f;
public GameLogicThread(GameScreen screen)
{
m_screen = screen;
setName("GameLogic");
}
#Override
public void run()
{
m_runing = true;
Logger.log("Started");
while (m_runing)
{
m_timeBegin = TimeUtils.millis();
// hanlde events
m_screen.m_main.handler.processEvents();
synchronized (m_screen.figureStage)
{
// now figures
if (m_screen.m_status == GameStatus.GAME)
{
m_screen.character.myAct(1f / GameLogicThread.FRAMERATE);// and here it is ;)
m_screen.figureStage.act(1f / GameLogicThread.FRAMERATE);
}
}
m_timeDiff = TimeUtils.millis() - m_timeBegin;
m_sleepTime = (long) (1f / GameLogicThread.FRAMERATE * 1000f - m_timeDiff);
if (m_sleepTime > 0)
{
try
{
Thread.sleep(m_sleepTime);
}
catch (InterruptedException e)
{
Logger.error("Couldn't sleep " + e.getStackTrace());
}
}
else
{
Logger.error("we are to slow! " + m_sleepTime);
}
}
}
public void stopThread()
{
m_runing = false;
boolean retry = true;
while (retry)
{
try
{
this.join();
retry = false;
}
catch (Exception e)
{
Logger.error(e.getMessage());
}
}
}
}

Related

Why is it adding more than 1 to my speed control?

import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
public class Turtle extends Actor
{
/**
* Act - do whatever the Turtle wants to do. This method is called whenever
* the 'Act' or 'Run' button gets pressed in the environment.
*/
int laufmenge;
public void act()
{
if(Greenfoot.isKeyDown("left")){
move(-speed);
}
if(Greenfoot.isKeyDown("right")){
move(speed);
}
if(Greenfoot.isKeyDown("up")){
setLocation(getX() ,getY() -speed);
}
if(Greenfoot.isKeyDown("down")){
setLocation(getX() ,getY() +speed);
}
if(Greenfoot.isKeyDown("x")){
if(speed<10) speed++;
}
if(Greenfoot.isKeyDown("y")){
if(speed>0) speed--;
}
System.out.println(speed);
}
private int speed=1;
}
This is code from Greenfoot because i am currently trying to learn coding. I cant understand why when i execute the programm and control the speed he is changing the value by more than one. I guess it will be an easy question.
And is it possible to put the increase and decrease of the speed on one button with two letters like the >< key? i didnt work in my case.
This happens because act() is called in rapid succession. Even if you just press and release x, act() will have run several times while the key is down, and therefore updated the speed several times.
To avoid that, you can track whether or not you've adjusted the speed since the first time you noticed that the button was pressed.
For example, you can have a private bool adjustedSpeed = false; in your class, and then do:
if(Greenfoot.isKeyDown("x")){
if(speed<10 && !adjustedSpeed) speed++;
adjustedSpeed = true;
} else if(Greenfoot.isKeyDown("y")){
if(speed>0 && !adjustedSpeed) speed--;
adjustedSpeed = true;
} else {
adjustedSpeed = false
}

How to activate a function within an loop to continue after exiting loop

i'm sure I can figure this out on my own but I feel like the way i'm writing it is already too expensive and coupled.
I am writing a simulator with a security robot and a intruder, I have a collision function, where in the 3rd if statement it checks if an intruder (rectangle of width 11) collides with an surveillance camera (arc) and if that happens then I want to activate my function for the security robot to chase the intruder.
<-- Important note: the checkShapeIntersection function is inside a timeLine event so its running constantly -->
private boolean checkShapeIntersection(Shape block) {
//Name to check for intruder and surveillance collision
String Surveillance = "Arc";
boolean collisionDetected = false;
for (Shape static_bloc : nodes) {
if (static_bloc != block) {
Shape intersect = Shape.intersect(block, static_bloc);
if (intersect.getBoundsInLocal().getWidth() != -1) {
collisionDetected = true;
//Checks of intruder collides with an arc (surveillance), the 11th width is only for intruder rectangles
if ( Surveillance.equals(block.getClass().getSimpleName()) && static_bloc.getBoundsInLocal().getWidth() == 11) {
//Activate Chase function
testRobot.chaseIntruder(static_bloc);
detected = true;
}
}
}
}
if (collisionDetected) {
block.setFill(Color.BLUE);
} else {
block.setFill(Color.RED);
}
return detected;
}
And inside my Security Robot Class
public void chaseIntruder(Shape intruder) {
destinationsList.add(new Vector2D(intruder.getLayoutBounds().getMinX(),intruder.getLayoutBounds().getMinY()));
this.updatePosition();
}
You probably want to use multi-threading here, in Java you can implement Runnable or Thread to achieve wanted functionality.
Here are some links with more info:
In a simple to understand explanation, what is Runnable in Java?
https://docs.oracle.com/javase/7/docs/api/java/lang/Runnable.html
https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html
https://docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html
Hope it helps.

Java - Loop gets executed, but header doesnt fit condition

This function should check if the explosion hit a box and should be canceled on the first box it hits.
For example bsp.getBomb().getStrength() is currently 2, when a box is hit i=3, but the loop is executed one more time even if the condition isn't met, why is that?
public void detectBomb(BombSpritePair bsp) {
for(int i = 0; i <= bsp.getBomb().getStrength(); i++) {
if(bd.detect(bsp.getBomb().getX(), bsp.getBomb().getY()+i)) {
Sprite sprite = new Sprite(new Texture("gras.png"));
sprite.setPosition(bsp.getBomb().getX()*16, (bsp.getBomb().getY()+i)*16);
// i = bsp.getBomb().getStrength()+1;
sprites.add(sprite);
System.out.println("RIP"+i);
System.out.println(bsp.getBomb().getStrength());
break;
}
}
}
Try adding break to the loop:
public void detectBomb(BombSpritePair bsp) {
for(int i = 0; i <= bsp.getBomb().getStrength(); i++) {
if(bd.detect(bsp.getBomb().getX(), bsp.getBomb().getY() + i)) {
Sprite sprite = new Sprite(new Texture("gras.png"));
sprite.setPosition(bsp.getBomb().getX()*16, (bsp.getBomb().getY()+i)*16);
sprites.add(sprite);
System.out.println("RIP"+i);
System.out.println(bsp.getBomb().getStrength());
break;
}
}
}
You may be seeing duplicate print statements if you are calling the detectBomb method multiple times. Putting a breakpoint or print statement at the beginning of this method will help determine what the problem is.
Another thing to keep in mind is that you are creating a new Texture for the Sprite every time the method get executed - it would be wise to only instantiate the Texture once and share it with all subsequent Sprite instances that require it.

JLabel graphic changes at wrong time

I have a slot machine program with some graphics, and the graphic is supposed to change when you pull the lever and for some reason it changes the graphic after it goes through all of the other code first. Have a look:
Declare images:
static ImageIcon jImage = new ImageIcon("C:\\Users\\Harry\\Desktop\\jackpotLeverNotPulled.png");
static ImageIcon jackpot1 = new ImageIcon("C:\\Users\\Harry\\Desktop\\jackpotimage1.png");
static ImageIcon jackpotPulled = new ImageIcon("C:\\Users\\Harry\\Desktop\\jackpotLeverPulled.png");
Now I add to panel:
static JLabel jlb = new JLabel(jImage);
Now I want the image to change when a certain area is clicked on my panel but the main jackpot code runs first and then the image changes:
public void mousePressed(MouseEvent e) {
// Returns the X coordinate of where the mouse was click on the panel
System.out.println("X Coordinate: " + e.getX() );
// Returns the Y coordinate of where the mouse was click on the panel
System.out.println("Y Coordinate: " + e.getY() );
System.out.println();
Scanner ansr = new Scanner(System.in);
String yesno;
int random = (int)(Math.random() * 21 );
int percentCheck = (int)(Math.random() * 10 );
if (e.getX ()>975 && e.getX ()<1159 && e.getY ()>82 && e.getY ()<218){
jlb.setIcon(jackpotPulled);
if (cashMoneyz<1) {
System.out.println("Insufficient funds");
image1.setIcon(jackpot1);
} else {
System.out.println("One dollar has been removed from you slot machine balance");
cashMoneyz--;
try {
System.out.println("Spinning...");
Thread.sleep(1000);
System.out.println("Spinning...");
Thread.sleep(1000);
System.out.println("SPINNINGGGGG...OMG SOOO INTENSE");
Thread.sleep(1000);
} catch (InterruptedException ie)
{
}
}
System.out.println("You have this much money (in dollars) left in your slot machine balance: " + cashMoneyz);
System.out.println("");
System.out.println("----------------------------------------------------------------------------------");
}
It does the if statements and try catches and only changes the graphic to jackpotPulled at the end of everything.
Thanks in advance :)
There are basically 2 problems in your code:
1)
A call to label.setImage() won't update immediately, as this is true for everything in AWT and Swing. Any time a repaint request is fired, it is simply added to a repaint queue, that will wait patiently for all other tasks done in the EDT (Event Dispatching Thread) to finish. But since you do other things in the mousePressed(), they will run first. A simple solution for this would be to do the computing in mouseReleased(). But a bigger problem exists.
2)
What you are currently doing is "starving" the EDT - a bad programming practice - as all screen related invocations must be executed immediately. Sleeping the EDT won't allow any repaints to take place while running. This is true for any long running tasks as well.
Its solution is to run the non-painting calls in a different thread:
private volatile boolean isComputing = false;
public void mousePressed(MouseEvent evt) {
if(isComputing)
return;
isComputing = true;
// .
// .
// .
// change icon here, or any
// other swing related change.
// .
// .
// run game
new Thread(){
public void run(){
// all non-swing computations
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// change back icons,
// and some other swing updates
}
}
isComputing = false;
}
}.start();
}
An event handler (mousePressed) souldn't take a long time to complete, there should be no sleeps in it. As long as it runs (or sleeps), nothing else can happen. The runtime is waiting for the handler to return and displays the image after that. I would move most of the code to a function called by a timer, and use a state variable to keep track of how intensely the wheels are spinning.

small lags when starting the next moveTo action

[UPDATE] i changed the order a bit so i call the super.act(delta) at the end of the method and it seems to help a bit! But not that sure about it yet.
I got a square system for my map. So its an 2D array and i i make one move the figure does move from one square to the next. While that it's not possible to "stop" the figure between 2 squares. When my characters made one move i check if the Touchpad is touched and if yes i start the next move. While that it seems to lag sometimes and i dont know why!? I really hope you may find the "lag". Here is how i calculate the next move inside the act()of my Actor Character:
#Override
public void act(float delta) {
super.act(delta); // so the actions work
if (moveDone) {
if (screen.gameHud.pad.isTouched()) {
// check in which direction is the touchcontroller
if (screen.gameHud.pad.getKnobPercentX() < 0
&& Math.abs(screen.gameHud.pad.getKnobPercentY()) < Math
.abs(screen.gameHud.pad.getKnobPercentX())) {
// checkt if the |x|>|y|
if (checkNextMove(Status.LEFT)) {
this.status = Status.LEFT;
move(Status.LEFT);
this.screen.map.mapArray[(int) (this.mapPos.x)][(int) this.mapPos.y] = Config.EMPTYPOSITION;
this.screen.map.mapArray[(int) (this.mapPos.x - 1)][(int) this.mapPos.y] = Config.CHARSTATE;
this.mapPos.x--;
moveDone = false;
}
} else if //.... rest is the same just with other directions
else{ //if touchpad isnt touched!
setIdle();
}
updateSprite(delta); //just change the textureRegion if its time for that
} //methode end
Okay so you need some more informations i am sure. Checkmoves like this:
case LEFT:
if (this.mapPos.x - 1 >= 0)
if (this.screen.map.mapArray[(int) (this.mapPos.x - 1)][(int) this.mapPos.y] == Config.EMPTYPOSITION)
return true;
break; //same for all other just direction changin
And the last you need to know is the move(_) i guess. It does add an moveTo Action to my figures.
public void move(Status direction) {
switch (direction) {
case LEFT:
this.addAction(Actions.sequence(
Actions.moveTo((getX() - Config.BLOCK_SIZE), getY(), speed),
moveDoneAction));
break;
moveDoneAction is a simple RunnableAction that set the boolean moveDone to true if its done moving.
i really hope you can help. If you need some more informations please let me know as comment!
There are better tools than StackOverflow for optimizing Android code. Use a profiler and see what is actually happening. Specifically, the traceview profiler: how to use traceview in eclipse for android development? (If you're not using Eclipse, you can use traceview directly via the ADT.)

Categories

Resources