Zbyt szybka animacja postaci

0

Witam. Czytam książkę Beginning Java 8 Games Development i mam problem z animacją biegu postaci. Animacja jest zbyt szybka i nie wiem co jest przyczyną. Na karcie graficznej intela wszystko działa idealnie natomiast na nvidii animacja bardzo przyspiesza, że wygląda to nienaturalnie. Zauważyłem też że po aktualizacji ubuntu nawet zmiana karty nie pomaga i obecnie nie działa nawet na intelu. Po wyłączeniu metody moveInvincilBagel(iX, vY) animacja biegu działa. Również jak postać dotrze do granicy animacja wraca do normy. Proszę o pomoc. Zamieszczam kod źródłowy postaci, jeśli to konieczne mogę zamieścić resztę kodu źródłowego

  ./*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package invincibagel;

import javafx.scene.image.Image;
import static invincibagel.InvinciBagel.WIDTH;
import static invincibagel.InvinciBagel.HEIGHT;

/**
 *
 * @author arek
 */
public class Bagel extends Hero {

    protected InvinciBagel invinciBagel;
    protected static final double SPRITE_PIXEL_X = 81;
    protected static final double SPRITE_PIXEL_Y = 81;
    protected static final double RIGHT_BOUNDARY = WIDTH / 2 - SPRITE_PIXEL_X / 2;
    protected static final double LEFTBOUNDARY = -(WIDTH / 2 - SPRITE_PIXEL_X / 2);
    protected static final double BOTTOM_BOUNDARY = HEIGHT / 2 - SPRITE_PIXEL_X / 2;
    protected static final double TOP_BOUNDARY = -(HEIGHT / 2 - SPRITE_PIXEL_X / 2);
    boolean animator = false;
    int frameCounter = 0;
    int runningSpeed = 7;

    public Bagel(InvinciBagel iBagel, String SVGdata, double xLocation, double yLocation, Image... spriteCels) {
        super(SVGdata, xLocation, yLocation, spriteCels);
        invinciBagel = iBagel;
    }

    @Override
    public void update() {

        setXYLocation();
        setBoundaries();
        setImageState();
        moveInvincilBagel(iX, vY);

    }

    @Override
    public boolean collide(Actor object) {
        return false;
    }

    private void setXYLocation() {

        if (invinciBagel.isRight()) {
            iX += vX;
        }
        if (invinciBagel.isLeft()) {
            iX -= vX;
        }
        if (invinciBagel.isDown()) {
            iY += vY;
        }
        if (invinciBagel.isUp()) {
            iY -= vY;
        }
    }

    private void setBoundaries() {

        if (iX >= RIGHT_BOUNDARY) {
            iX = RIGHT_BOUNDARY;
        }
        if (iX <= LEFTBOUNDARY) {
            iX = LEFTBOUNDARY;
        }
        if (iY >= BOTTOM_BOUNDARY) {
            iY = BOTTOM_BOUNDARY;
        }
        if (iY <= TOP_BOUNDARY) {
            iY = TOP_BOUNDARY;
        }
    }

    private void setImageState() {

        if (!invinciBagel.isRight() && !invinciBagel.isLeft() && !invinciBagel.isDown() && !invinciBagel.isUp()) {
            spriteFrame.setImage(imageStates.get(0));
            animator = false;
            frameCounter = 0;
        }
        if (invinciBagel.isRight()) {
            spriteFrame.setScaleX(1);
            if (!animator && (!invinciBagel.isUp()) && !invinciBagel.isDown()) {
                spriteFrame.setImage(imageStates.get(1));
                if (frameCounter >= runningSpeed) {
                    animator = true;
                    frameCounter = 0;
                } else {
                    frameCounter++;
                }

            } else if (animator) {
                spriteFrame.setImage(imageStates.get(2));
                if (frameCounter >= runningSpeed) {
                    animator = false;
                    frameCounter = 0;
                } else {
                    frameCounter++;
                }
            }
        }

        if (invinciBagel.isLeft() && (!invinciBagel.isUp()) && !invinciBagel.isDown()) {
            spriteFrame.setScaleX(-1);
            if (!animator) {
                spriteFrame.setImage(imageStates.get(1));
                if (frameCounter >= runningSpeed) {
                    animator = true;
                    frameCounter = 0;
                } else {
                    frameCounter++;
                }
            } else if (animator) {
                spriteFrame.setImage(imageStates.get(2));
                if (frameCounter >= runningSpeed) {
                    animator = false;
                    frameCounter = 0;
                } else {
                    frameCounter++;
                }
            }

        }
        if (invinciBagel.isDown()) {
            spriteFrame.setImage(imageStates.get(6));
        }

        if (invinciBagel.isUp()) {
            spriteFrame.setImage(imageStates.get(4));
        }

    }

    private void moveInvincilBagel(double x, double y) {
        spriteFrame.setTranslateX(x);
        spriteFrame.setTranslateY(y);

    }

}
0

Jeżeli mówiąc o animacji, masz na myśli przesuwanie obiektu po ekranie, to zdecydowanie najlepszą metodą byłoby, aby zamiast dodawać co update jakąś wartość na zasadzie podobnej do tego:

private int x;
private int y;
//...
public void move(int x, int y) {
	this.x += x;
	this.y += y;
}

Oprzeć się na oddzielnym ustalaniu prędkości przesunięcia w pikselach na milisekundach i przesyłaniu ilości milisekund, jaka upłynęła od ostatniego update'a. W takim wypadku prędkość będzie zapewne zapisana w double i będziesz musiał również w double przechować pozycję. Będzie ona zaokrąglana przy rysowaniu do całości, ale gdybyś zostawił int, przy mniejszych prędkościach obiekt stałby w miejscu.

private double x;
private double y;
private double vx;
private double vy;
//...
public void update(long millis) {
	this.x += vx * millis;
	this.y += vy * millis;
}

Przykładowe wywołanie metody update:

long before = System.currentTimeMillis();
while (true) { //pętla główna gry
	long difference = System.currentTimeMillis() - before;
	update(difference);
	before = System.currentTimeMillis();
}

Takie rozwiązanie sprawia, że prędkość przesuwania się obiektu po ekranie powinna być niezależna od częstotliwości odświeżania, uruchamiania metody update i czegokolwiek innego. Jedyne, co może spowolnić/przyspieszyć przesuwanie obiektu, to błędnie działające System.currentTimeMillis(), a to raczej mało prawdopodobne.

0

Dzięki za odpowiedź. Widziałem już przykład, o którym mówisz i wiem że ten sposób działa. Zastanawiałem się tylko od czego zależy różna prędkość poruszania się obiektu po ekranie i dlaczego działa prawidłowo na windowsie a na ubuntu już nie. Skoro klasa animationTimer zawsze generuje 60 fps.

1 użytkowników online, w tym zalogowanych: 0, gości: 1