首页 > 代码库 > libgdx Screen 切换

libgdx Screen 切换

我们一般在开发时,都会分成多个Screen去实现不同的功能,比如:

MenuScreen用于菜单界面显示,GameScreen主游戏界面,HelpScreen游戏帮助界面。

直接使用game.setScreen就可以完成场景的切换。不过这样略显生硬,另外,在内存占用方面有可能出现瞬时内存占用太大的问题,可能导致游戏退出什么的。

跟cocos2dx的道理一样,一个ScreenOne在切换的ScreenTwo时,是这样一个过程:

1. ScreenOne在运行中,它已加载资源。

2. 实例化ScreenTwo,加载ScreenTwo的资源(这时One和Two的资源都在内存中

3. 将显示切换到ScreenTwo,也就是game.setScreen(ScreenTwo)

4. ScreenOne销毁释放它的资源。

如果这两个Screen都加载很多资源的话,程序很容易出现问题。

比如iOS限定单个app最大10M内存(具体多少我忘了,我只是比方,请查文档),而ScreenOne和ScreenTwo分别占用8M,切换瞬间会有16M,这时就有问题啦。

 

以前在玩2dx的时候,哥们告诉我了一种方法,就是中间加个过渡的切换专用Screen,当然它的占用应该很小。

然后切换过程就变成了这样:

1. ScreenOne在运行中,它已加载资源。

2. 实例化TransScreen,加载TransScreen的资源,当然也可以不用资源,就是个黑屏

3. 将显示切换到TransScreen,也就是game.setScreen(TransScreen)

4. ScreenOne销毁释放它的资源。

5. 实例化ScreenTwo,加载ScreenTwo的资源

6. 将显示切换到ScreenTwo,也就是game.setScreen(ScreenTwo)

7. TransScreen销毁释放它的资源。

 

这样我们就把大量的资源占用错开了。

上代码

  1 public class ScreenTrans implements Screen {  2     private ScreenType next;  3     private Game game;//在需要切换场景的时候直接game.setScreen  4     private Stage stage;  5     private static final Logger LOGGER = new Logger(ScreenTrans.class.getName(), Application.LOG_DEBUG);  6     private static final float DURATION=0.5f;  7     private Texture logoTexture;  8     private Skin skin;  9     private ProgressBar bar; 10     private GameTimer timer; 11  12     public enum ScreenType{ 13         SCREEN_ONE,SCREEN_TWO 14     } 15  16     public ScreenTrans(Game game,ScreenType next) { 17         LOGGER.debug("init"); 18         this.game = game; 19         this.next = next; 20  21         stage = new Stage(); 22         //Gdx.input.setInputProcessor(null); 23  24         logoTexture = new Texture(Gdx.files.internal("badlogic.jpg")); 25         Image logo = new Image(logoTexture); 26         logo.setCenterPosition(Gdx.graphics.getWidth()/2,Gdx.graphics.getHeight()/2); 27         stage.addActor(logo); 28  29         skin = new Skin(); 30         Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888); 31         pixmap.setColor(Color.WHITE); 32         pixmap.fill(); 33         skin.add("white", new Texture(pixmap)); 34  35         ProgressBar.ProgressBarStyle style = new ProgressBar.ProgressBarStyle(); 36         style.knob = skin.newDrawable("white",Color.GREEN); 37         style.knobBefore = skin.newDrawable("white", Color.GREEN); 38         style.knobAfter = skin.newDrawable("white",Color.GRAY); 39         style.background = skin.newDrawable("white",Color.RED); 40  41         style.knob.setMinHeight(10); 42         style.knobBefore.setMinHeight(10); 43         style.knobAfter.setMinHeight(10); 44  45         bar = new ProgressBar(0,100,1,false,style); 46         bar.setWidth(logo.getWidth()); 47         bar.setCenterPosition(Gdx.graphics.getWidth()/2,(Gdx.graphics.getHeight()-logo.getHeight())/2-5); 48         stage.addActor(bar); 49  50         timer = new GameTimer(DURATION); 51     } 52  53     @Override 54     public void render(float delta) { 55         Gdx.gl.glClearColor(0, 0, 0, 1); 56         Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); 57  58         float d = CommonUtils.getDelta(delta); 59         timer.update(d); 60         if(timer.isFinished()){ 61             this.trans(); 62         } 63         bar.setValue(timer.getLiveTime()*100/DURATION); 64         stage.act(delta); 65         stage.draw(); 66     } 67  68     private void trans(){ 69         Screen nextScreen = null; 70         switch (next){ 71             case SCREEN_ONE: 72                 nextScreen = new ScreenOne(this.game); 73             break; 74             case SCREEN_TWO: 75                 nextScreen = new ScreenTwo(this.game); 76                 break; 77         } 78         this.game.setScreen(nextScreen); 79         this.dispose(); 80     } 81  82     @Override 83     public void resize(int width, int height) { 84         stage.getViewport().update(width,height,true); 85     } 86  87     @Override 88     public void show() { 89         LOGGER.debug("show"); 90     } 91  92     @Override 93     public void hide() { 94  95     } 96  97     @Override 98     public void pause() { 99 100     }101 102     @Override103     public void resume() {104 105     }106 107     @Override108     public void dispose() {109         LOGGER.debug("dispose");110         stage.dispose();111         logoTexture.dispose();112         skin.dispose();113     }114 }

以上代码中使用了枚举的场景类型用以区分下一步是哪个,当然也可以用int或者更高级一点用Class<? extends Screen>,然后用class.newInstance等。

GameTimer是个特别简单的计时器。

这个过渡屏我加入了一个假的加载进度条,当然是假的,这时候next的Screen还没实例化呢。其实是个计时条=。=

还有一个image。加入这些,我就是为了感受一下切换是否生硬。

以下是效果图:

 

以下是调试信息:

com.tide.g2d.screeneffect.two.ScreenOne: init
com.tide.g2d.screeneffect.two.ScreenOne: show
com.tide.g2d.screeneffect.ScreenTrans: init
com.tide.g2d.screeneffect.ScreenTrans: show
com.tide.g2d.screeneffect.two.ScreenOne: dispose

-----这时正在展示过渡屏
com.tide.g2d.screeneffect.two.ScreenTwo: init
com.tide.g2d.screeneffect.two.ScreenTwo: show
com.tide.g2d.screeneffect.ScreenTrans: dispose
com.tide.g2d.screeneffect.ScreenTrans: init
com.tide.g2d.screeneffect.ScreenTrans: show
com.tide.g2d.screeneffect.two.ScreenTwo: dispose

-----这时正在展示过渡屏
com.tide.g2d.screeneffect.two.ScreenOne: init
com.tide.g2d.screeneffect.two.ScreenOne: show
com.tide.g2d.screeneffect.ScreenTrans: dispose
com.tide.g2d.screeneffect.ScreenTrans: init
com.tide.g2d.screeneffect.ScreenTrans: show
com.tide.g2d.screeneffect.two.ScreenOne: dispose

-----这时正在展示过渡屏
com.tide.g2d.screeneffect.two.ScreenTwo: init
com.tide.g2d.screeneffect.two.ScreenTwo: show
com.tide.g2d.screeneffect.ScreenTrans: dispose

 

libgdx Screen 切换