Java Libgdx屏幕管理器

Java Libgdx屏幕管理器,java,libgdx,Java,Libgdx,我正在用LibGdx做一个游戏,我会经常切换屏幕,所以我想我应该做一个自己的小屏幕管理器。不过,要设置屏幕,我需要参考LibGdx游戏。我对经理现在的样子不满意,我一定有办法做到这一点,而不必发送两次游戏对象 我的代码: public static void setScreen(Screen screen, Game game){ if(currentScreen != null){ currentScreen.dispose();

我正在用LibGdx做一个游戏,我会经常切换屏幕,所以我想我应该做一个自己的小屏幕管理器。不过,要设置屏幕,我需要参考
LibGdx游戏
。我对经理现在的样子不满意,我一定有办法做到这一点,而不必发送两次游戏对象

我的代码:

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),Id需要向屏幕的构造函数发送一个游戏对象,如下所示:

ScreenManager.setScreen(新游戏屏幕(游戏),游戏)

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

ScreenManager.setScreen(新游戏屏幕(),游戏

ScreenManager.setScreen(新游戏屏幕(游戏)


有人能想出一个方法来实现这一点吗?或者我只是在痴迷于一些我可以让它成为现实的东西?

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

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));


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

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));


您可以查看此项目:。检查它,看看您是否可以使用它来解决问题。

您可以查看此项目:。检查它,看看您是否可以使用它来解决问题。

您可以使用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);
}

您可以使用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);
}

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

  • 所有
    Screen
    对象都应该是单例对象。我将它们的构造函数包设置为私有,只有
    ScreenManager
    可以直接实例化它们。它们存储在哈希映射中
  • 在实例化时只实例化一次
    屏幕
    的对象,并将它们添加到
    屏幕
    (因此,我的所有组件也在扩展
    参与者
  • 实现一个方法
    getInputProcessors()
    ,该方法返回自定义
    屏幕使用的、不会被后台隐式触发的任何自定义处理程序。(实际上,我为其他对象提供了一组类似的函数,但为了清晰起见,这里将其删除。)
  • 我的
    ScreenManager
    在需要调出屏幕时调用
    show
    hide
    ,这实际上不需要做任何事情,但可以为自定义行为覆盖
下面的工作方式是,我的屏幕管理器有一个
阶段
。管理器只需清除屏幕之间的阶段对象并添加新阶段,因为它是一个
(这是一个
参与者
,可以包含更多参与者)

在不深入太多细节的情况下,这将涉及到解释我的框架中的许多内部类,下面是一个一般过程,其中抽象出的功能可能与您无关(并允许传入外部屏幕对象):

private final AtomicReference curScreen=。。。;
...
公共静态布尔集(屏幕下一个屏幕)
{
mutex.lock();//防止多线程问题
尝试
{
//确保提供的屏幕有效
最终屏幕cur=curScreen.get();
if(null==nextScreen | | nextScreen.equals(cur))返回false;
//自动更新当前屏幕参考
如果(!curScreen.compareAndSet(cur,nextScreen))返回false;
//记录back()操作的屏幕并将其添加到后台
if(null!=cur)screenStack.push(cur);
stage.clear();
stage.add(nextScreen);
//从后台抓取任何自定义输入处理器并构建输入处理程序
final inputProcessors=nextScreen.getInputProcessors();
最终InputProcessor[]processors=inputProcessors.toArray(新的InputProcessor[inputProcessors.size()+1]);
处理器[inputProcessors.length-1]=阶段;
//通知gdx我们的新输入目标
setInputProcessor(新的输入多路复用器(处理器));
返回true;
}
catch(Throwable t){Log.error(t);返回false;}
最后{mutex.unlock();}
}

请注意使用了
AtomicReference
和自定义
Mutex
对象,这是由于更复杂的情况可以提高效率。您可以将
Mutex
交换为
ReentrantLock
,并将
AtomicReference
直接转换为
屏幕
,以实现更简单的应用程序。

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

  • 所有
    Screen
    对象都应该是单例对象。我将它们的构造函数包设置为私有,只有
    ScreenManager
    可以直接实例化它们。它们存储在哈希映射中
  • 在实例化时只实例化一次
    屏幕
    的对象,并将它们添加到
    屏幕
    (因此,我的所有组件也在扩展
    参与者
  • 实现一个方法
    getInputProce