Libgdx 屏幕管理器

Libgdx ScreenManager

我正在 LibGdx 开发一款游戏,我会经常切换屏幕,所以我想我应该制作自己的小屏幕管理器。但是要设置屏幕,我需要参考 LibGdx Game。我对经理现在的样子不满意,必须有某种方法可以实现这一点,而不必发送两次 Game 对象。

我的代码:

public static void setScreen(Screen screen, Game game){
        if(currentScreen != null){
            currentScreen.dispose();
            System.out.println("Screen disposed");
        }
        currentScreen = screen;
        game.setScreen(currentScreen);
    }

现在要从另一个屏幕设置屏幕(例如从 menuScreen 设置 gameScreen)我需要将游戏对象发送到屏幕的构造函数,如下所示:

ScreenManager.setScreen(new GameScreen(game), game);

我这个完美主义者希望能够这样称呼它:

ScreenManager.setScreen(new GameScreen(), game

ScreenManager.setScreen(new GameScreen(game)

有谁能想办法做到这一点吗?还是我只是沉迷于一些我不妨放手去做的事情?

您可以创建自己的屏幕类型,它将 return 游戏放入其中并实现屏幕方法。

package ***;

import com.badlogic.gdx.Screen;
import ***.GameCore;

public class MyScreen implements Screen {
    GameCore game;
    public MyScreen(GameCore game) {
        this.game = game;
    }

    public GameCore getGameCore(){
        return this.game;
    }
    /*
    Methods implemented from Screen (render , hide , dispose etc...)
    */
}

然后创建将扩展 MyScreen 的屏幕类型。

package ***;

import ***.GameCore;

public class MenuScreen extends MyScreen{

    public MenuScreen (GameCore game) {
        super(game);        
    }
    /*
    Methods implemented from Screen (render , hide , dispose etc...)
    */
}

在 GameCore 中创建 MenuScreen 实例。

MenuScreen menuScreen = new MenuScreen(this);

然后你就可以做你想做的事了。

public static void setScreen(Screen screen){
    if(currentScreen != null){
        currentScreen.dispose();
        System.out.println("Screen disposed");
    }
    currentScreen = screen;
    currentScreen.getGameCore().setScreen(currentScreen);
}

然后你就可以自由设置你的屏幕了

ScreenManager.setScreen(new MenuScreen(game));

ScreenManager.setScreen(menuScreen);//if you have already created an instance of menu

你可以看看这个项目:https://github.com/edesdan/libgdx-playground。看看能不能用它来解决你的问题。

您可以使用 Gdx.app.getApplicationListener() 将其转换为 Game 来获取游戏实例。此外,您的代码可以变得更加简洁,将 setScreen 方法更改为:

public static void setScreen(Screen screen){
    if(currentScreen != null){
        currentScreen.dispose();
        System.out.println("Screen disposed");
    }
    currentScreen = screen;
    Game game = (Game)Gdx.app.getApplicationListener();
    game.setScreen(currentScreen);
}

我通过实现我自己的 Screen 来实现我自己的 ScreenManager,它扩展了 Group。我使用的协议是为最小对象实例化而设计的:

  • 所有 Screen 对象都应该是单例。我将它们的构造函数设为包私有的,只有 ScreenManager 可以直接实例化它们。它们存储在哈希映射中。
  • 仅在实例化时实例化您的 Screen 对象一次,并将它们添加到 Screen(因此我的所有组件也扩展了 Actor)。
  • 实施一种方法 getInputProcessors(),该方法 returns 自定义 Screen 使用的任何自定义处理程序都不会被阶段隐式触发。 (我实际上有一组类似的其他对象的功能,但为了清楚起见在这里删除。)
  • 我的 ScreenManager 在屏幕需要换出时调用 showhide,这实际上不需要做任何事情,但可以覆盖自定义行为。

下面的工作方式是我的 ScreenManager 有一个 Stage。经理只需清除屏幕之间的舞台对象并添加新舞台,因为它是一个 Group(这是一个可以包含更多演员的 Actor)。

无需过多介绍,这将涉及解释我的框架中的大量内部 类,这里是一般过程,其中抽象出了可能与您无关的功能(并允许外部 Screen 对象传入):

private final AtomicReference<Screen> curScreen = ...;
...
public static boolean set(Screen nextScreen)
{
  mutex.lock(); // prevent multi-threading issues
  try
  {
    // ensure the provided screen is valid
    final Screen cur = curScreen.get();
    if (null == nextScreen || nextScreen.equals(cur)) return false;

    // atomically update the current screen reference
    if (!curScreen.compareAndSet(cur, nextScreen)) return false;

    // record the screen for back() operations and add it to the stage
    if (null != cur) screenStack.push(cur);
    stage.clear();
    stage.add(nextScreen);

    // grab any custom input processors from the stage and build an input handler
    final inputProcessors = nextScreen.getInputProcessors();
    final InputProcessor[] processors = inputProcessors.toArray(new InputProcessor[inputProcessors.size()+1]);
    processors [inputProcessors.length-1] = stage;

    // inform gdx of our new input target
    Gdx.input.setInputProcessor(new InputMultiplexer(processors));

    return true;
  }
  catch (Throwable t) { Log.error(t); return false; }
  finally { mutex.unlock(); }
}

请注意 AtomicReference 自定义 Mutex 对象的使用,这是由于在更复杂的情况下可以获得效率。您可以将 Mutex 替换为 ReentrantLock,并将 AtomicReference 直接转换为 Screen 以获得更简单的应用程序。