libgdx教程
要将世界渲染到屏幕上,我们需要为其创建一个屏幕,并告诉它渲染世界。 在libgdx中,有一个名为Game
的便利类,我们将把StarAssault
类重写为StarAssault
提供的Game
类的子类。
关于屏幕
一个游戏可以包含多个屏幕。 甚至我们的游戏也将具有3个基本屏幕。 “开始游戏”屏幕,“播放”屏幕和“游戏结束”屏幕。 每个屏幕都与发生的事情有关,彼此之间并不关心。 例如,“开始游戏”屏幕将包含菜单选项“播放”和“退出” 。 它具有两个元素(按钮),并且关注于处理这些元素上的单击/触摸。 它不知疲倦地渲染这两个按钮,并且如果单击/触摸了“播放”按钮,它将通知主游戏加载“播放屏幕”并摆脱当前屏幕。 播放屏幕将运行我们的游戏,并将处理与游戏有关的所有内容。 达到“游戏结束”状态后,它会告诉主游戏过渡到“游戏结束”屏幕,其唯一目的是显示高分并收听“重播”按钮上的单击。
现在,让我们重构代码并仅创建游戏的主屏幕。 我们将跳过屏幕的开始和游戏。
GameScreen.java
package net.obviam.starassault.screens;
import com.badlogic.gdx.Screen;
public class GameScreen implements Screen {
@Override
public void render(float delta) {
// TODO Auto-generated method stub
}
@Override
public void resize(int width, int height) {
// TODO Auto-generated method stub
}
@Override
public void show() {
// TODO Auto-generated method stub
}
@Override
public void hide() {
// TODO Auto-generated method stub
}
@Override
public void pause() {
// TODO Auto-generated method stub
}
@Override
public void resume() {
// TODO Auto-generated method stub
}
@Override
public void dispose() {
// TODO Auto-generated method stub
}
}
StarAssault.java
将变得非常简单。
package net.obviam.starassault;
import net.obviam.starassault.screens.GameScreen;
import com.badlogic.gdx.Game;
public class StarAssault extends Game {
@Override
public void create() {
setScreen(new GameScreen());
}
}
GameScreen
实现了非常类似于ApplicationListener
的Screen
接口,但是它添加了2个重要方法。show()
–当主游戏激活该屏幕时调用hide()
–当主游戏激活另一个屏幕时调用
StarAssault
仅实现了一种方法。 create()
无非就是激活新实例化的GameScreen
。 换句话说,它创建了它,调用了show()
方法,随后将在每个周期调用其render()
方法。
GameScreen
将成为下一部分的焦点,因为它是游戏的生存地。 请记住,游戏循环是render()
方法。 但是要渲染一些东西,我们首先需要创造世界。 可以在show()
方法中创建世界,因为我们没有任何其他屏幕可以打断我们的游戏玩法。 当前,仅在游戏开始时才显示GameScreen
。
我们将在类中添加两个成员并实现render(float delta)
方法。
private World world;
private WorldRenderer renderer;
/** Rest of methods ommited **/
@Override
public void render(float delta) {
Gdx.gl.glClearColor(0.1f, 0.1f, 0.1f, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
renderer.render();
}
world
属性是World
实例,其中包含块和Bob。renderer
是一个类,它将在屏幕上绘制/渲染世界(我很快就会展示出来)。render(float delta)
让我们创建WorldRenderer
类。WorldRenderer.java
package net.obviam.starassault.view;
import net.obviam.starassault.model.Block;
import net.obviam.starassault.model.Bob;
import net.obviam.starassault.model.World;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Rectangle;
public class WorldRenderer {
private World world;
private OrthographicCamera cam;
/** for debug rendering **/
ShapeRenderer debugRenderer = new ShapeRenderer();
public WorldRenderer(World world) {
this.world = world;
this.cam = new OrthographicCamera(10, 7);
this.cam.position.set(5, 3.5f, 0);
this.cam.update();
}
public void render() {
// render blocks
debugRenderer.setProjectionMatrix(cam.combined);
debugRenderer.begin(ShapeType.Rectangle);
for (Block block : world.getBlocks()) {
Rectangle rect = block.getBounds();
float x1 = block.getPosition().x + rect.x;
float y1 = block.getPosition().y + rect.y;
debugRenderer.setColor(new Color(1, 0, 0, 1));
debugRenderer.rect(x1, y1, rect.width, rect.height);
}
// render Bob
Bob bob = world.getBob();
Rectangle rect = bob.getBounds();
float x1 = bob.getPosition().x + rect.x;
float y1 = bob.getPosition().y + rect.y;
debugRenderer.setColor(new Color(0, 1, 0, 1));
debugRenderer.rect(x1, y1, rect.width, rect.height);
debugRenderer.end();
}
}
WorldRenderer
只有一个目的。 获取世界的当前状态并将其当前状态呈现到屏幕上。 它有一个公共的render()
方法,该方法由主循环( GameScreen
)调用。 渲染器需要访问world
因此我们在实例化渲染器时将其传递。 第一步,我们将渲染元素的边界框(块和鲍勃),以查看到目前为止的内容。 在OpenGL中绘制图元非常繁琐,但是libgdx带有ShapeRenderer ,这使此任务非常容易。重点说明。
#14 –将world
声明为成员变量。#15 –我们声明一个OrthographicCamera。 我们将使用此相机从正交摄影法“看”世界。 当前世界很小,只能放在一个屏幕上,但是当我们需要一个宽广的水准并且Bob在其中移动时,我们将不得不跟随Bob移动摄像机。 它类似于现实生活中的相机。 有关正射投影的更多信息,请参见此处。#18 – ShapeRenderer
被声明。 我们将使用它为实体绘制图元(矩形)。 这是一个辅助渲染器,可以绘制诸如线,矩形,圆之类的图元。 对于熟悉基于画布的图形的人来说,这应该很容易。#20 –以world
为参数的构造函数。#22 –我们创建的相机的视口为10个单位宽和7个单位高。 这意味着用单位块(宽度=高度= 1)填充屏幕将导致在X轴上显示10个框,在Y轴上显示7个框。重要:这与分辨率无关。 如果屏幕分辨率为480×320,则480像素代表10个单位,因此一个框将为48像素宽。 这也意味着320像素代表7个单位,因此屏幕上的框将为45.7像素高。 这将不是一个完美的广场。 这是由于长宽比。 在我们的情况下,长宽比为10:7。#23 –这条线将摄像机定位在房间中间。 默认情况下,它查看房间的角落(0,0)。 相机的(0,0)位于普通相机的中间。 下图显示了世界和相机设置坐标。
#24 –相机的内部矩阵已更新。 每次对摄像机进行操作(移动,缩放,旋转等)时,都必须调用update方法。