1.Application 只是个接口而以,通过它的实现可以取到引擎的所有封装
public Graphics getGraphics ();
/** @return the {@link Audio} instance */
public Audio getAudio ();
/** @return the {@link Input} instance */
public Input getInput ();
/** @return the {@link Files} instance */
public Files getFiles ();
可以写入日志
/** Logs a message to the console or logcat */
public void log (String tag, String message);
/** Logs a message to the console or logcat */
public void log (String tag, String message, Exception exception);
/** Logs an error message to the console or logcat */
public void error (String tag, String message);
/** Logs an error message to the console or logcat */
public void error (String tag, String message, Exception exception);
/** Sets the log level. {@link #LOG_NONE} will mute all log output. {@link #LOG_ERROR} will only let messages issued with
* {@link #error(String, String)} through. {@link #LOG_INFO} will let all messages though, either logged via
* {@link #error(String, String)} or {@link #log(String, String)}.
* @param logLevel {@link #LOG_NONE}, {@link #LOG_ERROR}, {@link #LOG_INFO}. */
public void setLogLevel (int logLevel);
同时可以获取游戏版本,虚拟机堆栈,native堆栈等
/** @return what {@link ApplicationType} this application has, e.g. Android or Desktop */
public ApplicationType getType ();
/** @return the Android API level on Android or 0 on the desktop. */
public int getVersion ();
/** @return the Java heap memory use in bytes */
public long getJavaHeap ();
/** @return the Native heap memory use in bytes */
public long getNativeHeap ();
然后还有其他几个有用的功能
/** Returns the {@link Preferences} instance of this Application. It can be used to store application settings across runs.
* @param name the name of the preferences, must be useable as a file name.
* @return the preferences. */
public Preferences getPreferences (String name);
/** Posts a {@link Runnable} on the main loop thread.
*
* @param runnable the runnable. */
public void postRunnable (Runnable runnable);
/** Exits the application. This will cause a call to pause() and dispose() some time in the loadFuture, it will not immediately
* finish your application! */
public void exit ();
2.ApplicationListener同样是接口,它是游戏实现的基础
/** Called when the {@link Application} is first created. */
public void create ();
/** Called when the {@link Application} is resized. This can happen at any point during a non-paused state but will never happen
* before a call to {@link #create()}.
*
* @param width the new width in pixels
* @param height the new height in pixels */
public void resize (int width, int height);
/** Called when the {@link Application} should render itself. */
public void render ();
/** Called when the {@link Application} is paused. An Application is paused before it is destroyed, when a user pressed the Home
* button on Android or an incoming call happend. On the desktop this will only be called immediately before {@link #dispose()}
* is called. */
public void pause ();
/** Called when the {@link Application} is resumed from a paused state. On Android this happens when the activity gets focus
* again. On the desktop this method will never be called. */
public void resume ();
/** Called when the {@link Application} is destroyed. Preceded by a call to {@link #pause()}. */
public void dispose ();
3.ApplicationAdapter是一个空的实现
4.Gdx是整个引擎是数据核心,它通过静态变量保存引擎所有工具类
public class Gdx {
public static Application app;
public static Graphics graphics;
public static Audio audio;
public static Input input;
public static Files files;
public static GLCommon gl;
public static GL10 gl10;
public static GL11 gl11;
public static GL20 gl20;
public static GLU glu;
}
5.Game 也是ApplicationListener的一个抽象的实现,它实现了部分功能
public abstract class Game implements ApplicationListener {
private Screen screen;
@Override
public void dispose () {
if (screen != null) screen.hide();
}
@Override
public void pause () {
if (screen != null) screen.pause();
}
@Override
public void resume () {
if (screen != null) screen.resume();
}
@Override
public void render () {
if (screen != null) screen.render(Gdx.graphics.getDeltaTime());
}
@Override
public void resize (int width, int height) {
if (screen != null) screen.resize(width, height);
}
/** Sets the current screen. {@link Screen#hide()} is called on any old screen, and {@link Screen#show()} is called on the new
* screen. */
public void setScreen (Screen screen) {
if (this.screen != null) this.screen.hide();
this.screen = screen;
screen.show();
screen.resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}
/** @return the currently active {@link Screen}. */
public Screen getScreen () {
return screen;
}
}
一般来说游戏通常是直接实现这个类,它给抽象的游戏接口引入了一个Screen对象,它代表了游戏的画面
6.Screen当然是个接口,它的具体实现代表了具体的界面
7.Graphics也是个接口,它的具体实现封装获取不同图像接口的方法,你可以通过它访问framebuffer或者opengl
8.Input是个接口,它是输入的重要通道,通过它可以知道用户键盘,点击的状况
9.InputProcessor是个接口,它是点击键盘事件的截获器
public interface InputProcessor {
/** Called when a key was pressed
*
* @param keycode one of the constants in {@link Input.Keys}
* @return whether the input was processed */
public boolean keyDown (int keycode);
/** Called when a key was released
*
* @param keycode one of the constants in {@link Input.Keys}
* @return whether the input was processed */
public boolean keyUp (int keycode);
/** Called when a key was typed
*
* @param character The character
* @return whether the input was processed */
public boolean keyTyped (char character);
/** Called when the screen was touched or a mouse button was pressed. The button parameter will be {@link Buttons#LEFT} on
* Android.
*
* @param x The x coordinate, origin is in the upper left corner
* @param y The y coordinate, origin is in the upper left corner
* @param pointer the pointer for the event.
* @param button the button
* @return whether the input was processed */
public boolean touchDown (int x, int y, int pointer, int button);
/** Called when a finger was lifted or a mouse button was released. The button parameter will be {@link Buttons#LEFT} on
* Android.
*
* @param x The x coordinate
* @param y The y coordinate
* @param pointer the pointer for the event.
* @param button the button
* @return whether the input was processed */
public boolean touchUp (int x, int y, int pointer, int button);
/** Called when a finger or the mouse was dragged.
*
* @param x The x coordinate
* @param y The y coordinate
* @param pointer the pointer for the event.
* @return whether the input was processed */
public boolean touchDragged (int x, int y, int pointer);
/** Called when the mouse was moved without any buttons being pressed. Will not be called on Android.
*
* @param x The x coordinate
* @param y The y coordinate
* @return whether the input was processed */
public boolean touchMoved (int x, int y);
/** Called when the mouse wheel was scrolled. Will not be called on Android.
* @param amount the scroll amount, -1 or 1 depending on the direction the wheel was scrolled.
* @return whether the input was processed. */
public boolean scrolled (int amount);
}
10.Audio是声音处理的接口
11.Files是文件处理的接口
12.Matrix3是个3*3的矩阵类
13.Matrix4是个4*4的矩阵类
14.Vector3是个3维的向量类
15.Vector2是个2维的向量类
16.Color是个处理颜色的工具类,包含有r,g,b,a 4个float变量代表颜色,通过它们来表示逻辑的颜色,同时它也实现了真正颜色和这种逻辑颜色的转换
public static int rgb565 (float r, float g, float b) {
return ((int)(r * 31) << 11) | ((int)(g * 63) << 5) | (int)(b * 31);
}
public static int rgba4444 (float r, float g, float b, float a) {
return ((int)(r * 15) << 12) | ((int)(g * 15) << 8) | ((int)(b * 15) << 4) | (int)(a * 15);
}
public static int rgb888 (float r, float g, float b) {
return ((int)(r * 255) << 16) | ((int)(g * 255) << 8) | (int)(b * 255);
}
public static int rgba8888 (float r, float g, float b, float a) {
return ((int)(r * 255) << 24) | ((int)(g * 255) << 16) | ((int)(b * 255) << 8) | (int)(a * 255);
}
/** Sets the Color components using the specified integer value in the format RGB565. This is inverse to the rgb565(r, g, b)
* method.
*
* @param color The Color to be modified.
* @param value An integer color value in RGB565 format. */
public static void rgb565ToColor (Color color, int value) {
color.r = ((value & 0x0000F800) >>> 11) / 31f;
color.g = ((value & 0x000007E0) >>> 5) / 63f;
color.b = ((value & 0x0000001F) >>> 0) / 31f;
}
/** Sets the Color components using the specified integer value in the format RGBA4444. This is inverse to the rgba4444(r, g, b,
* a) method.
*
* @param color The Color to be modified.
* @param value An integer color value in RGBA4444 format. */
public static void rgba4444ToColor (Color color, int value) {
color.r = ((value & 0x0000f000) >>> 12) / 15f;
color.g = ((value & 0x00000f00) >>> 8) / 15f;
color.b = ((value & 0x000000f0) >>> 4) / 15f;
color.a = ((value & 0x0000000f)) / 15f;
}
/** Sets the Color components using the specified integer value in the format RGB888. This is inverse to the rgb888(r, g, b)
* method.
*
* @param color The Color to be modified.
* @param value An integer color value in RGB888 format. */
public static void rgb888ToColor (Color color, int value) {
color.r = ((value & 0x00ff0000) >>> 16) / 255f;
color.g = ((value & 0x0000ff00) >>> 8) / 255f;
color.b = ((value & 0x000000ff)) / 255f;
}
/** Sets the Color components using the specified integer value in the format RGBA8888. This is inverse to the rgb8888(r, g, b,
* a) method.
*
* @param color The Color to be modified.
* @param value An integer color value in RGBA8888 format. */
public static void rgba8888ToColor (Color color, int value) {
color.r = ((value & 0xff000000) >>> 24) / 255f;
color.g = ((value & 0x00ff0000) >>> 16) / 255f;
color.b = ((value & 0x0000ff00) >>> 8) / 255f;
color.a = ((value & 0x000000ff)) / 255f;
}
17.FPSLogger是个调试中检查fps的工具类
public class FPSLogger {
long startTime;
public FPSLogger () {
startTime = System.nanoTime();
}
/** Logs the current frames per second to the console. */
public void log () {
if (System.nanoTime() - startTime > 1000000000) {
Gdx.app.log("FPSLogger", "fps: " + Gdx.graphics.getFramesPerSecond());
startTime = System.nanoTime();
}
}
}
18.Pixmap是图像绘画的主要接口,这个类是Gdx2DPixmap的包装,而这个Gdx2DPixmap相当于内存里面的图片,它通过各种方法来绘制这块内存,使用了图像学中最最基础的方法
19.Texture是纹理的封装
如何给图形附上纹理?
GL10.glEnable(GL10.GL_TEXTURE_2D);
Bitmap bitmap = BitmapFactory.decodeStream(game.getFileIO().readAsset("bobrgb888.png"));
int textureIds[] = new int[1];
//生成纹理
gl.glGenTextures(1, textureIds, 0);
int textureId = textureIds[0];
//绑定纹理
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
//设置纹理的参数
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_NEAREST);
//使用纹理绘图
vertices.position(0);
gl.glVertexPointer(2, GL10.GL_FLOAT, VERTEX_SIZE, vertices);
vertices.position(2);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, VERTEX_SIZE, vertices);
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
//解除绑定
gl.glBindTexture(GL10.GL_TEXTURE_2D, 0);
//回收资源
bitmap.recycle();
上面是opengles的做法,这个类封装了几个有用的函数
public static int createGLHandle () {
buffer.position(0);
buffer.limit(buffer.capacity());
Gdx.gl.glGenTextures(1, buffer);
return buffer.get(0);
}
public void load (TextureData data) {
if (this.data != null && data.isManaged() != this.data.isManaged())
throw new GdxRuntimeException("New data must have the same managed status as the old data");
this.data = data;
if(!data.isPrepared()) data.prepare();
if (data.getType() == TextureDataType.Pixmap) {
Pixmap pixmap = data.consumePixmap();
uploadImageData(pixmap);
if (data.disposePixmap()) pixmap.dispose();
setFilter(minFilter, magFilter);
setWrap(uWrap, vWrap);
}
if (data.getType() == TextureDataType.Compressed) {
Gdx.gl.glBindTexture(GL10.GL_TEXTURE_2D, glHandle);
data.consumeCompressedData();
setFilter(minFilter, magFilter);
setWrap(uWrap, vWrap);
}
}
private void uploadImageData (Pixmap pixmap) {
if (enforcePotImages && Gdx.gl20 == null
&& (!MathUtils.isPowerOfTwo(data.getWidth()) || !MathUtils.isPowerOfTwo(data.getHeight()))) {
throw new GdxRuntimeException("Texture width and height must be powers of two: " + data.getWidth() + "x"
+ data.getHeight());
}
boolean disposePixmap = false;
if (data.getFormat() != pixmap.getFormat()) {
Pixmap tmp = new Pixmap(pixmap.getWidth(), pixmap.getHeight(), data.getFormat());
Blending blend = Pixmap.getBlending();
Pixmap.setBlending(Blending.None);
tmp.drawPixmap(pixmap, 0, 0, 0, 0, pixmap.getWidth(), pixmap.getHeight());
Pixmap.setBlending(blend);
pixmap = tmp;
disposePixmap = true;
}
Gdx.gl.glBindTexture(GL10.GL_TEXTURE_2D, glHandle);
Gdx.gl.glPixelStorei(GL10.GL_UNPACK_ALIGNMENT, 1);
if (data.useMipMaps()) {
MipMapGenerator.generateMipMap(pixmap, pixmap.getWidth(), pixmap.getHeight(), disposePixmap);
} else {
Gdx.gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, pixmap.getGLInternalFormat(), pixmap.getWidth(), pixmap.getHeight(), 0,
pixmap.getGLFormat(), pixmap.getGLType(), pixmap.getPixels());
if (disposePixmap) {
pixmap.dispose();
}
}
}
上面三个方法就把纹理绑定了
public Texture (TextureData data) {
create(data);
}
这个是主要的构造函数
public Texture (FileHandle file, Format format, boolean useMipMaps) {
if (file.name().contains(".etc1")) {
create(new ETC1TextureData(file, useMipMaps));
} else {
create(new FileTextureData(file, null, format, useMipMaps));
}
}
public Texture (Pixmap pixmap) {
this(new PixmapTextureData(pixmap, null, false, false));
}
private void create (TextureData data) {
glHandle = createGLHandle();
load(data);
if (data.isManaged()) addManagedTexture(Gdx.app, this);
}
在构造函数中就完成了绑定
/** Disposes all resources associated with the texture */
public void dispose () {
// this is a hack. reason: we have to set the glHandle to 0 for textures that are
// reloaded through the asset manager as we first remove (and thus dispose) the texture
// and then reload it. the glHandle is set to 0 in invalidateAllTextures prior to
// removal from the asset manager.
if(glHandle == 0) return;
buffer.put(0, glHandle);
Gdx.gl.glDeleteTextures(1, buffer);
if (data.isManaged()) {
if (managedTextures.get(Gdx.app) != null) managedTextures.get(Gdx.app).remove(this);
}
glHandle = 0;
}
析构
20.TextureData是Texture的数据
它就是上面opengles中用到的bitmap数据的包装,但它使用pixmap
public Pixmap consumePixmap ();
就是用来获取这个数据
21.PixmapTextureData是TextureData的实现,它就直接包装pixmap
22.FileTextureData是TextureData的实现,它就间接包装pixmap
@Override
public void prepare () {
if (isPrepared) throw new GdxRuntimeException("Already prepared");
if (pixmap == null) {
pixmap = new Pixmap(file);
width = pixmap.getWidth();
height = pixmap.getHeight();
if (format == null) format = pixmap.getFormat();
}
isPrepared = true;
}
这个方法需要在consumePixmap之前调用
23.TextureRegion是纹理区域
/** @param width The width of the texture region. May be negative to flip the sprite when drawn.
* @param height The height of the texture region. May be negative to flip the sprite when drawn. */
public void setRegion (int x, int y, int width, int height) {
float invTexWidth = 1f / texture.getWidth();
float invTexHeight = 1f / texture.getHeight();
setRegion(x * invTexWidth, y * invTexHeight, (x + width) * invTexWidth, (y + height) * invTexHeight);
}
public void setRegion (float u, float v, float u2, float v2) {
this.u = u;
this.v = v;
this.u2 = u2;
this.v2 = v2;
}
这是它的核心方法
24.Sprite是一个核心类,它保存了位置颜色纹理等等东西,它是一个精灵的抽象
它永远是矩形的,由左下,右上两点来限制
它保存了4个点的位置,颜色,纹理的位置,同时它可以缩放旋转,它本身可以绘制
public float[] getVertices () {
if (dirty) {
dirty = false;
float[] vertices = this.vertices;
float localX = -originX;
float localY = -originY;
float localX2 = localX + width;
float localY2 = localY + height;
float worldOriginX = this.x - localX;
float worldOriginY = this.y - localY;
if (scaleX != 1 || scaleY != 1) {
localX *= scaleX;
localY *= scaleY;
localX2 *= scaleX;
localY2 *= scaleY;
}
if (rotation != 0) {
final float cos = MathUtils.cosDeg(rotation);
final float sin = MathUtils.sinDeg(rotation);
final float localXCos = localX * cos;
final float localXSin = localX * sin;
final float localYCos = localY * cos;
final float localYSin = localY * sin;
final float localX2Cos = localX2 * cos;
final float localX2Sin = localX2 * sin;
final float localY2Cos = localY2 * cos;
final float localY2Sin = localY2 * sin;
final float x1 = localXCos - localYSin + worldOriginX;
final float y1 = localYCos + localXSin + worldOriginY;
vertices[X1] = x1;
vertices[Y1] = y1;
final float x2 = localXCos - localY2Sin + worldOriginX;
final float y2 = localY2Cos + localXSin + worldOriginY;
vertices[X2] = x2;
vertices[Y2] = y2;
final float x3 = localX2Cos - localY2Sin + worldOriginX;
final float y3 = localY2Cos + localX2Sin + worldOriginY;
vertices[X3] = x3;
vertices[Y3] = y3;
vertices[X4] = x1 + (x3 - x2);
vertices[Y4] = y3 - (y2 - y1);
} else {
final float x1 = localX + worldOriginX;
final float y1 = localY + worldOriginY;
final float x2 = localX2 + worldOriginX;
final float y2 = localY2 + worldOriginY;
vertices[X1] = x1;
vertices[Y1] = y1;
vertices[X2] = x1;
vertices[Y2] = y2;
vertices[X3] = x2;
vertices[Y3] = y2;
vertices[X4] = x2;
vertices[Y4] = y1;
}
}
return vertices;
}
获取它变换后的顶点位置
public void draw (SpriteBatch spriteBatch) {
spriteBatch.draw(texture, getVertices(), 0, SPRITE_SIZE); //20
}
这个TextRegion的类不是单单保存区域的位置而已,它同时对顶点做了转换,所以上面传人spriteBatch的是Texture
public void setRegion (float u, float v, float u2, float v2) {
this.u = u;
this.v = v;
this.u2 = u2;
this.v2 = v2;
float[] vertices = Sprite.this.vertices;
vertices[U1] = u;
vertices[V1] = v2;
vertices[U2] = u;
vertices[V2] = v;
vertices[U3] = u2;
vertices[V3] = v;
vertices[U4] = u2;
vertices[V4] = v2;
}
25.VertexAttribute是一个代表顶点属性的类
26.VertexData保存了openGL需要的顶点
27.VertexArray是VertexData的实现类
//申请空间
public VertexArray (int numVertices, VertexAttributes attributes) {
this.attributes = attributes;
byteBuffer = ByteBuffer.allocateDirect(this.attributes.vertexSize * numVertices);
byteBuffer.order(ByteOrder.nativeOrder());
buffer = byteBuffer.asFloatBuffer();
buffer.flip();
byteBuffer.flip();
}
//将这些顶点绑定
public void bind () {
GL10 gl = Gdx.gl10;
int textureUnit = 0;
int numAttributes = attributes.size();
byteBuffer.limit(buffer.limit() * 4);
for (int i = 0; i < numAttributes; i++) {
VertexAttribute attribute = attributes.get(i);
switch (attribute.usage) {
case Usage.Position:
byteBuffer.position(attribute.offset);
gl.glEnableClientState(GL11.GL_VERTEX_ARRAY);
gl.glVertexPointer(attribute.numComponents, GL10.GL_FLOAT, attributes.vertexSize, byteBuffer);
break;
case Usage.Color:
case Usage.ColorPacked:
int colorType = GL10.GL_FLOAT;
if (attribute.usage == Usage.ColorPacked) colorType = GL11.GL_UNSIGNED_BYTE;
byteBuffer.position(attribute.offset);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
gl.glColorPointer(attribute.numComponents, colorType, attributes.vertexSize, byteBuffer);
break;
case Usage.Normal:
byteBuffer.position(attribute.offset);
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
gl.glNormalPointer(GL10.GL_FLOAT, attributes.vertexSize, byteBuffer);
break;
case Usage.TextureCoordinates:
gl.glClientActiveTexture(GL10.GL_TEXTURE0 + textureUnit);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
byteBuffer.position(attribute.offset);
gl.glTexCoordPointer(attribute.numComponents, GL10.GL_FLOAT, attributes.vertexSize, byteBuffer);
textureUnit++;
break;
default:
// throw new GdxRuntimeException("unkown vertex attribute type: " + attribute.usage);
}
}
isBound = true;
}
//设置数据
@Override
public void setVertices (float[] vertices, int offset, int count) {
BufferUtils.copy(vertices, byteBuffer, count, offset);
buffer.position(0);
buffer.limit(count);
}
28.Camera是个涉及变换的虚类
GL_PROJECTION是投影矩阵的设置
public void apply (GL10 gl) {
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadMatrixf(projection.val, 0);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadMatrixf(view.val, 0);
}
29.OrthographicCamera正交投影
zoom=1;
near=0;
far=100;
@Override
public void update () {
projection.setToOrtho(zoom * -viewportWidth / 2, zoom * viewportWidth / 2, zoom * -viewportHeight / 2, zoom
* viewportHeight / 2, Math.abs(near), Math.abs(far));
view.setToLookAt(position, tmp.set(position).add(direction), up);
combined.set(projection);
Matrix4.mul(combined.val, view.val);
invProjectionView.set(combined);
Matrix4.inv(invProjectionView.val);
frustum.update(invProjectionView);
}
30.SpriteBatch是整个graphic的核心类,它将所有绘画包装起来,在内存中计算好所有顶点的位置一起提交
31.Mesh是一个由顶点,索引等构成的类
32.BitmapFont是用来绘制图片字体的
String text = "Touch screen to gameover!";
float width = font.getBounds(text).width;
font.draw(spriteBatch, text, 240 - width / 2, 128);
通常这样就可以在游戏中绘制字体
用hiero创建fnt,和png,fnt为字体的定位和属性文件,png就是字体的texture
33.Animation仅仅就是个TextRegion的简单集合而已
34.Cullable是个接口
public interface Cullable {
public void setCullingArea (Rectangle cullingArea);
}
35.Widget一个虚类,是各种控件的基础
36.Image图片类,可以知道它可以支持Texture和patch两种图片格式
37.Label标签类,使用BitmapFont来写文字
38.TextField输入框类
39.Group是Actor的集合类,它将点击消息传个children
40.WidgetGroup是组合控件的基类
41.Table 继承WidgetGroup
42.Button按钮类继承自Table
43.CheckBox是按钮类,但同时它是一个Image类加一个Label类对象组合而成
44.ComboBox继承自Widget
45.List列表类继承自Widget
46.Action是个虚类用来描述动作
47.XmlReader是个轻量级的xml解析器
48.XmlWriter很原始的xml生成器
49.GdxNativesLoader是本地文件加载器
50.AndroidApplication是程序的开始,它就是一个Activity
public class AndroidApplication extends Activity implements Application
Gdx.app = this;
Gdx.input = this.getInput();
Gdx.audio = this.getAudio();
Gdx.files = this.getFiles();
Gdx.graphics = this.getGraphics();
和前面描述一样,都在Gdx里面
initializeForView需要在OnCreate里面调用
graphics = new AndroidGraphics(this, config, config.resolutionStrategy == null ? new FillResolutionStrategy()
: config.resolutionStrategy);
return graphics.getView();
是它产生View的重要方法
51.AndroidGraphics是图像显示的类,它给上面的Activity提供glsurfaceview
package com.google.android.ClearTest;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.app.Activity;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.MotionEvent;
public class ClearActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mGLView = new ClearGLSurfaceView(this); setContentView(mGLView);}
@Override
protected void onPause()
{ super.onPause(); mGLView.onPause();}
@Override
protected void onResume()
{ super.onResume(); mGLView.onResume();}
private GLSurfaceView mGLView;}
class ClearGLSurfaceView extends GLSurfaceView
{
public ClearGLSurfaceView(Context context)
{ super(context);
mRenderer = new ClearRenderer();
setRenderer(mRenderer);}
public boolean onTouchEvent(final MotionEvent event)
{
queueEvent(new Runnable() {
public void run()
{ mRenderer.setColor(event.getX() / getWidth(), event.getY() / getHeight()1.0f);}}); return true;}
ClearRenderer mRenderer;
}
class ClearRenderer implements GLSurfaceView.Renderer
{
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{ // Do nothing special.
}
public void onSurfaceChanged(GL10 gl, int w, int h)
{ gl.glViewport(0, 0, w, h);}
public void onDrawFrame(GL10 gl)
{ gl.glClearColor(mRed, mGreen, mBlue, 1.0f);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
}
public void setColor(float r, float g, float b)
{ mRed = r; mGreen = g; mBlue = b;}
private float mRed;
private float mGreen;
private float mBlue;
}
}
}
这个程序功能很简单,每帧绘制时将屏幕设置成黑色。但它是一个完整的工作在 Activity 生命周期中的 OpenGL 程序。当 activity 暂停时,它暂停渲染
上面是一个基本的程序,而这个类就包装了这个过程
private View createGLSurfaceView (Activity activity, boolean useGL2, ResolutionStrategy resolutionStrategy) {
EGLConfigChooser configChooser = getEglConfigChooser();
if (useGL2 && checkGL20()) {
GLSurfaceView20 view = new GLSurfaceView20(activity, resolutionStrategy);
if (configChooser != null)
view.setEGLConfigChooser(configChooser);
else
view.setEGLConfigChooser(config.r, config.g, config.b, config.a, config.depth, config.stencil);
view.setRenderer(this);
return view;
} else {
config.useGL20 = false;
configChooser = getEglConfigChooser();
if (Integer.parseInt(android.os.Build.VERSION.SDK) <= 4) {
GLSurfaceViewCupcake view = new GLSurfaceViewCupcake(activity, resolutionStrategy);
if (configChooser != null)
view.setEGLConfigChooser(configChooser);
else
view.setEGLConfigChooser(config.r, config.g, config.b, config.a, config.depth, config.stencil);
view.setRenderer(this);
return view;
} else {
android.opengl.GLSurfaceView view = new DefaultGLSurfaceView(activity, resolutionStrategy);
if (configChooser != null)
view.setEGLConfigChooser(configChooser);
else
view.setEGLConfigChooser(config.r, config.g, config.b, config.a, config.depth, config.stencil);
view.setRenderer(this);
return view;
}
}
}
一般目前的机器都会创建这个DefaultGLSurfaceView,它就是一个简单的glsurfaceview,而它本身就是一个Renderer,
52.DefaultGLSurfaceView就是个简单的glsurfaceview
public class DefaultGLSurfaceView extends GLSurfaceView
53.GLSurfaceViewCupcake是surfaceview的实现,其中还有渲染线程的实现
54.AndroidAudio是声音引擎,它保存了一堆AndroidMusic和一个SoundPool
55.AndroidMusic是MediaPlayer的简单封装
56.AndroidAudioDevice是AudioTrack的封装
57.AndroidAudioRecorder是AudioRecord的封装
58.AndroidSound是SoundPool的封装
59.GL10将GL10又封装了一次
60.AndroidApplicationConfiguration是Application的一个配置类
Demo分析
1.Cuboc
MainMenu
@Override
public void show () {
//取title.png的一部分,0,0,480,320的位置
title = new TextureRegion(new Texture(Gdx.files.internal("data/title.png")), 0, 0, 480, 320);
batch = new SpriteBatch();
//设置投影矩阵0,0,480,320
batch.getProjectionMatrix().setToOrtho2D(0, 0, 480, 320);
}
@Override
public void render (float delta) {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
batch.begin();
//在0,0点的位置绘制这块纹理
batch.draw(title, 0, 0);
batch.end();
time += delta;
if (time > 1) {
if (Gdx.input.isKeyPressed(Keys.ANY_KEY) || Gdx.input.justTouched()) {
game.setScreen(new IntroScreen(game));
}
}
}
GameOverScreen
@Override
public void show () {
//取0,0,480,320这块纹理
intro = new TextureRegion(new Texture(Gdx.files.internal("data/gameover.png")), 0, 0, 480, 320);
batch = new SpriteBatch();
batch.getProjectionMatrix().setToOrtho2D(0, 0, 480, 320);
}
@Override
public void render (float delta) {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
batch.begin();
//在0,0的位置绘图
batch.draw(intro, 0, 0);
batch.end();
time += delta;
if (time > 1) {
if (Gdx.input.isKeyPressed(Keys.ANY_KEY) || Gdx.input.justTouched()) {
game.setScreen(new MainMenu(game));
}
}
}
IntroScreen
@Override
public void show () {
intro = new TextureRegion(new Texture(Gdx.files.internal("data/intro.png")), 0, 0, 480, 320);
batch = new SpriteBatch();
batch.getProjectionMatrix().setToOrtho2D(0, 0, 480, 320);
}
@Override
public void render (float delta) {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(intro, 0, 0);
batch.end();
time += delta;
if (time > 1) {
if (Gdx.input.isKeyPressed(Keys.ANY_KEY) || Gdx.input.justTouched()) {
game.setScreen(new GameScreen(game));
}
}
}
这个Screen最为复杂
GameScreen
@Override
public void show () {
map = new Map();
renderer = new MapRenderer(map);
controlRenderer = new OnscreenControlRenderer(map);
}
@Override
public void render (float delta) {
delta = Math.min(0.06f, Gdx.graphics.getDeltaTime());
map.update(delta); //逻辑部分
Gdx.gl.glClearColor(0.1f, 0.1f, 0.1f, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
renderer.render(delta); //绘图部分
controlRenderer.render();
if (map.bob.bounds.overlaps(map.endDoor.bounds)) {
game.setScreen(new GameOverScreen(game));
}
if (Gdx.input.isKeyPressed(Keys.ESCAPE)) {
game.setScreen(new MainMenu(game));
}
}
public void render (float deltaTime) {
if (map.cube.state != Cube.CONTROLLED)
cam.position.lerp(lerpTarget.set(map.bob.pos.x, map.bob.pos.y, 0), 2f * deltaTime);
else
cam.position.lerp(lerpTarget.set(map.cube.pos.x, map.cube.pos.y, 0), 2f * deltaTime);
cam.update();
renderLaserBeams();
cache.setProjectionMatrix(cam.combined);
Gdx.gl.glDisable(GL10.GL_BLEND);
cache.begin();
int b = 0;
for (int blockY = 0; blockY < 4; blockY++) {
for (int blockX = 0; blockX < 6; blockX++) {
cache.draw(blocks[blockX][blockY]);
b++;
}
}
cache.end();
Gdx.app.log("Cubocy", "blocks: " + b);
stateTime += deltaTime;
batch.setProjectionMatrix(cam.combined);
batch.begin();
renderDispensers();
if (map.endDoor != null) batch.draw(endDoor, map.endDoor.bounds.x, map.endDoor.bounds.y, 1, 1);
renderLasers();
renderMovingSpikes();
renderBob();
renderCube();
renderRockets();
batch.end();
renderLaserBeams();
fps.log();
}
@Override
public void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initialize(new HelloWorld(), false);
}
HelloWorld implements ApplicationListener
它来完成游戏逻辑
@Override
public void create () {
font = new BitmapFont();
font.setColor(Color.RED); //字体
texture = new Texture(Gdx.files.internal("data/badlogic.jpg")); //纹理
spriteBatch = new SpriteBatch();
}
@Override
public void resize (int width, int height) {
//修改投影
spriteBatch.getProjectionMatrix().setToOrtho2D(0, 0, width, height);
textPosition.set(0, 0);
}
//绘图
int centerX = Gdx.graphics.getWidth() / 2;
int centerY = Gdx.graphics.getHeight() / 2;
Gdx.graphics.getGL10().glClear(GL10.GL_COLOR_BUFFER_BIT);
// more fun but confusing :)
// textPosition.add(textDirection.tmp().mul(Gdx.graphics.getDeltaTime()).mul(60));
textPosition.x += textDirection.x * Gdx.graphics.getDeltaTime() * 60;
textPosition.y += textDirection.y * Gdx.graphics.getDeltaTime() * 60;
if (textPosition.x < 0) {
textDirection.x = -textDirection.x;
textPosition.x = 0;
}
if (textPosition.x > Gdx.graphics.getWidth()) {
textDirection.x = -textDirection.x;
textPosition.x = Gdx.graphics.getWidth();
}
if (textPosition.y < 0) {
textDirection.y = -textDirection.y;
textPosition.y = 0;
}
if (textPosition.y > Gdx.graphics.getHeight()) {
textDirection.y = -textDirection.y;
textPosition.y = Gdx.graphics.getHeight();
}
spriteBatch.begin();
spriteBatch.setColor(Color.WHITE);
spriteBatch.draw(texture, centerX - texture.getWidth() / 2, centerY - texture.getHeight() / 2, 0, 0, texture.getWidth(),
texture.getHeight());
font.draw(spriteBatch, "Hello World!", (int)textPosition.x, (int)textPosition.y);
spriteBatch.end();
3.GdxInvadersAndroid
@Override
public void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
config.useWakelock = true; //开启屏幕灯
initialize(new GdxInvaders(), config);
}
public class GdxInvaders implements ApplicationListener
@Override
public void render () {
Application app = Gdx.app;
// update the screen逻辑
screen.update(app);
// render the screen绘制
screen.render(app);
// when the screen is done we change to the
// next screen
if (screen.isDone()) {
// dispose the current screen
screen.dispose();
// if this screen is a main menu screen we switch to
// the game loop
if (screen instanceof MainMenu)
screen = new GameLoop(app);
else
// if this screen is a game loop screen we switch to the
// game over screen
if (screen instanceof GameLoop)
screen = new GameOver(app);
else
// if this screen is a game over screen we switch to the
// main menu screen
if (screen instanceof GameOver) screen = new MainMenu(app);
}
}
private final Sound explosion;
/** shot sound **/
private final Sound shot;
public GameLoop (Application app) {
simulation = new Simulation();
simulation.listener = this;
renderer = new Renderer(app);//渲染器
explosion = app.getAudio().newSound(app.getFiles().getFileHandle("data/explosion.ogg", FileType.Internal)); //获取声音
shot = app.getAudio().newSound(app.getFiles().getFileHandle("data/shot.ogg", FileType.Internal)); //获取声音
}
@Override
public void update (Application app) {
simulation.update(app.getGraphics().getDeltaTime());
//通过Input来获取键盘,触屏的状态
Input input = app.getInput();
if (input.getAccelerometerY() < 0)
simulation.moveShipLeft(app.getGraphics().getDeltaTime(), Math.abs(input.getAccelerometerY()) / 10);
else
simulation.moveShipRight(app.getGraphics().getDeltaTime(), Math.abs(input.getAccelerometerY()) / 10);
if (input.isKeyPressed(Keys.DPAD_LEFT)) simulation.moveShipLeft(app.getGraphics().getDeltaTime(), 0.5f);
if (input.isKeyPressed(Keys.DPAD_RIGHT)) simulation.moveShipRight(app.getGraphics().getDeltaTime(), 0.5f);
if (input.isTouched() || input.isKeyPressed(Keys.SPACE)) simulation.shot();
}
public void update (float delta) {
ship.update(delta);
updateInvaders(delta);
updateShots(delta);
updateExplosions(delta);
checkShipCollision();
checkInvaderCollision();
checkBlockCollision();
checkNextLevel();
}
public class Explosion {
public static final float EXPLOSION_LIVE_TIME = 1;
public float aliveTime = 0; //经过的时间
public final Vector3 position = new Vector3(); //位置
public Explosion (Vector3 position) {
this.position.set(position);
}
public void update (float delta) {
aliveTime += delta;
}
}
public class Invader {
public static float INVADER_RADIUS = 0.75f;
public static float INVADER_VELOCITY = 1;
public static int INVADER_POINTS = 40;
public final static int STATE_MOVE_LEFT = 0;
public final static int STATE_MOVE_DOWN = 1;
public final static int STATE_MOVE_RIGHT = 2;
public final Vector3 position = new Vector3(); //位置
public int state = STATE_MOVE_LEFT;
public boolean wasLastStateLeft = true;
public float movedDistance = Simulation.PLAYFIELD_MAX_X / 2;;
public Invader (Vector3 position) {
this.position.set(position);
}
public void update (float delta, float speedMultiplier) {
movedDistance += delta * INVADER_VELOCITY * speedMultiplier;
if (state == STATE_MOVE_LEFT) {
position.x -= delta * INVADER_VELOCITY * speedMultiplier;
if (movedDistance > Simulation.PLAYFIELD_MAX_X) {
state = STATE_MOVE_DOWN;
movedDistance = 0;
wasLastStateLeft = true;
}
}
if (state == STATE_MOVE_RIGHT) {
position.x += delta * INVADER_VELOCITY * speedMultiplier;
if (movedDistance > Simulation.PLAYFIELD_MAX_X) {
state = STATE_MOVE_DOWN;
movedDistance = 0;
wasLastStateLeft = false;
}
}
if (state == STATE_MOVE_DOWN) {
position.z += delta * INVADER_VELOCITY * speedMultiplier;
if (movedDistance > 1) {
if (wasLastStateLeft)
state = STATE_MOVE_RIGHT;
else
state = STATE_MOVE_LEFT;
movedDistance = 0;
}
}
}
}
@Override
public void render (Application app) {
app.getGraphics().getGL10().glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
renderer.render(app, simulation);
}
public class Renderer {
/** sprite batch to draw text **/
private SpriteBatch spriteBatch;
/** the ship mesh **/
private Mesh shipMesh;
/** the ship texture **/
private Texture shipTexture;
/** the invader mesh **/
private Mesh invaderMesh;
/** the invader texture **/
private Texture invaderTexture;
/** the block mesh **/
private Mesh blockMesh;
/** the shot mesh **/
private Mesh shotMesh;
/** the background texture **/
private Texture backgroundTexture;
/** the explosion mesh **/
private Mesh explosionMesh;
/** the explosion texture **/
private Texture explosionTexture;
/** the font **/
private BitmapFont font;
/** the rotation angle of all invaders around y **/
private float invaderAngle = 0;
/** status string **/
private String status = "";
/** keeping track of the last score so we don't constantly construct a new string **/
private int lastScore = 0;
private int lastLives = 0;
private int lastWave = 0;
/** view and transform matrix for text rendering **/
private Matrix4 viewMatrix = new Matrix4();
private Matrix4 transformMatrix = new Matrix4();
/** perspective camera **/
private PerspectiveCamera camera;
//给出了不少mesh