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
在屏幕需要换出时调用 show
和 hide
,这实际上不需要做任何事情,但可以覆盖自定义行为。
下面的工作方式是我的 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
以获得更简单的应用程序。
我正在 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
在屏幕需要换出时调用show
和hide
,这实际上不需要做任何事情,但可以覆盖自定义行为。
下面的工作方式是我的 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
以获得更简单的应用程序。