Libgdx ScreenManager

时间:2015-04-03 16:31:09

标签: java libgdx

我正在开发一个LibGdx游戏,我会切换屏幕很多,所以我想我会做自己的小屏幕管理器。但是,要设置屏幕,我需要引用LibGdx 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)

有人能想到办法吗?或者我只是迷恋一些我可能会成为的东西?

4 个答案:

答案 0 :(得分:4)

您可以创建自己的屏幕类型,该类型将返回游戏并将实现屏幕方法。

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

答案 1 :(得分:2)

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

  • 所有Screen个对象都应该是单身。我使他们的构造函数包私有,只有ScreenManager可以直接实例化它们。它们存储在哈希映射中。
  • 仅在实例化时对您的Screen个对象进行一次实例化,然后将其添加到Screen(因此我的所有组件也都在扩展Actor)。
  • 实现一个方法getInputProcessors(),该方法返回自定义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以获得更简单的应用。

答案 2 :(得分:0)

您可以查看此项目:https://github.com/edesdan/libgdx-playground。检查一下,看看你是否可以用它来解决你的问题。

答案 3 :(得分:0)

您可以使用Gdx.app.getApplicationListener()将其投射到游戏中来获取游戏实例。此外,您的代码可以变得更清晰,将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);
}