• [libgdx游戏开发教程]使用Libgdx进行游戏开发(2)-游戏框架搭建


    让我们抛开理论开始code吧。

    入口类CanyonBunnyMain的代码:

    package com.packtpub.libgdx.canyonbunny;
    
    import com.badlogic.gdx.ApplicationListener;
    import com.packtpub.libgdx.canyonbunny.game.WorldController;
    import com.packtpub.libgdx.canyonbunny.game.WorldRenderer;
    
    public class CanyonBunnyMain implements ApplicationListener {
        private static final String TAG = CanyonBunnyMain.class.getName();
        private WorldController worldController;
        private WorldRenderer worldRenderer;
    
        @Override
        public void create() {
        }
    
        @Override
        public void render() {
        }
    
        @Override
        public void resize(int width, int height) {
        }
    
        @Override
        public void pause() {
        }
    
        @Override
        public void resume() {
        }
    
        @Override
        public void dispose() {
        }
    }

    WorldController

    package com.packtpub.libgdx.canyonbunny.game;
    
    public class WorldController {
        private static final String TAG = WorldController.class.getName();
    
        public WorldController() {
        }
    
        private void init() {
        }
    
        public void update(float deltaTime) {
        }
    }

    WorldRenderer

    package com.packtpub.libgdx.canyonbunny.game;
    
    import com.badlogic.gdx.graphics.OrthographicCamera;
    import com.badlogic.gdx.graphics.g2d.SpriteBatch;
    import com.badlogic.gdx.utils.Disposable;
    import com.packtpub.libgdx.canyonbunny.util.Constants;
    
    public class WorldRenderer implements Disposable {
        private OrthographicCamera camera;
        private SpriteBatch batch;
        private WorldController worldController;
    
        public WorldRenderer(WorldController worldController) {
        }
    
        private void init() {
        }
    
        public void render() {
        }
    
        public void resize(int width, int height) {
        }
    
        @Override
        public void dispose() {
        }
    }

    我们完成了CanyonBunnyMain, WorldController, WorldRenderer的第一个基本版本(骨架)。

    有必要回顾一下我们框架的核心点:游戏主循环是在CanyonBunnyMain类的render()方法中。

    要把三者联系起来,首先在create()中添加:

    @Override
        public void create() {
            // Set Libgdx log level to DEBUG
            Gdx.app.setLogLevel(Application.LOG_DEBUG);
            // Initialize controller and renderer
            worldController = new WorldController();
            worldRenderer = new WorldRenderer(worldController);
        }

    然后在render里调用

        @Override
        public void render() {
            // Update game world by the time that has passed
            // since last rendered frame.
            worldController.update(Gdx.graphics.getDeltaTime());
            // Sets the clear screen color to: Cornflower Blue
            Gdx.gl.glClearColor(0x64 / 255.0f, 0x95 / 255.0f, 0xed / 255.0f,0xff / 255.0f);
    //or Gdx.gl.glClearColor(100/255.0f, 149/255.0f, 237/255.0f, 255/255.0f);自定义的颜色
    // Clears the screen Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); // Render game world to screen worldRenderer.render(); }

    顺便修改下resize():(在游戏开始改变窗口大小的时候会触发)

        @Override
        public void resize(int width, int height) {
            worldRenderer.resize(width, height);
        }

    之后是dispose

    @Override
    public void dispose() {
    worldRenderer.dispose();
    }

    【在Android下,可以做个小改进】

    在Android上进行暂停的时候:我们让游戏别渲染了。

     加个标志位

    private boolean paused;

    create()和render()这么改:

        @Override
        public void create() {
            // Set Libgdx log level to DEBUG
            Gdx.app.setLogLevel(Application.LOG_DEBUG);
            // Initialize controller and renderer
            worldController = new WorldController();
            worldRenderer = new WorldRenderer(worldController);
            // Game world is active on start
            paused = false;
        }
    
        @Override
        public void render() {
            // Do not update game world when paused.
            if (!paused) {
                // Update game world by the time that has passed
                // since last rendered frame.
                worldController.update(Gdx.graphics.getDeltaTime());
            }
            // Sets the clear screen color to: Cornflower Blue
            Gdx.gl.glClearColor(0x64 / 255.0f, 0x95 / 255.0f, 0xed / 255.0f,
                    0xff / 255.0f);
            // Clears the screen
            Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
            // Render game world to screen
            worldRenderer.render();
        }

    加上切换的代码:

        @Override
        public void pause() {
            paused = true;
        }
    
        @Override
        public void resume() {
            paused = false;
        }

    OK。整合在一起了。运行看看效果。

    太棒了。(你应该猜到了这里使用的设计模式就是MVC模式)

    接下来,我们需要一个常量类来保存所有用到的常量。

    Constants.java

    package com.packtpub.libgdx.canyonbunny.util;
    public class Constants {
    // Visible game world is 5 meters wide
    public static final float VIEWPORT_WIDTH = 5.0f;
    // Visible game world is 5 meters tall
    public static final float VIEWPORT_HEIGHT = 5.0f;
    }

    现在需要在屏幕上加点东东了。我们现在在屏幕上画5个箱子。有人已经开始在准备箱子的图片了,这里我们不用图片,自己画。

    (画一个矩形填上色,画两个对角线,再画个矩形边框,不就是个箱子吗?哈哈)像素画是不会美工的程序员的最爱,除了比较简单,还因为可以用程序画出来。

    当然,用图片也是一样的。
    首先要在脑子里想清楚,箱子对象归谁管理?画箱子这个职责是谁的?

    箱子对象自然是由控制器来管理:为了方便识别,我们让其中一个箱子作为当前选中的箱子,并且让它自转。

      public Sprite[] testSprites;
        public int selectedSprite;
    
        public WorldController() {
            init();
        }
    
        private void init() {
            initTestObjects();
        }
    
        private void initTestObjects() {
            // Create new array for 5 sprites
            testSprites = new Sprite[5];
            // Create empty POT-sized Pixmap with 8 bit RGBA pixel data
            int width = 32;
            int height = 32;
            Pixmap pixmap = createProceduralPixmap(width, height);
            // Create a new texture from pixmap data
            Texture texture = new Texture(pixmap);
            // Create new sprites using the just created texture
            for (int i = 0; i < testSprites.length; i++) {
                Sprite spr = new Sprite(texture);
                // Define sprite size to be 1m x 1m in game world
                spr.setSize(1, 1);
                // Set origin to sprite's center
                spr.setOrigin(spr.getWidth() / 2.0f, spr.getHeight() / 2.0f);
                // Calculate random position for sprite
                float randomX = MathUtils.random(-2.0f, 2.0f);
                float randomY = MathUtils.random(-2.0f, 2.0f);
                spr.setPosition(randomX, randomY);
                // Put new sprite into array
                testSprites[i] = spr;
            }
            // Set first sprite as selected one
            selectedSprite = 0;
        }
    
        private Pixmap createProceduralPixmap(int width, int height) {
            Pixmap pixmap = new Pixmap(width, height, Format.RGBA8888);
            // Fill square with red color at 50% opacity
            pixmap.setColor(1, 0, 0, 0.5f);
            pixmap.fill();
            // Draw a yellow-colored X shape on square
            pixmap.setColor(1, 1, 0, 1);
            pixmap.drawLine(0, 0, width, height);
            pixmap.drawLine(width, 0, 0, height);
            // Draw a cyan-colored border around square
            pixmap.setColor(0, 1, 1, 1);
            pixmap.drawRectangle(0, 0, width, height);
            return pixmap;
        }
    
        public void update(float deltaTime) {
            updateTestObjects(deltaTime);
        }
    
        private void updateTestObjects(float deltaTime) {
            // Get current rotation from selected sprite
            float rotation = testSprites[selectedSprite].getRotation();
            // Rotate sprite by 90 degrees per second
            rotation += 90 * deltaTime;
            // Wrap around at 360 degrees
            rotation %= 360;
            // Set new rotation value to selected sprite
            testSprites[selectedSprite].setRotation(rotation);
        }

    注意:这里并没有任何涉及画箱子的部分(这里只是用代码生成了一副像素画,还没有显示)。不要和render搞混淆了。
    接下来WorldRender负责把它画出来。

    public WorldRenderer(WorldController worldController) {
            this.worldController = worldController;
            init();
        }
    
        private void init() {
            batch = new SpriteBatch();
            camera = new OrthographicCamera(Constants.VIEWPORT_WIDTH,
                    Constants.VIEWPORT_HEIGHT);
            camera.position.set(0, 0, 0);
            camera.update();
        }
    
        public void render() {
            renderTestObjects();
        }
    
        private void renderTestObjects() {
            batch.setProjectionMatrix(camera.combined);
            batch.begin();
            for (Sprite sprite : worldController.testSprites) {
                sprite.draw(batch);
            }
            batch.end();
        }
    
        public void resize(int width, int height) {
            camera.viewportWidth = (Constants.VIEWPORT_HEIGHT / height) * width;
            camera.update();
        }
    
        @Override
        public void dispose() {
            batch.dispose();
        }

    看看效果

     至此,MVC模式的基本框架完成了。

    接下来,我们需要开发一些Debug的控制功能来方便我们的开发。

    比如

    按上下左右,当前选中的箱子就开始上下左右移动。

    按R键,游戏场景重新初始化。

    按空格键,下一个箱子被选中。

    再比如摄像机跟随当前箱子,视角放大缩小。

    不用急着看下一章的代码实现,自己先试试用代码实现这些功能。

  • 相关阅读:
    创建供应商-采购模块
    定义容差组
    前台创建供应商-财务角度
    对供应商账户组分配编号范围
    拓端数据tecdat|R语言建立和可视化混合效应模型mixed effect model
    拓端数据tecdat|R语言建模收入不平等:分布函数拟合及洛伦兹曲线(Lorenz curve)
    拓端数据tecdat|R语言中的多项式回归、局部回归、核平滑和平滑样条回归模型
    拓端数据tecdat|R语言ARIMA,SARIMA预测道路交通流量时间序列:季节性、周期性
    拓端数据tecdat|ARIMA模型预测CO2浓度时间序列
    拓端数据tecdat|R语言基于递归神经网络RNN的温度时间序列预测
  • 原文地址:https://www.cnblogs.com/mignet/p/Learning_Libgdx_Game_Development_02.html
Copyright © 2020-2023  润新知