libgdx 分析

 

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值