Android Open Source - SevenWonders Seven Wonders G L Renderer






From Project

Back to project page SevenWonders.

License

The source code is released under:

Apache License

If you think the Android project SevenWonders listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package skylight1.sevenwonders.view;
//  w  ww  .j av a2s .  c o m
import static javax.microedition.khronos.opengles.GL10.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import skylight1.opengl.CollisionDetector;
import skylight1.opengl.CollisionDetector.CollisionObserver;
import skylight1.opengl.FastGeometryBuilder;
import skylight1.opengl.FastGeometryBuilderFactory;
import skylight1.opengl.GeometryBuilder;
import skylight1.opengl.GeometryBuilder.NormalizableTriangle3D;
import skylight1.opengl.GeometryBuilder.TexturableRectangle2D;
import skylight1.opengl.GeometryBuilder.TexturableTriangle3D;
import skylight1.opengl.OpenGLGeometry;
import skylight1.opengl.OpenGLGeometryBuilder;
import skylight1.opengl.OpenGLGeometryBuilderFactory;
import skylight1.opengl.Texture;
import skylight1.opengl.TransformingGeometryBuilder;
import skylight1.opengl.files.ObjFileLoader;
import skylight1.sevenwonders.GameState;
import skylight1.sevenwonders.PlayActivity;
import skylight1.sevenwonders.R;
import skylight1.sevenwonders.Settings;
import skylight1.sevenwonders.SevenWondersApplication;
import skylight1.sevenwonders.levels.CollisionAction;
import skylight1.sevenwonders.levels.GameLevel;
import skylight1.sevenwonders.levels.GameObjectDescriptor;
import skylight1.sevenwonders.services.SoundTracks;
import skylight1.sevenwonders.view.GameMessagesDisplay.GameEvent;
import skylight1.util.FPSLogger;
import android.content.Context;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLU;
import android.opengl.Matrix;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.FloatMath;
import android.util.Log;

public class SevenWondersGLRenderer implements Renderer {
  
  private boolean firstCollission = true;
  
  public static class CollisionActionToCollisionObserverAdapter implements CollisionObserver {
    private final List<OpenGLGeometry> listOfOpenGLGeometries;
    private final CollisionAction collisionAction;
    private SevenWondersGLRenderer sevenWondersGLRenderer;
    private Handler uiHandler;

    public CollisionActionToCollisionObserverAdapter(final List<OpenGLGeometry> aListOfOpenGLGeometries, final CollisionAction aCollisionAction, final SevenWondersGLRenderer aSevenWondersGLRenderer, final Handler aUiHandler) {
      listOfOpenGLGeometries = aListOfOpenGLGeometries;
      collisionAction = aCollisionAction;
      sevenWondersGLRenderer = aSevenWondersGLRenderer;
      uiHandler = aUiHandler;
    }
    
    @Override
    public boolean collisionOccurred(float[] aBoundingSphere) {
      // TODO do this early and cache it to be reused by all collectables with the same size
      
      // create a fast geometry that is out of sight
      final FastGeometryBuilder<?, ?> somewhereFarFarAway = FastGeometryBuilderFactory.createTexturableNormalizable(listOfOpenGLGeometries.get(0));
      // TODO there has to be a better way to make a correctly sized geometry, than to know it has 3 times as many
      // vertices as triangles
      for (int silly = 0; silly < listOfOpenGLGeometries.get(0).getNumberOfVerticies() / 3; silly++) {
        somewhereFarFarAway.add3DTriangle(0, 0, -100, 0, 0, -100, 0, 0, -100);
      }

      // iterate through all animation geometries, moving the objects off screen
      for (int spellAnimationIndex = 0; spellAnimationIndex < listOfOpenGLGeometries.size(); spellAnimationIndex++) {
        listOfOpenGLGeometries.get(spellAnimationIndex).updateModel(somewhereFarFarAway);
      }

      collisionAction.collision(uiHandler, sevenWondersGLRenderer);
      
      // suppress future collisions
      return true;
    }
  }

  static final float MAXIMUM_VELOCITY = 300f * 1000f / 60f / 60f / 1000f;

  // Used to reduce turning velocity, which was too high as the phone angle times the time delta alone.
  private static final int TURNING_VELOCITY_DIVISOR = 100;

  private static final String TAG = SevenWondersGLRenderer.class.getName();

  private static final int FRAMES_BETWEEN_LOGGING_FPS = 60;

  private static final float MINIMUM_VELOCITY = -MAXIMUM_VELOCITY / 10f;

  private static final int NUMBER_OF_SPINNING_ANIMATION_FRAMES = 16;

  private static final int PERIOD_FOR_SPINNING_ANIMATION_CYCLE = 1000;

  private static final OpenGLGeometryBuilder<GeometryBuilder.TexturableTriangle3D<GeometryBuilder.NormalizableTriangle3D<Object>>, GeometryBuilder.TexturableRectangle2D<Object>> openGLGeometryBuilder = OpenGLGeometryBuilderFactory.createTexturableNormalizable(96753);
  
  private final Context context;

  private FPSLogger fPSLogger = new FPSLogger(TAG, FRAMES_BETWEEN_LOGGING_FPS);

  private OpenGLGeometry[] allSpellsGeometry;
  
  private OpenGLGeometry[] allHazardsGeometry;

  private OpenGLGeometry skyboxGeometry;

  private long timeAtLastOnRenderCall;

  private final CollisionDetector gameObjectCollisionDetector = new CollisionDetector();

  private final CollisionDetector obstacleCollisionDetector = new CollisionDetector();
  
  private Carpet carpet;

  private List<OpenGLGeometry> decorationGeometries = new ArrayList<OpenGLGeometry>();

  private List<OpenGLGeometry> glowGeometries = new ArrayList<OpenGLGeometry>();
  
  private final Map<Integer, Texture> textureResourceIdToTextureMap = new HashMap<Integer, Texture>();

  private final Handler updateUiHandler;

  private final GameLevel level;

  private final float[] temporaryMatrix = new float[16];

  private float playerFacingThisFrame;

  private boolean paused;

  private Integer spellAnimationIndex;

  private Integer swordAnimationIndex;

  private float startOfFramePlayerWorldPositionX;

  private float startOfFramePlayerWorldPositionZ;

  private Settings settings;

  private final GameState gameState;
  
  public SevenWondersGLRenderer(final Context aContext, final Handler aUpdateUiHandler, final GameLevel aLevel, final GameState aGameState) {
    Log.i(TAG, "SevenWondersGLRenderer()");
    context = aContext;
    gameState = aGameState;
    carpet = new Carpet(this);
    level = aLevel;
    updateUiHandler = aUpdateUiHandler;

    settings = new Settings(aContext);
    
    openGLGeometryBuilder.reset();
    
    // load all of the decorations (land, water, sphinx, pyramids, etc.)
    addGeometriesFromGameObjects(decorationGeometries, level.getDecorations(), false);

    // load glows that brighten areas
    addGeometriesFromGameObjects(glowGeometries, level.getGlows(), true);
    
    openGLGeometryBuilder.startGeometry(getTexture(R.raw.skybox_texture, false));    
    loadRequiredObj(R.raw.skybox_model, openGLGeometryBuilder);
    skyboxGeometry = openGLGeometryBuilder.endGeometry();

    // add the collectables to the world geometry
    allSpellsGeometry = addObjectsToGeometry(openGLGeometryBuilder, level.getCollectables(), R.raw.textures);
    
    // add the hazards to the world geometry
    allHazardsGeometry = addObjectsToGeometry(openGLGeometryBuilder, level.getHazards(), R.raw.textures);
    
    // add the carpet
    carpet.createGeometry(openGLGeometryBuilder);

    // collision with an obstacle moves the player back to where
    // they were at the start of the frame, prior to any movement
    final CollisionObserver obstacleCollisionObserver = new CollisionObserver() {

      @Override
      public boolean collisionOccurred(final float[] aBoundingSphere) {
        // Return early without doing anything if the player has gained the ability to fly through obstacles.
        if ( gameState.isPlayerAbleToFlyThroughObstacles() ) {
          return false;
        }
        
          SoundTracks.getInstance().play(SoundTracks.BUMP);
          if(firstCollission) {
            GameMessagesDisplay.postMessage(GameEvent.COLLIDED_WITH_OBSTACLE);
            firstCollission = false;
          }
          // Find the distance traveled toward the pyramid.
        float initialOffsetToPyramidX = aBoundingSphere[0] - startOfFramePlayerWorldPositionX;
        float initialOffsetToPyramidZ = aBoundingSphere[2] - startOfFramePlayerWorldPositionZ;
        float collidingOffsetToPyramidX = aBoundingSphere[0] - gameState.playerWorldPosition.x;
        float collidingOffsetToPyramidZ = aBoundingSphere[2] - gameState.playerWorldPosition.z;
        float initialDistanceFromPyramid = Matrix.length(Math.abs(initialOffsetToPyramidX), 0, Math.abs(initialOffsetToPyramidZ));
        float collidingDistanceFromPyramid = Matrix.length(Math.abs(collidingOffsetToPyramidX), 0, Math.abs(collidingOffsetToPyramidZ));
        float distanceTraveledTowardPyramid = initialDistanceFromPyramid - collidingDistanceFromPyramid;

        // Find X offset to travel that distance away using same slope as if headed toward pyramid.
        float xToZ = initialOffsetToPyramidX / initialOffsetToPyramidZ;
        float slideAmountZ = FloatMath.sqrt(distanceTraveledTowardPyramid * distanceTraveledTowardPyramid / (xToZ * xToZ + 1));
        float slideOffsetZ = slideAmountZ * initialOffsetToPyramidZ / Math.abs(initialOffsetToPyramidZ);

        // Find Z offset to travel that distance away using same slope as if headed toward pyramid.
        float zToX = initialOffsetToPyramidZ / initialOffsetToPyramidX;
        float slideAmountX = FloatMath.sqrt(distanceTraveledTowardPyramid * distanceTraveledTowardPyramid / (zToX * zToX + 1));
        float slideOffsetX = slideAmountX * initialOffsetToPyramidX / Math.abs(initialOffsetToPyramidX);
        
        // Take where the player would have gone had he not collided
        // and subtract the distance traveled toward the pyramid. 
        // This should leave only the motion to the side of the pyramid.
        float playerSlidingPositionX = gameState.playerWorldPosition.x - slideOffsetX;
        float playerSlidingPositionZ = gameState.playerWorldPosition.z - slideOffsetZ;
        
        gameState.playerWorldPosition.x = playerSlidingPositionX;
        gameState.playerWorldPosition.z = playerSlidingPositionZ;
          
        // do not suppress future collisions
        return false;
      }
    };
    for (final float[] boundingSphere : level.getObstacles()) {
      obstacleCollisionDetector.addBoundingSphere(boundingSphere, obstacleCollisionObserver);
    }
  }

  private void addGeometriesFromGameObjects(final List<OpenGLGeometry> aDestinationGeometries,
      final Collection<GameObjectDescriptor> aGameObjects, final boolean aUseseparateGeometries) {
    int currentTextureResource = 0;
    for (GameObjectDescriptor objectDescriptor : aGameObjects) {
      // if the texture has changed (including the first time through), then ...
      if (aUseseparateGeometries || objectDescriptor.textureResource != currentTextureResource) {
        // wrap up the existing geometry (if any, since first time through there won't be an existing geometry)
        if (openGLGeometryBuilder.isBuildingGeometry()) {
          final OpenGLGeometry previousGeometry = openGLGeometryBuilder.endGeometry();
          aDestinationGeometries.add(previousGeometry);
        }
        
        currentTextureResource = objectDescriptor.textureResource;
        
        // create a new texture object, store it in the texture id to texture map,
        // and start a new geometry using the new texture
        final Texture texture = getTexture(objectDescriptor.textureResource, true);
        openGLGeometryBuilder.startGeometry(texture);
      }

      // load the object
      TransformingGeometryBuilder<GeometryBuilder.TexturableTriangle3D<GeometryBuilder.NormalizableTriangle3D<Object>>, GeometryBuilder.TexturableRectangle2D<Object>> transformingGeometryBuilder = new TransformingGeometryBuilder<TexturableTriangle3D<NormalizableTriangle3D<Object>>, TexturableRectangle2D<Object>>(openGLGeometryBuilder, objectDescriptor.coordinateTransformationMatrix, objectDescriptor.textureTransformationMatrix);
      loadRequiredObj(objectDescriptor.objectFileResourceId, transformingGeometryBuilder);
    }
    // wrap up the existing geometry (if any, since first time through there won't be an existing geometry)
    if (openGLGeometryBuilder.isBuildingGeometry()) {
      final OpenGLGeometry lastGeometry = openGLGeometryBuilder.endGeometry();
      aDestinationGeometries.add(lastGeometry);
    }
  }

  public void onSurfaceCreated(final GL10 aGl, final EGLConfig aConfig) {
    Log.i(TAG, "- onSurfaceCreated - ");

    openGLGeometryBuilder.enable(aGl);

    aGl.glColor4f(1, 1, 1, 1);
    aGl.glClearColor(0.5f, 0.5f, 1, 1.0f);

    // Don't draw inside facing surfaces on things like the pyramid and sphinx.
    // This fixes a z-fighting issue: At long distances OpenGL doesn't have enough precision in the depth buffer
    // to tell if the front is closer or if the inside of a nearby back surface is closer and gets it wrong some
    // times.
    aGl.glEnable(GL10.GL_CULL_FACE);
    aGl.glEnable(GL10.GL_DEPTH_TEST);
    aGl.glDisable(GL10.GL_BLEND);
    // Function for additive blending. Blending is only currently turned on for glows that add to the light of something.
    aGl.glBlendFunc(GL_ONE, GL_ONE);
    aGl.glShadeModel(GL10.GL_SMOOTH);
    aGl.glEnable(GL10.GL_LIGHTING);
    aGl.glLightModelfv(GL10.GL_LIGHT_MODEL_AMBIENT, new float[] { 0.75f, 0.75f, 0.75f, 1f }, 0);
    aGl.glEnable(GL10.GL_LIGHT0);
    aGl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, new float[] { -1f, 0f, 1f, 0.0f }, 0);
    aGl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, new float[] { 0.5f, 0.5f, 0.5f, 1f }, 0);

    aGl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, new float[] { 1.0f, 1.0f, 1.0f, 1.0f }, 0);
    aGl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, new float[] { 1.0f, 1.0f, 1.0f, 1.0f }, 0);
    aGl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, new float[] { 0.1f, 0.1f, 0.1f, 1.0f }, 0);
    aGl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SHININESS, new float[] { 50.0f }, 0);
  }

  private OpenGLGeometry[] addObjectsToGeometry(
      final OpenGLGeometryBuilder<TexturableTriangle3D<NormalizableTriangle3D<Object>>, TexturableRectangle2D<Object>> anOpenGLGeometryBuilder, 
      final Map<GameObjectDescriptor, CollisionAction> aMapOfObjectDescriptorsToCollisionActions,
      final int aTextureResource) {

    // return null quickly if there are no objects in the collection
    if (aMapOfObjectDescriptorsToCollisionActions.isEmpty()) {
      return null;
    }

    final Map<GameObjectDescriptor, List<OpenGLGeometry>> mapOfGameObjectDescriptorsToListOfOpenGLGeometries = new HashMap<GameObjectDescriptor, List<OpenGLGeometry>>();
    
    final Texture texture = getTexture(aTextureResource, true);

    final OpenGLGeometry[] objectGeometries = new OpenGLGeometry[NUMBER_OF_SPINNING_ANIMATION_FRAMES];

    final Map<Integer, ObjFileLoader> resourceIdToObjFileLoaderMap = new HashMap<Integer, ObjFileLoader>();

    // create a number of objects, in a number of orientations
    float[] coordinateTransform = new float[16];
    for (int animationIndex = 0; animationIndex < NUMBER_OF_SPINNING_ANIMATION_FRAMES; animationIndex++) {
      anOpenGLGeometryBuilder.startGeometry(texture);

      int objectIndex = 0;
      for (final GameObjectDescriptor objectDescriptor : aMapOfObjectDescriptorsToCollisionActions.keySet()) {
        final int objectFileResourceId = objectDescriptor.objectFileResourceId;
        ObjFileLoader objFileLoader = resourceIdToObjFileLoaderMap.get(objectFileResourceId);
        if (objFileLoader == null) {
          try {
            objFileLoader = new ObjFileLoader(context, objectFileResourceId);
          } catch (IOException e) {
            throw new RuntimeException("could not load file", e);
          }
          resourceIdToObjFileLoaderMap.put(objectFileResourceId, objFileLoader);
        }
        anOpenGLGeometryBuilder.startGeometry(texture);
        
        System.arraycopy(objectDescriptor.coordinateTransformationMatrix, 0, coordinateTransform, 0, coordinateTransform.length);

        Matrix.rotateM(coordinateTransform, 0, 360f * (float) animationIndex
            / (float) NUMBER_OF_SPINNING_ANIMATION_FRAMES, 0, 1, 0);
        // this final rotate is to "stand up" the ankh
        Matrix.rotateM(coordinateTransform, 0, -90f, 1, 0, 0);

        // load the object into the geometry
        TransformingGeometryBuilder<TexturableTriangle3D<NormalizableTriangle3D<Object>>, TexturableRectangle2D<Object>> transformingGeometryBuilder = new TransformingGeometryBuilder<TexturableTriangle3D<NormalizableTriangle3D<Object>>, TexturableRectangle2D<Object>>(anOpenGLGeometryBuilder, coordinateTransform, objectDescriptor.textureTransformationMatrix);
        objFileLoader.createGeometry(transformingGeometryBuilder);
        final OpenGLGeometry objectGeometry = anOpenGLGeometryBuilder.endGeometry();

        final List<OpenGLGeometry> listOfOpenGLGeometries;
        if (mapOfGameObjectDescriptorsToListOfOpenGLGeometries.containsKey(objectDescriptor)) {
          listOfOpenGLGeometries = mapOfGameObjectDescriptorsToListOfOpenGLGeometries.get(objectDescriptor);
        } else {
          listOfOpenGLGeometries = new ArrayList<OpenGLGeometry>();
          mapOfGameObjectDescriptorsToListOfOpenGLGeometries.put(objectDescriptor, listOfOpenGLGeometries);
        }
        listOfOpenGLGeometries.add(objectGeometry);
        
        // next object
        objectIndex++;
      }
      objectGeometries[animationIndex] = anOpenGLGeometryBuilder.endGeometry();
    }

    // create collision observers and add them for the objects
    for (final Map.Entry<GameObjectDescriptor, List<OpenGLGeometry>> entry : mapOfGameObjectDescriptorsToListOfOpenGLGeometries.entrySet()) {
      final List<OpenGLGeometry> listOfOpenGLGeometries = entry.getValue();
      final CollisionActionToCollisionObserverAdapter adapter = new CollisionActionToCollisionObserverAdapter(listOfOpenGLGeometries, aMapOfObjectDescriptorsToCollisionActions.get(entry.getKey()), this, updateUiHandler);
      gameObjectCollisionDetector.addBoundingSphere(listOfOpenGLGeometries.get(0).getBoundingSphere(), adapter);
    }
    
    return objectGeometries;
  }

  void loadRequiredObj(
      final int aObjId,
      final GeometryBuilder<GeometryBuilder.TexturableTriangle3D<GeometryBuilder.NormalizableTriangle3D<Object>>, GeometryBuilder.TexturableRectangle2D<Object>> aBuilder) {
    final ObjFileLoader loader;
    try {
      loader = new ObjFileLoader(context, aObjId);
    } catch (IOException e) {
      throw new RuntimeException("Error loading required geometry from OBJ file:" + aObjId, e);
    }
    loader.createGeometry(aBuilder);
  }

  public void onSurfaceChanged(final GL10 aGl, final int aW, final int aH) {
    aGl.glMatrixMode(GL10.GL_PROJECTION);
    aGl.glLoadIdentity();
    aGl.glViewport(0, 0, aW, aH);
    GLU.gluPerspective(aGl, 45, (float) aW / (float) aH, 0.25f, 4000.0f);

    aGl.glMatrixMode(GL10.GL_MODELVIEW);
    
    // load all of the used textures
    for (Texture texture : textureResourceIdToTextureMap.values()) {
      texture.load(aGl);
    }

    updateUiHandler.sendEmptyMessage(PlayActivity.START_RENDERING_MESSAGE);
  }
  
  Texture getTexture(final int aResource, final boolean aUsesMipMaps) {
    final Texture texture;
    if (textureResourceIdToTextureMap.containsKey(aResource)) {
      texture = textureResourceIdToTextureMap.get(aResource);
    } else {
      texture = new Texture(context, aResource, aUsesMipMaps);
      textureResourceIdToTextureMap.put(aResource, texture);
    }
    return texture;
  }
  
  public void onDrawFrame(final GL10 aGl) {
    aGl.glClear(GL10.GL_DEPTH_BUFFER_BIT);
    
    final long timeDeltaMS = calculateTimeSinceLastRenderMillis();
    float turnAmountFromTurningVelocity = gameState.turningVelocity * timeDeltaMS / TURNING_VELOCITY_DIVISOR;
    turn(turnAmountFromTurningVelocity);
    
    playerFacingThisFrame = gameState.playerFacing;
    
    drawCarpet(aGl);

    //Bank the world if we are turning.
    float worldAngle = carpet.getWorldAngle();
    aGl.glPushMatrix();    
    aGl.glRotatef(worldAngle, 0f, 0f, 1f);
    drawSkybox(aGl, worldAngle);
        
    applyMovement(aGl, timeDeltaMS);
    detectCollisions();

    drawSpells(aGl);    
    drawSwords(aGl);

    for (int geometryIndex = 0; geometryIndex < decorationGeometries.size(); geometryIndex++) {
      final OpenGLGeometry geometry = decorationGeometries.get(geometryIndex);
      geometry.draw(aGl);
    }

    drawGlows(aGl);

    aGl.glPopMatrix();

    if (SevenWondersApplication.isDebug) {
      if (settings.isDebugEnabled()) {
        Message msg = updateUiHandler.obtainMessage(PlayActivity.FPS_MESSAGE, fPSLogger.frameRendered(), 0);
        updateUiHandler.sendMessage(msg);
      }
    }
  }

  private void drawGlows(final GL10 aGl) {
    // Blend function is set to additive blending at init time, which adds light, not obscures
    aGl.glEnable(GL10.GL_BLEND);
    for (int geometryIndex = 0; geometryIndex < glowGeometries.size(); geometryIndex++) {
      final OpenGLGeometry geometry = glowGeometries.get(geometryIndex);
      if ( null != geometry ) {
        geometry.draw(aGl);
      }
    }
    aGl.glDisable(GL10.GL_BLEND);
  }

  private void drawCarpet(final GL10 aGl) {
    // Carpet drawn with no transformations, always right in front of the screen.
    aGl.glLoadIdentity();
    // Drawn first for performance, might occlude other geometry, which OpenGL can then skip.
    // XXX Hack to fix the carpet being drawn face down. Should probably change geometry or disable culling for the
    // carpet instead.
    aGl.glFrontFace(GL_CW);

    carpet.draw(aGl, paused);

    aGl.glFrontFace(GL_CCW);
  }

  private void drawSkybox(GL10 aGl, float worldAngle) {  
    // save the current matrix for later - later? what later?
    aGl.glPushMatrix();

    // rotate the skybox to match the player's facing
    aGl.glRotatef(playerFacingThisFrame, 0f, 1f, 0f);
    aGl.glDisable(GL10.GL_LIGHTING);

    skyboxGeometry.draw(aGl);
    
     aGl.glEnable(GL10.GL_LIGHTING);
    
    // restore the matrix
    aGl.glPopMatrix();
  }  

  private void detectCollisions() {
    float[] carpetBoundingBox = temporaryMatrix;
    // TODO should we use Matrix.orthoM()
    Matrix.frustumM(carpetBoundingBox, 0, -0.3f, 0.3f, GameState.HEIGHT_OF_CARPET_FROM_GROUND, GameState.HEIGHT_OF_CARPET_FROM_GROUND + 2f, 0.1f, 1f);

    // Rotate first, otherwise map rotates around center point we translated away from.
    Matrix.rotateM(carpetBoundingBox, 0, playerFacingThisFrame, 0, 1, 0);
    Matrix.translateM(carpetBoundingBox, 0, -gameState.playerWorldPosition.x, -gameState.playerWorldPosition.y, -gameState.playerWorldPosition.z);

    if(!paused) {
      gameObjectCollisionDetector.detectCollisions(carpetBoundingBox);
    }
  }

  private void applyMovement(final GL10 aGl, final long aTimeDeltaMS) {  
    // keep the old position in case a collision with an obstacle requires a "movement rollback"
    startOfFramePlayerWorldPositionX = gameState.playerWorldPosition.x;
    startOfFramePlayerWorldPositionZ = gameState.playerWorldPosition.z;

    final float facingX = (float) Math.sin(playerFacingThisFrame / 180f * Math.PI);
    final float facingZ = -(float) Math.cos(playerFacingThisFrame / 180f * Math.PI);

    if ( !paused ) {
      final float newPositionX = gameState.playerWorldPosition.x + facingX * gameState.velocity * aTimeDeltaMS;
      final float newPositionZ = gameState.playerWorldPosition.z + facingZ * gameState.velocity * aTimeDeltaMS;
  
      boolean isAtEndOfWorld = false;
      // Only update the position if it isn't too far from the end of the world.
      if (newPositionX > (CubeBounds.TERRAIN.x1)
          && newPositionX < (CubeBounds.TERRAIN.x2)) {
        gameState.playerWorldPosition.x = newPositionX;
      } else {
          isAtEndOfWorld = true;
      }
  
      if (newPositionZ > (CubeBounds.TERRAIN.z1)
          && newPositionZ < (CubeBounds.TERRAIN.z2)) {
        gameState.playerWorldPosition.z = newPositionZ;
      } else {
          isAtEndOfWorld = true;
      }
      
      if (isAtEndOfWorld) {
        SoundTracks.getInstance().play(SoundTracks.BUMP);
        GameMessagesDisplay.postMessage(GameEvent.END_OF_WORLD_REACHED);
      }
     }

    checkForCollisionsWithObstacles();

    GLU.gluLookAt(aGl, gameState.playerWorldPosition.x, GameState.HEIGHT_OF_CARPET_FROM_GROUND, 
      gameState.playerWorldPosition.z, gameState.playerWorldPosition.x
        + facingX, GameState.HEIGHT_OF_CARPET_FROM_GROUND, gameState.playerWorldPosition.z + facingZ, 0f, 1f, 0f);
  }

  private void checkForCollisionsWithObstacles() {
    float[] centerOfCarpet = temporaryMatrix;
    // a single point only, otherwise turning away from collisions is problematic
    Matrix.frustumM(centerOfCarpet, 0, -0.001f, 0.001f, GameState.HEIGHT_OF_CARPET_FROM_GROUND, GameState.HEIGHT_OF_CARPET_FROM_GROUND+0.001f, 0.001f, 0.002f);

    // Rotate first, otherwise map rotates around center point we translated away from.
    Matrix.rotateM(centerOfCarpet, 0, playerFacingThisFrame, 0, 1, 0);
    Matrix.translateM(centerOfCarpet, 0, 
      -gameState.playerWorldPosition.x, -gameState.playerWorldPosition.y, -gameState.playerWorldPosition.z);

    obstacleCollisionDetector.detectCollisions(centerOfCarpet);
  }

  private long calculateTimeSinceLastRenderMillis() {
    final long now = SystemClock.uptimeMillis();
    if (timeAtLastOnRenderCall == 0) {
      timeAtLastOnRenderCall = now;
    }

    final long timeDeltaMS = now - timeAtLastOnRenderCall;
    timeAtLastOnRenderCall = now;
    return timeDeltaMS;
  }

  private void drawSpells(final GL10 aGl) {
    if ( !paused || null == spellAnimationIndex ) {
      spellAnimationIndex = (int) ((float) (SystemClock.uptimeMillis() % PERIOD_FOR_SPINNING_ANIMATION_CYCLE)
          / (float) PERIOD_FOR_SPINNING_ANIMATION_CYCLE * (float) NUMBER_OF_SPINNING_ANIMATION_FRAMES);
    }
    allSpellsGeometry[spellAnimationIndex].draw(aGl);
  }

  private void drawSwords(final GL10 aGl) {
    if ( !paused || null == swordAnimationIndex ) {
      swordAnimationIndex = (int) ((float) (SystemClock.uptimeMillis() % PERIOD_FOR_SPINNING_ANIMATION_CYCLE)
          / (float) PERIOD_FOR_SPINNING_ANIMATION_CYCLE * (float) NUMBER_OF_SPINNING_ANIMATION_FRAMES);
    }
    if (allHazardsGeometry != null) {
      allHazardsGeometry[swordAnimationIndex].draw(aGl);
    }
  }

  public synchronized void setPlayerVelocity(final int aNewVelocity) {
    if ( paused ) {
      return;
    }
    gameState.velocity = aNewVelocity;
  }

  public synchronized void turn(final float anAngleOfTurn) {
    if ( paused ) {
      return;
    }
    gameState.playerFacing += anAngleOfTurn;
    carpet.recordTurnAngle(anAngleOfTurn);
  }

  public synchronized void setTurningVelocity(final float aTurningVelocity) {
    if ( paused ) {
      return;
    }
    gameState.turningVelocity = aTurningVelocity;
  }

  public synchronized void setPlayerFacing(final float anAngleAbosulte) {
    if ( paused ) {
      return;
    }
    gameState.playerFacing = anAngleAbosulte;
  }

  public synchronized void changeVelocity(final float aVelocityIncrement) {
    if ( paused ) {
      return;
    }
    gameState.velocity = Math.min(MAXIMUM_VELOCITY, 
      Math.max(MINIMUM_VELOCITY, gameState.velocity + aVelocityIncrement));
  }

  public synchronized void setVelocity(final float aVelocity) {
    if ( paused ) {
      return;
    }
    gameState.velocity = Math.min(MAXIMUM_VELOCITY, Math.max(MINIMUM_VELOCITY, aVelocity));
  }

  public synchronized void togglePaused() {
    paused = !paused;
  }

  /**
   * Sets the player's velocity via a percentage of the maximum velocity. This prevents calling code from having to
   * understand the actual velocity maximum when calculating a new velocity to set due to the player using the
   * controls.
   * 
   * @param aPercent
   *            float percent from -1 to 1
   */
  public void setVelocityPercent(final float aPercent) {
    if ( paused ) {
      return;
    }
    final float newVelocity = aPercent < 0 ? MINIMUM_VELOCITY * aPercent : MAXIMUM_VELOCITY * aPercent;
    gameState.velocity = constrainVelocity(newVelocity);
  }

  /**
   * Constrains a candidate velocity to an allowed velocity range.
   * 
   * @param aCandidateVelocity
   *            float candidate velocity in meters per second
   * @return allowable velocity
   */
  private float constrainVelocity(final float aCandidateVelocity) {
    return aCandidateVelocity < MINIMUM_VELOCITY ? MINIMUM_VELOCITY
        : aCandidateVelocity > MAXIMUM_VELOCITY ? MAXIMUM_VELOCITY : aCandidateVelocity;
  }
  
  public GameState getGameState() {
    return gameState;
  }

  public void hideGlowAt(final int aGlowIndex) {
    glowGeometries.set(aGlowIndex, null);
  }
}




Java Source Code List

com.facebook.android.AsyncFacebookRunner.java
com.facebook.android.DialogError.java
com.facebook.android.FacebookError.java
com.facebook.android.Facebook.java
com.facebook.android.FbDialog.java
com.facebook.android.Util.java
skylight1.sevenwonders.AboutActivity.java
skylight1.sevenwonders.Adverts.java
skylight1.sevenwonders.Analytics.java
skylight1.sevenwonders.GameState.java
skylight1.sevenwonders.LevelChooserActivity.java
skylight1.sevenwonders.MenuActivity.java
skylight1.sevenwonders.PlayActivity.java
skylight1.sevenwonders.ScoreActivity.java
skylight1.sevenwonders.SettingsActivity.java
skylight1.sevenwonders.Settings.java
skylight1.sevenwonders.SevenWondersApplication.java
skylight1.sevenwonders.SoundTracksStoppingExceptionHandler.java
skylight1.sevenwonders.SplashActivity.java
skylight1.sevenwonders.StoryActivity.java
skylight1.sevenwonders.levels.CoinCollisionAction.java
skylight1.sevenwonders.levels.CollisionAction.java
skylight1.sevenwonders.levels.ExtraTimeAction.java
skylight1.sevenwonders.levels.GameLevel.java
skylight1.sevenwonders.levels.GameObjectDescriptor.java
skylight1.sevenwonders.levels.HazardCollisionAction.java
skylight1.sevenwonders.levels.LevelConstructionToolkit.java
skylight1.sevenwonders.levels.ProtectionAction.java
skylight1.sevenwonders.levels.RubyCollisionAction.java
skylight1.sevenwonders.levels.SpellCollisionAction.java
skylight1.sevenwonders.services.SoundTracks.java
skylight1.sevenwonders.social.DialogUtil.java
skylight1.sevenwonders.social.NoNPEWebView.java
skylight1.sevenwonders.social.facebook.FacebookApplicationPost.java
skylight1.sevenwonders.social.facebook.FacebookConfig.java
skylight1.sevenwonders.social.facebook.FacebookScoreActivity.java
skylight1.sevenwonders.social.facebook.FacebookUtil.java
skylight1.sevenwonders.social.facebook.LoginAndGetPermissions.java
skylight1.sevenwonders.social.facebook.SessionStore.java
skylight1.sevenwonders.social.facebook.WallPost.java
skylight1.sevenwonders.social.twitter.AuthRequest.java
skylight1.sevenwonders.social.twitter.AuthStore.java
skylight1.sevenwonders.social.twitter.TwitterUpdater.java
skylight1.sevenwonders.view.Carpet.java
skylight1.sevenwonders.view.CubeBounds.java
skylight1.sevenwonders.view.GameMessagesDisplay.java
skylight1.sevenwonders.view.GameTexture.java
skylight1.sevenwonders.view.Position.java
skylight1.sevenwonders.view.SevenWondersGLRenderer.java
skylight1.sevenwonders.view.SevenWondersGLSurfaceView.java
skylight1.sevenwonders.view.StoryPagesController.java
skylight1.sevenwonders.view.StyledSpannableStringBuilder.java
skylight1.sevenwonders.view.TextStyles.java
skylight1.sevenwonders.view.TiltControl.java
wave.Constants.java
wave.CreateWave.java
wave.RectangleWave.java
wave.TriangleWave.java
wave.UtilsWave.java
wave.VertexWave.java