Понедельник, 18 Ноября 2024, 06:35

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 1 из 1
  • 1
Игровой цикл независимый от размер экрана и фреймрейта
DurianOdourДата: Четверг, 14 Декабря 2017, 23:20 | Сообщение # 1
был не раз
Сейчас нет на сайте
Здравствуйте, нужно сделать очень простую игру для Android, ну очень простую.
Даже в этом случае не могу понять в чем проблема.
Собственно читал статьи на эту тему, сделал все как было описано, несколько раз проверял, но все равно что-то неправильно сделал.

Мой игровой цикл выглядит следующим образом

Код
  public static final int PAUSE_SLEEP_TIME = 10;
        long totalElapsed = 0;
        long previousTime = TimeUtils.getCurrentTimeMillis();
        long dt = 5;
        long accumulator = 0;

        @Override
        public void run() {
            while (mIsRunning) {
                // Pause game
                while (mIsPaused) {
                    try {
                        Thread.sleep(PAUSE_SLEEP_TIME);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                long currentTime = TimeUtils.getCurrentTimeMillis();
                long frameTime = currentTime - previousTime;
                previousTime = currentTime;
                totalElapsed += frameTime;
                accumulator += frameTime;
                while (accumulator >= dt) {
                    processGameInput();
                    updateGameState(totalElapsed, dt);
                    accumulator -= dt;
                }

                drawGame();
                checkIfGameShouldStop(totalElapsed);
            }
            shutdownGracefully();
        }

        private void shutdownGracefully() {
        }


В update game state я просто передвигаю шарик относительно текущих координат с какой-то константной скоростью без ускорения.

Также для того чтобы поддерживать несколько экранов сделал концепцию абстрактного экрана. Идея в том что есть определенный размер экрана, по которому ведутся расчеты, но при отрисовке непосредственно все координаты транслируются в настоящие.

Код
public class GameScreen implements AbstractCoordinatesConverter {
    private static final long DEFAULT_SCREEN_COEFFICIENT = 100;
    private static final long DEFAULT_ABSTRACT_SCREEN_WIDTH = 720;
    private static final long DEFAULT_ABSTRACT_SCREEN_HEIGHT = 1280;
    private static final ScreenSize DEFAULT_ABSTRACT_SCREEN_SIZE = new ScreenSize(DEFAULT_ABSTRACT_SCREEN_WIDTH, DEFAULT_ABSTRACT_SCREEN_HEIGHT);
    private Point2d mReusablePoint = new Point2d();
    private ScreenAspectRatio mScreenAspectRatio;
    private ScreenSize mAbstractScreenSize;
    private ScreenSize mRealScreenSize = new ScreenSize();
    private ScreenAspectCoefficient mScreenAspectCoefficient = new ScreenAspectCoefficient();
    private long mScreenCoefficient = DEFAULT_SCREEN_COEFFICIENT;
    

    public void updateFromCanvasSize(CanvasSize canvasSize) {
        mRealScreenSize.setHeight(canvasSize.getHeight());
        mRealScreenSize.setWidth(canvasSize.getWidth());
        onScreenSizeUpdated();
        Logger.error("ABSTRACT SCREEN SIZE WIDTH : " + mAbstractScreenSize.getWidth() + " HEIGHT " + mAbstractScreenSize.getHeight());
    }

    private void onScreenSizeUpdated() {
        mScreenAspectRatio = ScreenAspectRatio.fromScreenSize(mRealScreenSize);
        mAbstractScreenSize = calculateAbstractScreenSize(mScreenAspectRatio, mScreenCoefficient);
        mScreenAspectCoefficient = ScreenAspectCoefficient.fromScreenSizes(mAbstractScreenSize, mRealScreenSize);
    }

    @Override
    public Point2d convertPointToRealPosition(Point2d point2d) {
        mReusablePoint.x = convertXPointToRealPosition(point2d.x);
        mReusablePoint.y = convertYPointToRealPosition(point2d.y);
        return mReusablePoint;

    }

    @Override
    public float convertXPointToRealPosition(float xAbstract) {
        return xAbstract * mScreenAspectCoefficient.getWidthCoefficient();

    }

    @Override
    public float convertYPointToRealPosition(float yAbstract) {
        return yAbstract * mScreenAspectCoefficient.getHeightCoefficient();
    }

    @Override
    public float convertYRealToAbstract(float yReal) {
        return yReal / mScreenAspectCoefficient.getHeightCoefficient();
    }

    @Override
    public float convertXRealToAbstract(float xReal) {
        return xReal / mScreenAspectCoefficient.getHeightCoefficient();
    }

    public static ScreenSize calculateAbstractScreenSize(ScreenAspectRatio aspectRatio, long coefficient) {
        return DEFAULT_ABSTRACT_SCREEN_SIZE;
        // return new ScreenSize(aspectRatio.getWidthRatio() * coefficient, aspectRatio.getHeightRatio() * coefficient);
    }
}

Но все равно на разных устройствах по разному работает игра. На одних быстрее на одних медленнее. Вот пример видео Video Game Loop

Мне все равно с какой плавностью будет работать отрисовка в зависимости от фреймрейта, мне главное это чтобы за одно и тоже время шарик в данном случае проходил одно и тоже расстояние вне зависимости от экрана.

Буду благодарен за любую помощь


Сообщение отредактировал DurianOdour - Четверг, 14 Декабря 2017, 23:22
afqДата: Пятница, 15 Декабря 2017, 04:13 | Сообщение # 2
Разработчик
Сейчас нет на сайте
DurianOdour, ты на libgdx делаешь? В игре чтобы везде одинаково было нужно делать симуляцию времени и обновлять действия объектов не с помощью кадров, а с помощью времени. В unity3d например для этого используют deltatime, в sdl используют sdl_delay, тебе тоже нужно использовать симуляцию времени, и если нет такой функции, то придется писать самому. А так, посмотри какие нибудь видео курсы по разработке игры нв libgdx ( если ты с помощью нее делаешь ), и увидишь что используют в качестве симуляции времени.
DurianOdourДата: Пятница, 15 Декабря 2017, 22:07 | Сообщение # 3
был не раз
Сейчас нет на сайте
Спасибо за ответ, я делаю это под Андроид вообще, без использования движков каких либо, все сам делаю, игра сильно простенькая. Подскажите в чем может быть проблема или как правильно сделать, чтобы сильно не усложнять
PsychoДата: Суббота, 16 Декабря 2017, 01:00 | Сообщение # 4
Психоламер
Сейчас нет на сайте
Цитата DurianOdour ()
TimeUtils.getCurrentTimeMillis()

Попробуй вместо этого использовать System.nanoTime(). Как вариант:

Код
long current = System.nanoTime();
int delta = (int) ((current - previous) / 1000000);
previous = current;
  • Страница 1 из 1
  • 1
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг