[alienbloodbath commit] r102 - Revamped the content loading code for shorter loading times. The game now requires the API...

8 views
Skip to first unread message

codesite...@google.com

unread,
May 23, 2009, 7:09:06 PM5/23/09
to alien-blood-b...@googlegroups.com
Author: matt.burkhart
Date: Sat May 23 16:08:22 2009
New Revision: 102

Added:
trunk/assets/
trunk/assets/avatar.animated
trunk/assets/avatar.png
- copied, changed from r101, /trunk/content_package/avatar.png
trunk/assets/avatar_damage.mp3 (props changed)
- copied unchanged from r98, /trunk/content_package/avatar_damage.mp3
trunk/assets/avatar_death.mp3 (props changed)
- copied unchanged from r98, /trunk/content_package/avatar_death.mp3
trunk/assets/avatar_jump.mp3 (props changed)
- copied unchanged from r98, /trunk/content_package/avatar_jump.mp3
trunk/assets/avatar_win.mp3 (props changed)
- copied unchanged from r98, /trunk/content_package/avatar_win.mp3
trunk/assets/enemy_death.mp3 (props changed)
- copied unchanged from r98, /trunk/content_package/enemy_death.mp3
trunk/assets/explosion.mp3 (props changed)
- copied unchanged from r98, /trunk/content_package/explosion.mp3
trunk/assets/help.htm
trunk/assets/misc.png
- copied, changed from r99, /trunk/content_package/misc.png
trunk/generate_epoch.sh (contents, props changed)
- copied, changed from r98, /trunk/prepare_content.sh
trunk/res/drawable/help.png (contents, props changed)
trunk/src/android/com/abb/AnimatedEntity.java
trunk/src/android/com/abb/Grappling.java
Removed:
trunk/content_package/
trunk/prepare_content.sh
trunk/res/raw/
Modified:
trunk/AndroidManifest.xml
trunk/create_demo.sh
trunk/default.properties
trunk/install.sh
trunk/res/drawable/avatar.png
trunk/res/drawable/maps.png
trunk/res/drawable/settings.png
trunk/res/layout/level_select_main.xml
trunk/src/android/com/abb/AlienBloodBathMain.java
trunk/src/android/com/abb/ArticulatedEntity.java
trunk/src/android/com/abb/Avatar.java
trunk/src/android/com/abb/Content.java
trunk/src/android/com/abb/Enemy.java
trunk/src/android/com/abb/Entity.java
trunk/src/android/com/abb/GameState.java
trunk/src/android/com/abb/GameView.java
trunk/src/android/com/abb/Graphics.java
trunk/src/android/com/abb/LevelSelectActivity.java
trunk/src/android/com/abb/Map.java
trunk/src/android/com/abb/Weapon.java

Log:
Revamped the content loading code for shorter loading times. The game now
requires the API and platform 3 (version 1.5). Improved level rendering
speed by rendering more tiles with fewer OpenGL calls. Reverted to sprites
for drawing the avatar instead of an articulated body for performance
reasons. Improved touch controls, added click to shoot. Added a help tab to
the level selection screen.

Modified: trunk/AndroidManifest.xml
==============================================================================
--- trunk/AndroidManifest.xml (original)
+++ trunk/AndroidManifest.xml Sat May 23 16:08:22 2009
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.com.abb"
- android:versionCode="9"
- android:versionName="2.1.3">
+ android:versionCode="10"
+ android:versionName="2.2.0">

- <uses-sdk android:minSdkVersion="1" />
+ <uses-sdk android:minSdkVersion="2" />

<uses-permission android:name="android.permission.VIBRATE" />


Added: trunk/assets/avatar.animated
==============================================================================
--- (empty file)
+++ trunk/assets/avatar.animated Sat May 23 16:08:22 2009
@@ -0,0 +1,5 @@
+avatar.png
+standing 0 0 48 48 1 1
+running 0 48 48 48 3 20
+shoot_up 0 192 48 48 1 1
+jumping 0 240 48 48 4 20

Copied: trunk/assets/avatar.png (from r101,
/trunk/content_package/avatar.png)
==============================================================================
Binary files. No diff available.

Added: trunk/assets/help.htm
==============================================================================
--- (empty file)
+++ trunk/assets/help.htm Sat May 23 16:08:22 2009
@@ -0,0 +1,12 @@
+<p>
+Kill the aliens! Use the touch-screen for control by touching the lower
portion
+of the screen. The left section moves left, the middle section jumps, the
right
+section movies right. Click on the screen, above the movement controls to
shoot
+in that direction.
+</p>
+
+<p>
+For more information, or to download the source code,
+visit: <a href="http://code.google.com/p/alienbloodbath">
+http://code.google.com/p/alienbloodbath</a>.
+</p>

Copied: trunk/assets/misc.png (from r99, /trunk/content_package/misc.png)
==============================================================================
Binary files. No diff available.

Modified: trunk/create_demo.sh
==============================================================================
--- trunk/create_demo.sh (original)
+++ trunk/create_demo.sh Sat May 23 16:08:22 2009
@@ -1,41 +1,41 @@
#!/bin/bash

-rm -rf content_package/Demo
-mkdir content_package/Demo
+rm -rf assets/Demo
+mkdir assets/Demo

-cp content_package/The_Second_Wave/ak47.*
content_package/Demo/
-cp content_package/The_Second_Wave/aug.*
content_package/Demo/
-cp content_package/The_Second_Wave/flamethrower.*
content_package/Demo/
-
-cp content_package/The_Second_Wave/hopper.*
content_package/Demo/
-cp content_package/The_Second_Wave/big_hopper.*
content_package/Demo/
-cp content_package/The_Second_Wave/slimer.*
content_package/Demo/
-cp content_package/The_Second_Wave/fast_slimer.*
content_package/Demo/
-
-cp content_package/The_Second_Wave/background_industrial.jpg
content_package/Demo/
-cp content_package/The_Second_Wave/background_forest.jpg
content_package/Demo/
-cp content_package/The_Second_Wave/background_stars.jpg
content_package/Demo/
-
-cp content_package/The_Second_Wave/tiles_industrial.png
content_package/Demo/
-cp content_package/The_Second_Wave/tiles_forest.png
content_package/Demo/
-
-cp content_package/The_Second_Wave/level_0.txt
content_package/Demo/
-cp content_package/The_Second_Wave/level_1.txt
content_package/Demo/
-cp content_package/The_Second_Wave/level_2.txt
content_package/Demo/
-cp content_package/The_Second_Wave/level_3.txt
content_package/Demo/
-cp content_package/The_Second_Wave/level_4.txt
content_package/Demo/
-
-cp content_package/The_Second_Wave/description_0.txt
content_package/Demo/
-cp content_package/The_Second_Wave/description_1.txt
content_package/Demo/
-cp content_package/The_Second_Wave/description_2.txt
content_package/Demo/
-cp content_package/The_Second_Wave/description_3.txt
content_package/Demo/
-cp content_package/The_Second_Wave/description_4.txt
content_package/Demo/
-
-cp content_package/The_Second_Wave/tiles_default.txt
content_package/Demo/
-cp content_package/The_Second_Wave/tiles_2.txt
content_package/Demo/
-cp content_package/The_Second_Wave/tiles_3.txt
content_package/Demo/
-cp content_package/The_Second_Wave/tiles_4.txt
content_package/Demo/
-
-cp content_package/The_Second_Wave/effects_default.txt
content_package/Demo/
-cp content_package/The_Second_Wave/effects_2.txt
content_package/Demo/
-cp content_package/The_Second_Wave/effects_3.txt
content_package/Demo/
+cp assets/The_Second_Wave/ak47.* assets/Demo/
+cp assets/The_Second_Wave/aug.* assets/Demo/
+cp assets/The_Second_Wave/flamethrower.* assets/Demo/
+
+cp assets/The_Second_Wave/hopper.* assets/Demo/
+cp assets/The_Second_Wave/big_hopper.* assets/Demo/
+cp assets/The_Second_Wave/slimer.* assets/Demo/
+cp assets/The_Second_Wave/fast_slimer.* assets/Demo/
+
+cp assets/The_Second_Wave/background_industrial.jpg assets/Demo/
+cp assets/The_Second_Wave/background_forest.jpg assets/Demo/
+cp assets/The_Second_Wave/background_stars.jpg assets/Demo/
+
+cp assets/The_Second_Wave/tiles_industrial.png assets/Demo/
+cp assets/The_Second_Wave/tiles_forest.png assets/Demo/
+
+cp assets/The_Second_Wave/level_0.txt assets/Demo/
+cp assets/The_Second_Wave/level_1.txt assets/Demo/
+cp assets/The_Second_Wave/level_2.txt assets/Demo/
+cp assets/The_Second_Wave/level_3.txt assets/Demo/
+cp assets/The_Second_Wave/level_4.txt assets/Demo/
+
+cp assets/The_Second_Wave/description_0.txt assets/Demo/
+cp assets/The_Second_Wave/description_1.txt assets/Demo/
+cp assets/The_Second_Wave/description_2.txt assets/Demo/
+cp assets/The_Second_Wave/description_3.txt assets/Demo/
+cp assets/The_Second_Wave/description_4.txt assets/Demo/
+
+cp assets/The_Second_Wave/tiles_default.txt assets/Demo/
+cp assets/The_Second_Wave/tiles_2.txt assets/Demo/
+cp assets/The_Second_Wave/tiles_3.txt assets/Demo/
+cp assets/The_Second_Wave/tiles_4.txt assets/Demo/
+
+cp assets/The_Second_Wave/effects_default.txt assets/Demo/
+cp assets/The_Second_Wave/effects_2.txt assets/Demo/
+cp assets/The_Second_Wave/effects_3.txt assets/Demo/

Modified: trunk/default.properties
==============================================================================
--- trunk/default.properties (original)
+++ trunk/default.properties Sat May 23 16:08:22 2009
@@ -8,4 +8,4 @@
# project structure.

# Project target.
-target=android-2
+target=Google Inc.:Google APIs:3

Copied: trunk/generate_epoch.sh (from r98, /trunk/prepare_content.sh)
==============================================================================
--- /trunk/prepare_content.sh (original)
+++ trunk/generate_epoch.sh Sat May 23 16:08:22 2009
@@ -2,15 +2,9 @@

./create_demo.sh

-TARGET="res/raw/content_package.zip"
-EPOCH="content_package/epoch.txt"
+EPOCH="assets/epoch.txt"

-ALL_FILES=`find -L content_package | grep -v \~ | grep -v \.svn | grep -v
\.drop`
-DEMO_FILES=`find -L content_package | grep -v \~ | grep -v \.svn | grep -v
\.drop | grep -v Classic | grep -v The_Second_Wave`
+ALL_FILES=`find -L assets | grep -v \~ | grep -v \.svn | grep -v \.drop`

-CONTENT_FILES=$ALL_FILES
-
-rm $TARGET
rm $EPOCH
-cat $CONTENT_FILES | sha1sum > $EPOCH
-zip $TARGET $CONTENT_FILES $EPOCH
+cat $ALL_FILES | sha1sum > $EPOCH

Modified: trunk/install.sh
==============================================================================
--- trunk/install.sh (original)
+++ trunk/install.sh Sat May 23 16:08:22 2009
@@ -1,5 +1,10 @@
#!/bin/bash

-./prepare_content.sh
+echo "Generating the content epoch..."
+./generate_epoch.sh

+echo "Cleaning build..."
+rm -rf bin
+
+echo "Installing..."
ant reinstall

Modified: trunk/res/drawable/avatar.png
==============================================================================
Binary files. No diff available.

Added: trunk/res/drawable/help.png
==============================================================================
Binary file. No diff available.

Modified: trunk/res/drawable/maps.png
==============================================================================
Binary files. No diff available.

Modified: trunk/res/drawable/settings.png
==============================================================================
Binary files. No diff available.

Modified: trunk/res/layout/level_select_main.xml
==============================================================================
--- trunk/res/layout/level_select_main.xml (original)
+++ trunk/res/layout/level_select_main.xml Sat May 23 16:08:22 2009
@@ -29,6 +29,10 @@
android:id="@+id/settingsview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
+ <WebView
+ android:id="@+id/helpview"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" />
</FrameLayout>
</LinearLayout>


Modified: trunk/src/android/com/abb/AlienBloodBathMain.java
==============================================================================
--- trunk/src/android/com/abb/AlienBloodBathMain.java (original)
+++ trunk/src/android/com/abb/AlienBloodBathMain.java Sat May 23 16:08:22
2009
@@ -28,7 +28,8 @@
@Override
public void onCreate(Bundle saved_instance_state) {
super.onCreate(saved_instance_state);
- Content.initialize(getResources());
+ Content.initialize(this);
+
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
@@ -74,9 +75,6 @@
public void onSaveInstanceState(Bundle saved_instance_state) {
saved_instance_state.putBundle("mGameState",
mGameState.saveStateBundle());
super.onSaveInstanceState(saved_instance_state);
-
- // Clean up any temporary files used by the content management library.
- Content.cleanup();
}

@Override

Added: trunk/src/android/com/abb/AnimatedEntity.java
==============================================================================
--- (empty file)
+++ trunk/src/android/com/abb/AnimatedEntity.java Sat May 23 16:08:22 2009
@@ -0,0 +1,129 @@
+// Copyright 2008 and onwards Matthew Burkhart.
+//
+// This program is free software; you can redistribute it and/or modify it
under
+// the terms of the GNU General Public License as published by the Free
Software
+// Foundation; version 3 of the License.
+//
+// This program is distributed in the hope that it will be useful, but
WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+// details.
+
+package android.com.abb;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.util.Log;
+import java.util.TreeMap;
+import junit.framework.Assert;
+
+
+/** An AnimatedEntity is a functional replacement to an Entity instance. It
+ * represents a single drawable, physical game object. The AnimatedEntity
class
+ * provides, on top of Entity, the selection and drawing of frames from a
single
+ * image file. */
+public class AnimatedEntity extends Entity {
+ public AnimatedEntity() {
+ super();
+ }
+
+ @Override
+ public Object clone() {
+ return super.clone();
+ }
+
+ public void loadFromUri(Uri uri) {
+ // The file at the specified path is expected to contain an image name
+ // followed by a series of animation sequence specifications. The file
+ // format is expected to be an ASCII text file laid out with a single
+ // animation sequence line. The first line specifies the image file
name
+ // containing the animation frames (animations proceed down the
image). Each
+ // line after the first must be of the format "<animation name> <start
x>
+ // <start y> <frame width> <frame height> <frame count> <frame rate>".
+ //
+ // For example:
+ // entity.png
+ // stand 0 0 64 64 1 1
+ // run 0 64 64 64 3 20
+ String file_path = Content.getFilePath(uri);
+ String[] tokens = Content.readFileTokens(file_path);
+
+ final int kLineTokenCount = 7;
+ Assert.assertTrue("Animated entity file empty.", tokens.length > 1);
+ Assert.assertEquals("Animated entity file improperly formatted.",
+ (tokens.length - 1) % kLineTokenCount, 0);
+
+ // Path names are expected to be relative to the path specified for the
+ // animation definition file.
+ String uri_string = uri.toString();
+ Log.d("AnimatedEntity::loadFromUri", "Found uri= " + uri_string);
+ String base_uri_string = uri_string.substring(0,
uri_string.lastIndexOf("/"));
+ mImageUri = Uri.parse(base_uri_string + "/" + tokens[0]);
+
+ for (int index = 1; index < tokens.length; index += kLineTokenCount) {
+ Animation animation = new Animation();
+ animation.start_x = Integer.parseInt(tokens[index + 1]);
+ animation.start_y = Integer.parseInt(tokens[index + 2]);
+ animation.frame_width = Integer.parseInt(tokens[index + 3]);
+ animation.frame_height = Integer.parseInt(tokens[index + 4]);
+ animation.frame_count = Integer.parseInt(tokens[index + 5]);
+ animation.frame_rate = Float.parseFloat(tokens[index + 6]);
+ String animation_name = tokens[index];
+ mAnimations.put(animation_name, animation);
+ }
+ }
+
+ public void setAnimation(String animation) {
+ mCurrentAnimation = mAnimations.get(animation);
+ Assert.assertNotNull("Error: could not find animation: " + animation,
+ mCurrentAnimation);
+ }
+
+ public void stepAnimation(float time_step) {
+ mTime += time_step;
+
+ if (mCurrentAnimation == null) {
+ return; // setAnimation(...) must be called first.
+ }
+
+ int frame = ((int)(mCurrentAnimation.frame_rate * mTime) %
+ mCurrentAnimation.frame_count);
+ sprite_rect.left = mCurrentAnimation.start_x;
+ sprite_rect.top = mCurrentAnimation.start_y;
+ sprite_rect.right = mCurrentAnimation.start_x +
mCurrentAnimation.frame_width;
+ sprite_rect.bottom = mCurrentAnimation.start_y +
mCurrentAnimation.frame_height;
+ sprite_rect.offset(0, mCurrentAnimation.frame_height * frame);
+ }
+
+ @Override
+ public void draw(Graphics graphics, float center_x, float center_y,
+ float zoom) {
+ // Load part image if it hasn't yet been loaded. This is necessary
since the
+ // graphics class must only be interacted with from the main thread.
This is
+ // a product of the lack of thread safety in OpenGL.
+ if (mImageUri != null) {
+ String image_path = Content.getFilePath(mImageUri);
+ Bitmap image_bitmap = BitmapFactory.decodeFile(image_path);
+ sprite_image = graphics.loadImageFromBitmap(image_bitmap);
+ mImageUri = null;
+ }
+
+ super.draw(graphics, center_x, center_y, zoom);
+ }
+
+ class Animation {
+ public int start_x;
+ public int start_y;
+ public int frame_width;
+ public int frame_height;
+ public int frame_count;
+ public float frame_rate;
+ } // class Animation
+
+ private TreeMap<String, Animation> mAnimations =
+ new TreeMap<String, Animation>();
+ private Animation mCurrentAnimation;
+ private Uri mImageUri;
+ private float mTime;
+}

Modified: trunk/src/android/com/abb/ArticulatedEntity.java
==============================================================================
--- trunk/src/android/com/abb/ArticulatedEntity.java (original)
+++ trunk/src/android/com/abb/ArticulatedEntity.java Sat May 23 16:08:22
2009
@@ -13,7 +13,6 @@

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Rect;
@@ -42,16 +41,16 @@
// mappings representing a directed acyclic graph (DAG) of articulated
// parts. There is to be a single root named "root". The file format is
// expected to be an ASCII text file laid out with a single arc per
line.
- // The first line specifies the image Uri. Each line after the first
must be
- // of the format "<part name> <root part name> <rect left> <rect top>
<rect
- // right> <rect bottom>".
+ // The first line specifies the image file name. Each line after the
first
+ // must be of the format "<part name> <root part name> <rect left>
<rect
+ // top> <rect right> <rect bottom>".
//
// For example:
- // content:///entity.png
+ // entity.png
// thigh root 0 0 30 10
// leg thigh 10 0 30 20

- String file_path = Content.getTemporaryFilePath(uri);
+ String file_path = Content.getFilePath(uri);
String[] tokens = Content.readFileTokens(file_path);

final int kLineTokenCount = 6;
@@ -111,7 +110,7 @@
// graphics class must only be interacted with from the main thread.
This is
// a product of the lack of thread safety in OpenGL.
if (mImageUri != null) {
- String image_path = Content.getTemporaryFilePath(mImageUri);
+ String image_path = Content.getFilePath(mImageUri);
Bitmap image_bitmap = BitmapFactory.decodeFile(image_path);
mImageHandle = graphics.loadImageFromBitmap(image_bitmap);
mImageUri = null;
@@ -175,7 +174,7 @@
transformation.preTranslate(-image_rect.width() / 2, 0.0f);
transformation.preScale(image_rect.width(), image_rect.height());
graphics.drawImage(
- image_handle, image_rect, transformation, false, false);
+ image_handle, image_rect, transformation, false, false, 1);
}

// Draw children. The root node transformation is handled specially
to
@@ -234,7 +233,7 @@
// leg 0.0 180
// leg 0.5 170

- String file_path = Content.getTemporaryFilePath(uri);
+ String file_path = Content.getFilePath(uri);
String[] tokens = Content.readFileTokens(file_path);

final int kLineTokenCount = 3;

Modified: trunk/src/android/com/abb/Avatar.java
==============================================================================
--- trunk/src/android/com/abb/Avatar.java (original)
+++ trunk/src/android/com/abb/Avatar.java Sat May 23 16:08:22 2009
@@ -19,12 +19,12 @@
import android.view.MotionEvent;


-public class Avatar extends ArticulatedEntity {
+public class Avatar extends AnimatedEntity {
public Avatar(GameState game_state) {
super();
mGameState = game_state;

- setDrawingScale(kDrawingScale);
+ //setDrawingScale(kDrawingScale);
radius = kRadius; // Collision radius.
}

@@ -73,17 +73,15 @@
} else if (dx > 0.0f) {
sprite_flipped_horizontal = false;
}
+ stepAnimation(time_step);
if (has_ground_contact) {
if (Math.abs(dx) > kAnimationStopThreshold) {
- loadAnimationFromUri("content:///run.humanoid.animation");
- stepAnimation(kGroundAnimationSpeed * Math.abs(dx));
+ setAnimation("running");
} else {
- loadAnimationFromUri("content:///stand.humanoid.animation");
- stepAnimation(time_step);
+ setAnimation("standing");
}
} else {
- loadAnimationFromUri("content:///jump.humanoid.animation");
- stepAnimation(time_step);
+ setAnimation("jumping");
}

// Update the equipped weapon instance.
@@ -94,10 +92,43 @@
mWeapon.dy = dy;
mWeapon.has_ground_contact = has_ground_contact;
mWeapon.sprite_flipped_horizontal = sprite_flipped_horizontal;
+ mWeapon.setTarget(mTargetX, mTargetY);
mWeapon.step(time_step);
}
}

+ public void drawHud(Graphics graphics) {
+ // Draw the avatar life and ammo meters.
+ float meter_width = mCanvasWidth - 45;
+ mRect.set(0, 0, 31, 17);
+ mRectF.set(0, 0, 31, 17);
+ graphics.drawImage(mGameState.misc_sprites, mRect, mRectF, false,
false, 1);
+ if (life > 0.0f) {
+ float life_meter_width = meter_width * life;
+ mRect.set(0, 22, 64, 26);
+ mRectF.set(32, 2, 32 + life_meter_width, 6);
+ graphics.drawImage(mGameState.misc_sprites, mRect, mRectF, false,
false, 1);
+ }
+ if (mWeapon != null) {
+ float ammo_meter_width =
+ Math.min(meter_width,
+ meter_width * mWeapon.getAmmo() / mWeapon.getMaxAmmo());
+ ammo_meter_width = Math.max(ammo_meter_width, 0.0f);
+ mRect.set(0, 29, 64, 33);
+ mRectF.set(32, 8, 32 + ammo_meter_width, 12);
+ graphics.drawImage(mGameState.misc_sprites, mRect, mRectF, false,
false, 1);
+ }
+
+ // Draw the touch screen indicators.
+ mRect.set(40, 4, 58, 12);
+ mRectF.set(0, 0, 12, 8);
+ mRectF.offset(mCanvasWidth / 3 - 6, mCanvasHeight -
kTouchMovementHeight);
+ graphics.drawImage(mGameState.misc_sprites, mRect, mRectF, false,
false, 1);
+ mRectF.set(0, 0, 12, 8);
+ mRectF.offset(2 * mCanvasWidth / 3 - 6, mCanvasHeight -
kTouchMovementHeight);
+ graphics.drawImage(mGameState.misc_sprites, mRect, mRectF, false,
false, 1);
+ }
+
@Override
public void draw(Graphics graphics, float center_x, float center_y,
float zoom) {
@@ -118,36 +149,21 @@
// draw method calculates the model's hand positions which we use to
draw
// the weapon on top of.
if (mWeapon != null) {
+ /*
super.getPartTransformation("farm_l").getValues(mArray9);
float hand_lx = mArray9[2];
float hand_ly = mArray9[5];
super.getPartTransformation("farm_r").getValues(mArray9);
float hand_rx = mArray9[2];
float hand_ry = mArray9[5];
+ */
+ float hand_lx = mCanvasWidth / 2 - 5;
+ float hand_ly = mCanvasHeight / 2;
+ float hand_rx = mCanvasWidth / 2 + 5;
+ float hand_ry = mCanvasHeight / 2;
mWeapon.draw(graphics, center_x, center_y, zoom,
hand_lx, hand_ly, hand_rx, hand_ry);
}
-
- // Draw the avatar life and ammo meters.
- float meter_width = mCanvasWidth - 45;
- mRect.set(0, 0, 31, 17);
- mRectF.set(0, 0, 31, 17);
- graphics.drawImage(mGameState.misc_sprites, mRect, mRectF, false,
false);
- if (life > 0.0f) {
- float life_meter_width = meter_width * life;
- mRect.set(0, 22, 64, 26);
- mRectF.set(32, 2, 32 + life_meter_width, 6);
- graphics.drawImage(mGameState.misc_sprites, mRect, mRectF, false,
false);
- }
- if (mWeapon != null) {
- float ammo_meter_width =
- Math.min(meter_width,
- meter_width * mWeapon.getAmmo() / mWeapon.getMaxAmmo());
- ammo_meter_width = Math.max(ammo_meter_width, 0.0f);
- mRect.set(0, 29, 64, 33);
- mRectF.set(32, 8, 32 + ammo_meter_width, 12);
- graphics.drawImage(mGameState.misc_sprites, mRect, mRectF, false,
false);
- }
}

public void setKeyState(int key_code, int state) {
@@ -172,10 +188,13 @@
has_ground_contact = false;
mJumping = true;
}
- if (key_code == kKeyJump && state == 0 && mJumping && dy < 0.0f) {
- dy = Math.min(0.0f, dy + kJumpVelocity);
- mJumping = false;
- }
+ // The following body of code handles the jump release mechanism for
jumping
+ // short heights. It has been disabled for the touch controls since
multi-
+ // touch on the phone is not available.
+ // if (key_code == kKeyJump && state == 0 && mJumping && dy < 0.0f) {
+ // dy = Math.min(0.0f, dy + kJumpVelocity);
+ // mJumping = false;
+ // }

// Shooting.
if (key_code == kKeyShoot1 || key_code == kKeyShoot2) {
@@ -194,44 +213,46 @@
// event handler. Note: Pressure and size measurements are also
available
// from the API, but aren't yet used here.
int action = motion_event.getAction();
- if (action == MotionEvent.ACTION_DOWN ||
- action == MotionEvent.ACTION_MOVE) {
- // This case handled below.
- } else if (action == MotionEvent.ACTION_UP) {
+
+ if (action == MotionEvent.ACTION_UP) {
setKeyState(kKeyLeft, 0);
setKeyState(kKeyRight, 0);
setKeyState(kKeyJump, 0);
setKeyState(kKeyShoot1, 0);
return;
- } else {
- return;
}

- // The touch event was in the movement section of the display surface.
- if (motion_event.getY() > mCanvasHeight - kTouchMovementHeight) {
- setKeyState(kKeyJump, 0);
- setKeyState(kKeyShoot1, 0);
- if (motion_event.getX() < mCanvasWidth / 2) {
- setKeyState(kKeyRight, 0);
- setKeyState(kKeyLeft, 1);
- } else {
- setKeyState(kKeyLeft, 0);
- setKeyState(kKeyRight, 1);
- }
- }
- // the touch event was in the action section. (Any area above the
movement
- // section of the display surface.)
- else {
- setKeyState(kKeyLeft, 0);
- setKeyState(kKeyRight, 0);
- if (motion_event.getX() < mCanvasWidth / 2) {
- setKeyState(kKeyShoot1, 0);
- setKeyState(kKeyJump, 1);
- } else {
- setKeyState(kKeyJump, 0);
- setKeyState(kKeyShoot1, 1);
+ if (action == MotionEvent.ACTION_DOWN ||
+ action == MotionEvent.ACTION_MOVE) {
+ // The touch event was in the movement section of the display
surface.
+ if (motion_event.getY() > mCanvasHeight - kTouchMovementHeight) {
+ int third_width = mCanvasWidth / 3;
+ if (motion_event.getX() < third_width) {
+ setKeyState(kKeyShoot1, 0);
+ setKeyState(kKeyJump, 0);
+ setKeyState(kKeyRight, 0);
+ setKeyState(kKeyLeft, 1);
+ } else if (motion_event.getX() < 2 * third_width) {
+ setKeyState(kKeyShoot1, 0);
+ setKeyState(kKeyRight, 0);
+ setKeyState(kKeyLeft, 0);
+ setKeyState(kKeyJump, 1);
+ } else {
+ setKeyState(kKeyShoot1, 0);
+ setKeyState(kKeyLeft, 0);
+ setKeyState(kKeyJump, 0);
+ setKeyState(kKeyRight, 1);
+ }
+ return;
}
+
+ // The touch event was in the action section. (Any area outside of
the
+ // movement section of the display surface.)
+ mTargetX = motion_event.getX() - mCanvasWidth / 2;
+ mTargetY = motion_event.getY() - mCanvasHeight / 2;
+ setKeyState(kKeyShoot1, 1);
}
+ return;
}

void setWeapon(Weapon weapon) {
@@ -246,6 +267,8 @@
private int mCanvasHeight;
private GameState mGameState;
private boolean mJumping;
+ private float mTargetX;
+ private float mTargetY;
public Weapon mWeapon;

// To avoid allocations, the following are used.
@@ -269,9 +292,8 @@
private static final int kKeyJump = KeyEvent.KEYCODE_K;
private static final int kKeyShoot1 = KeyEvent.KEYCODE_J;
private static final int kKeyShoot2 = KeyEvent.KEYCODE_L;
- private static final float kRadius = 25.0f;
- private static final Uri kSoundJump =
Uri.parse("content://avatar_jump.mp3");
- private static final int kSpriteSize = 64;
- private static final int kTouchMovementHeight = 30;
+ private static final float kRadius = 20.0f;
+ private static final Uri kSoundJump =
Uri.parse("file:///android_asset/avatar_jump.mp3");
+ private static final int kTouchMovementHeight = 45;
private static final float kVelocityBoost = 40.0f;
}

Modified: trunk/src/android/com/abb/Content.java
==============================================================================
--- trunk/src/android/com/abb/Content.java (original)
+++ trunk/src/android/com/abb/Content.java Sat May 23 16:08:22 2009
@@ -11,6 +11,8 @@

package android.com.abb;

+import android.content.Context;
+import android.content.res.AssetManager;
import android.content.res.Resources;
import android.net.Uri;
import android.util.Log;
@@ -28,77 +30,120 @@
import java.util.zip.ZipFile;
import junit.framework.Assert;

-
/** Class to abstract the details of extracting and accessing files from
the ABB
* content zip file in the same was files on disk are accessed. TODO: This
class
* is not thread-safe. Extracted files are not cached. */
public class Content {
- public static void initialize(Resources resources) {
- mResources = resources;
+ public static void initialize(Context context) {
+ mAssets = context.getAssets();
+ mCacheDir = context.getCacheDir().getAbsolutePath() + "/";
+ mResources = context.getResources();
prepare();
}

- private static void safePrepare() {
- if (!(new File(kTempContentPath)).exists()) {
- prepare();
+ synchronized private static void prepare() {
+ if (cacheIsState()) {
+ for (String cache_item : (new File(mCacheDir)).list()) {
+ deleteRecursively(cache_item);
+ }
+ extractAssets("");
}
}

- synchronized private static void prepare() {
- if (!(new File(kTempFileDirectory)).exists()) {
- boolean success = (new File(kTempFileDirectory)).mkdir();
- Assert.assertTrue("Could not create cache directory.", success);
+ private static boolean cacheIsState() {
+ if (!new File(mCacheDir + "epoch.txt").exists()) {
+ return true;
}

try {
- InputStream content_input_stream =
- mResources.openRawResource(R.raw.content_package);
- writeStreamToFile(content_input_stream, kTempContentPath);
- content_input_stream.close();
+ InputStream asset_input_stream = mAssets.open("epoch.txt");
+ writeStreamToFile(asset_input_stream, mCacheDir + "real_epoch.txt");
+ asset_input_stream.close();
} catch (IOException ex) {
- Assert.fail("Content::initialize. " +
- "Failed extracting content package: " + ex.toString());
+ Assert.fail("Could not compute assets epoch: " + ex.toString());
}
+
+ String[] epoch = readFileLines(mCacheDir + "epoch.txt");
+ String[] real_epoch = readFileLines(mCacheDir + "real_epoch.txt");
+
+ if (epoch.length != real_epoch.length) {
+ return true;
+ }
+ for (int line = 0; line < epoch.length; ++line) {
+ if (!epoch[line].equals(real_epoch[line])) {
+ return true;
+ }
+ }
+ return false;
}

- synchronized public static void cleanup() {
- safeDelete(kTempContentPath);
- for (String temporary_file : mFileCache.values()) {
- safeDelete(temporary_file);
+ private static void extractAssets(String path) {
+ String[] assets = null;
+ try {
+ assets = mAssets.list(path);
+ } catch (IOException ex) {
+ // The path is most likely not a directory. No work to do.
+ }
+
+ if (assets != null) {
+ for (String asset : assets) {
+ String full_path = path + (path.length() > 0 ? "/" : "") + asset;
+ String target_path = mCacheDir + full_path;
+ try {
+ // Skip android SDK specific assets.
+ boolean skip = false;
+ for (String ignore_asset : kIgnoreAssets) {
+ if (full_path.indexOf(ignore_asset) != -1) {
+ skip = true;
+ break;
+ }
+ }
+ if (skip) {
+ continue;
+ }
+
+ // Create the parent directory.
+ Log.d("Content::prepare", "Extracting asset: " + full_path);
+ (new File((new File(target_path)).getParent())).mkdir();
+
+ // Write the file.
+ InputStream asset_input_stream = mAssets.open(full_path);
+ writeStreamToFile(asset_input_stream, target_path);
+ asset_input_stream.close();
+ } catch (IOException ex) {
+ Log.d("Content::extractAssets",
+ "Failed extracting asset: " + full_path + " to " +
target_path);
+ }
+ extractAssets(full_path); // Recurse.
+ }
}
- mFileCache.clear();
}

- protected static void safeDelete(String file_path) {
- File file = new File(file_path);
- if (file.exists()) {
- file.delete();
+ private static void deleteRecursively(String path) {
+ File path_file = new File(path);
+ if (path_file.isDirectory()) {
+ for (String child : path_file.list()) {
+ deleteRecursively(path + child);
+ }
}
+ path_file.delete();
}

public static boolean exists(Uri uri) {
Log.d("Content::exists", uri.toString());

- safePrepare();
+ // Handle "file:///android_asset" scheme.
+ if (uri.toString().indexOf("file:///android_asset/") == 0) {
+ return exists(
+ Uri.parse(uri.toString().replaceFirst(
+ "file:///android_asset/", "file://" + mCacheDir)));
+ }

// Handle "file://" scheme.
if (uri.getScheme().equals("file")) {
return (new File(uri.getPath())).exists();
}

- // Handle "content://" scheme.
- else if (uri.getScheme().equals("content")) {
- String entry_name = uriToContentEntry(uri);
-
- String[] entries = rawContentEntries();
- Arrays.sort(entries);
- boolean exists = Arrays.binarySearch(entries, entry_name) > 0;
- if (!exists) {
- Log.d("Content::exists", "Could not find entry: " + entry_name);
- }
- return exists;
- }
-
// Bad uri scheme.
else {
Assert.fail("Content::exists. Bad URI scheme: " + uri.toString());
@@ -109,29 +154,18 @@
public static String[] list(Uri uri) {
Log.d("Content::list", uri.toString());

- safePrepare();
+ // Handle "file:///android_asset" scheme.
+ if (uri.toString().indexOf("file:///android_asset/") == 0) {
+ return list(
+ Uri.parse(uri.toString().replaceFirst(
+ "file:///android_asset/", "file://" + mCacheDir)));
+ }

// Handle "file://" scheme.
if (uri.getScheme().equals("file")) {
return (new File(uri.getPath())).list();
}

- // Handle "content://" scheme.
- else if (uri.getScheme().equals("content")) {
- String path_prefix = uriToContentEntry(uri);
-
- String[] entries = rawContentEntries();
- ArrayList<String> list_entries = new ArrayList<String>();
- for (String entry : entries) {
- if (entry.startsWith(path_prefix)) {
- entry = entry.replace(path_prefix, "");
- Log.d("Content::list", "Found entry: " + entry);
- list_entries.add(entry);
- }
- }
- return list_entries.toArray(new String[0]);
- }
-
// Bad uri scheme.
else {
Assert.fail("Content::list. Bad URI scheme: " + uri.toString());
@@ -139,59 +173,22 @@
}
}

- synchronized public static String getTemporaryFilePath(Uri uri) {
- Log.d("Content::getTemporaryFilePath", uri.toString());
+ synchronized public static String getFilePath(Uri uri) {
+ Log.d("Content::getFilePath", uri.toString());

- safePrepare();
+ // Handle "file:///android_asset" scheme.
+ if (uri.toString().indexOf("file:///android_asset/") == 0) {
+ return uri.toString().replaceFirst("file:///android_asset/",
mCacheDir);
+ }

// Handle "file://" scheme.
if (uri.getScheme().equals("file")) {
return uri.getPath();
}

- // Attempt to resolve the file request from the file cache.
- String cached_file_path = mFileCache.get(uri);
- if (cached_file_path != null) {
- return cached_file_path;
- }
-
- // Handle "content://" scheme. We must extract the file to a temporary
path
- // in order to handle this request.
- if (uri.getScheme().equals("content")) {
- ZipFile content_file;
- try {
- content_file = new ZipFile(kTempContentPath);
- } catch (IOException ex) {
- Assert.fail("Content::getTemporaryFilePath. " +
- "Unable to open package file: " + ex.toString());
- return null;
- }
- String entry_name = uriToContentEntry(uri);
- ZipEntry content_entry = content_file.getEntry(entry_name);
- if (content_entry == null) {
- Assert.fail("Content::getTemporaryFilePath. " +
- "Unable to find entry: " + entry_name);
- return null;
- }
-
- String temporary_file_path =
- kTempFileDirectory + entry_name.replace("/", "_");
- try {
- InputStream content_stream =
content_file.getInputStream(content_entry);
- writeStreamToFile(content_stream, temporary_file_path);
- } catch (IOException ex) {
- Assert.fail("Content::getTemporaryFilePath. " +
- "Unable to write out entry: " + ex.toString());
- return null;
- }
-
- mFileCache.put(uri, temporary_file_path);
- return temporary_file_path;
- }
-
// Bad uri scheme.
else {
- Assert.fail("Content::getTemporaryFilePath. " +
+ Assert.fail("Content::getFilePath. " +
"Bad URI scheme: " + uri.toString());
return null;
}
@@ -231,7 +228,7 @@
}

static public String[] readUriLines(Uri uri) {
- String file_path = getTemporaryFilePath(uri);
+ String file_path = getFilePath(uri);
return readFileLines(file_path);
}

@@ -317,33 +314,10 @@
output_stream.close();
}

- private static String[] rawContentEntries() {
- ZipFile content_file;
- try {
- content_file = new ZipFile(kTempContentPath);
- } catch (IOException ex) {
- Assert.fail("Content::rawContentEntries, " +
- "Unable to open package file: " + ex.toString());
- return null;
- }
- if (!content_file.entries().hasMoreElements()) {
- Log.d("Content::rawContentEntries", "Content package empty.");
- }
-
- ArrayList<String> entry_list = new ArrayList<String>();
- for (Enumeration<? extends ZipEntry> entry_it = content_file.entries();
- entry_it.hasMoreElements();) {
- String entry_name = entry_it.nextElement().getName();
- entry_list.add(entry_name);
- }
- return entry_list.toArray(new String[0]);
- }
-
- private static TreeMap<Uri, String> mFileCache = new TreeMap<Uri,
String>();
- private static Resources mResources;
+ private static String mCacheDir;
+ private static AssetManager mAssets;
+ private static Resources mResources;

- private static final String kTempFileDirectory =
- "/data/data/android.com.abb/cache/";
- private static final String kTempContentPath =
- "/data/data/android.com.abb/cache/abbpackage.tmp";
+ private static final String[] kIgnoreAssets = {
+ "images/", "sounds/", "webkit/" };
}

Modified: trunk/src/android/com/abb/Enemy.java
==============================================================================
--- trunk/src/android/com/abb/Enemy.java (original)
+++ trunk/src/android/com/abb/Enemy.java Sat May 23 16:08:22 2009
@@ -75,7 +75,7 @@
// Given a fully-specified default enemy parameters map, we can parse
and
// merge in the user defined values. Note that the following method
rejects
// all keys provided by the user which were not defined above.
- String file_path = Content.getTemporaryFilePath(uri);
+ String file_path = Content.getFilePath(uri);
String[] tokens = Content.readFileTokens(file_path);
Content.mergeKeyValueTokensWithMap(tokens, parameters);
Content.assertStringNotNone(parameters, kParameterEntity);

Modified: trunk/src/android/com/abb/Entity.java
==============================================================================
--- trunk/src/android/com/abb/Entity.java (original)
+++ trunk/src/android/com/abb/Entity.java Sat May 23 16:08:22 2009
@@ -96,7 +96,8 @@

graphics.drawImage(
sprite_image, sprite_rect, mRectF,
- sprite_flipped_horizontal, sprite_flipped_vertical);
+ sprite_flipped_horizontal, sprite_flipped_vertical,
+ 1 /*block count*/);
}
}


Modified: trunk/src/android/com/abb/GameState.java
==============================================================================
--- trunk/src/android/com/abb/GameState.java (original)
+++ trunk/src/android/com/abb/GameState.java Sat May 23 16:08:22 2009
@@ -29,6 +29,7 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
+import java.util.List;
import java.util.Random;
import java.util.TreeMap;

@@ -55,9 +56,9 @@
}

public void initializeGraphics(Graphics graphics) {
- avatar.loadFromUri(Uri.parse("content:///humanoid.entity"));
+ avatar.loadFromUri(Uri.parse("file:///android_asset/avatar.animated"));
String misc_sprites_path =
- Content.getTemporaryFilePath(Uri.parse("content:///misc.png"));
+ Content.getFilePath(Uri.parse("file:///android_asset/misc.png"));
Bitmap misc_sprites_bitmap =
BitmapFactory.decodeFile(misc_sprites_path);
misc_sprites = graphics.loadImageFromBitmap(misc_sprites_bitmap);
}
@@ -106,9 +107,35 @@
avatar.onMotionEvent(motion_event);
}

+ private int mFrame = 0;
+ private long mStepTime;
+ private long mDrawTime;
+
public boolean onFrame(Graphics graphics, float time_step) {
+ long time_0 = System.nanoTime();
stepGame(time_step);
+ long time_1 = System.nanoTime();
drawGame(graphics);
+ long time_2 = System.nanoTime();
+
+ mStepTime += time_1 - time_0;
+ mDrawTime += time_2 - time_1;
+ ++mFrame;
+ if (mFrame == 30) {
+ mStepTime /= 30;
+ mDrawTime /= 30;
+
+ float step_seconds = (float)mStepTime * 1.0e-9f;
+ float draw_seconds = (float)mDrawTime * 1.0e-9f;
+ Log.d("GameThread::run",
+ "Step budget: %" + (int)(step_seconds * 3000.0f));
+ Log.d("GameThread::run",
+ "Draw budget: %" + (int)(draw_seconds * 3000.0f));
+
+ mFrame = 0;
+ mStepTime = mDrawTime = 0;
+ }
+
return true; // True to keep updating.
}

@@ -282,6 +309,9 @@
for (int index = 0; index < particles.size(); ++index) {
particles.get(index).draw(graphics, mViewX, mViewY, mZoom);
}
+
+ // Draw the user interface and avatar statistics meters.
+ avatar.drawHud(graphics);
}

synchronized public void addNotification(String notification) {
@@ -386,7 +416,7 @@
public void preloadSound(Uri uri) {
if (!mSoundMap.containsKey(uri)) {
Log.d("GameState::playSound", "Loading: " + uri.toString());
- String file_path = Content.getTemporaryFilePath(uri);
+ String file_path = Content.getFilePath(uri);
int sound_id = mSoundPool.load(file_path, 1 /*Priority*/);
mSoundMap.put(uri, new Integer(sound_id));
}
@@ -398,7 +428,7 @@
sound_id = mSoundMap.get(uri).intValue();
} else {
Log.d("GameState::playSound", "Loading: " + uri.toString());
- String file_path = Content.getTemporaryFilePath(uri);
+ String file_path = Content.getFilePath(uri);
sound_id = mSoundPool.load(file_path, 1 /*Priority*/);
mSoundMap.put(uri, new Integer(sound_id));
}
@@ -476,20 +506,20 @@
private static final long kAvatarDeathVibrateLength = 250; //
Milliseconds.
private static final int kBloodBathSize = 20; // Particle
count.
private static final float kBloodBathVelocity = 60.0f;
- private static final float kDeathTimer = 3.0f;
+ private static final float kDeathTimer = 2.0f;
private static final float kDeathZoom = 1.5f;
private static final long kEnemyAttackVibrateLength = 50; //
Milliseconds.
private static final long kEnemyDeathVibrateLength = 30; //
Milliseconds.
private static final float kGravity = 200.0f;
private static final float kGroundZoom = 0.85f;
private static final int kMaxSounds = 10;
- private static final Uri kSoundAvatarDamage =
Uri.parse("content://avatar_damage.mp3");
- private static final Uri kSoundAvatarDeath =
Uri.parse("content://avatar_death.mp3");
- private static final Uri kSoundAvatarWin =
Uri.parse("content://avatar_win.mp3");
- private static final Uri kSoundEnemyDeath =
Uri.parse("content://enemy_death.mp3");
+ private static final Uri kSoundAvatarDamage =
Uri.parse("file:///android_asset/avatar_damage.mp3");
+ private static final Uri kSoundAvatarDeath =
Uri.parse("file:///android_asset/avatar_death.mp3");
+ private static final Uri kSoundAvatarWin =
Uri.parse("file:///android_asset/avatar_win.mp3");
+ private static final Uri kSoundEnemyDeath =
Uri.parse("file:///android_asset/enemy_death.mp3");
private static final float kViewLead = 1.0f;
private static final float kViewSpeed = 2.0f;
- private static final float kWinTimer = 3.5f;
+ private static final float kWinTimer = 3.0f;
private static final float kWinZoom = 1.7f;
private static final float kZoomSpeed = 1.0f;
}

Modified: trunk/src/android/com/abb/GameView.java
==============================================================================
--- trunk/src/android/com/abb/GameView.java (original)
+++ trunk/src/android/com/abb/GameView.java Sat May 23 16:08:22 2009
@@ -79,6 +79,7 @@
// http://blogs.sun.com/dholmes/entry/inside_the_hotspot_vm_clocks
long time = System.nanoTime();

+ int frame = 0;
while (mRunning) {
synchronized (this) {
while (mPaused && mRunning) {
@@ -96,7 +97,14 @@
long current_time = System.nanoTime();
float time_step = (float)(current_time - time) * 1.0e-9f;
time = current_time;
- if (time_step < kMinTimeStep) {
+
+ ++frame;
+ if (frame % 30 == 0) {
+ Log.d("GameThread::run",
+ "Frame rate: " + (int)(1.0f / time_step));
+ }
+
+ if (false && time_step < kMinTimeStep) {
float remaining_time = kMinTimeStep - time_step;
time_step = kMinTimeStep;
try {
@@ -109,11 +117,11 @@
// continue on. It's not worth the cycles to handle.
}
} else {
- // In the case where the thread took too long, let the thread
yield to
- // other processes. This should usually only happen in the case
- // something "big" is happening and we don't need / want to
starve the
- // more important system threads.
- yield();
+ // In the case where the thread took too long, consider letting
the
+ // thread yield to other processes. This should usually only
happen in
+ // the case something "big" is happening and we don't need /
want to
+ // starve the more important system threads.
+ // yield();
}
time_step = Math.max(time_step, kMinTimeStep);
time_step = Math.min(time_step, kMaxTimeStep);

Modified: trunk/src/android/com/abb/Graphics.java
==============================================================================
--- trunk/src/android/com/abb/Graphics.java (original)
+++ trunk/src/android/com/abb/Graphics.java Sat May 23 16:08:22 2009
@@ -156,18 +156,14 @@
}

public void drawImage(int image_handle, Rect source_rect, RectF
dest_rect,
- boolean flipped_horizontal, boolean
flipped_vertical) {
+ boolean flipped_horizontal, boolean
flipped_vertical,
+ int block_count) {
/* DEBUGGING ONLY
Assert.assertTrue("Invalid image handle in drawImage", image_handle >=
0);
// The drawImageOpenGL implementation has been inlined here for
performance
// reasons. TODO: Inline the 2D API implementation here.
Assert.assertEquals(mBackendType, BackendType.OPENGL);
*/
- if (mBackendType == BackendType.ANDROID2D) {
- drawImageAndroid2D(image_handle, source_rect, dest_rect,
- flipped_horizontal, flipped_vertical);
- return;
- }

if (image_handle >= mTextureData.size()) {
Log.d("Graphics::drawImage", "Unknown image handle encountered. " +
@@ -216,11 +212,12 @@
mGl.glMatrixMode(GL10.GL_MODELVIEW);
mGl.glLoadMatrixf(mMatrix4x4, 0);

- mGl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, 4);
+ mGl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 2 * block_count + 2);
}

public void drawImage(int image_handle, Rect source_rect, Matrix
dest_matrix,
- boolean flipped_horizontal, boolean
flipped_vertical) {
+ boolean flipped_horizontal, boolean
flipped_vertical,
+ int block_count) {
/* DEBUGGING ONLY
Assert.assertTrue("Invalid image handle in drawImage", image_handle >=
0);
// The drawImageOpenGL implementation has been inlined here for
performance
@@ -287,7 +284,7 @@
mGl.glMatrixMode(GL10.GL_MODELVIEW);
mGl.glLoadMatrixf(mMatrix4x4, 0);

- mGl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, 4);
+ mGl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 2 * block_count + 2);
}

/**
@@ -438,7 +435,7 @@
// /khronos/opengles/GL10.html

mEgl = (EGL10)EGLContext.getEGL();
- mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+ mEglDisplay = mEgl.eglGetDisplay(EGL11.EGL_DEFAULT_DISPLAY);

// We can now initialize EGL for that display.
int[] version = new int[2];
@@ -447,7 +444,7 @@
"Found version: " + version[0] + "." + version[1]);

int attrib_list[] = { // Use default bit depths.
- EGL10.EGL_NONE
+ EGL11.EGL_NONE
};

EGLConfig[] configs = new EGLConfig[1];
@@ -455,7 +452,7 @@
mEgl.eglChooseConfig(mEglDisplay, attrib_list, configs, 1, num_config);
mEglConfig = configs[0];
mEglContext = mEgl.eglCreateContext(
- mEglDisplay, mEglConfig, EGL10.EGL_NO_CONTEXT, null);
+ mEglDisplay, mEglConfig, EGL11.EGL_NO_CONTEXT, null);
mGl = (GL10)mEglContext.getGL();

final boolean kEnableOpenGLDebugging = false;
@@ -533,10 +530,24 @@
mGl.glLoadIdentity();
mGl.glOrthof(0, getWidthOpenGL(), 0, getHeightOpenGL(), -1, 1);

- // Since we will only be rendering quads, set up a shared vertex and
texture
- // coordinate array. The following is so convoluted I really wonder if
this
- // is right of if the Java / OpenGL ES folks need their heads examined.
- float[] corner_array = { 0, 0, 1, 0, 1, 1, 0, 1 };
+ // Since we will only be rendering triangle strips, set up a shared
vertex
+ // and texture coordinate array. The following array lays out 16 quads.
+ float[] corner_array = { 0, 0, 0, 1, 1, 0, 1, 1,
+ 2, 0, 2, 1,
+ 3, 0, 3, 1,
+ 4, 0, 4, 1,
+ 5, 0, 5, 1,
+ 6, 0, 6, 1,
+ 7, 0, 7, 1,
+ 8, 0, 8, 1,
+ 9, 0, 9, 1,
+ 10, 0, 10, 1,
+ 11, 0, 11, 1,
+ 12, 0, 12, 1,
+ 13, 0, 13, 1,
+ 14, 0, 14, 1,
+ 15, 0, 15, 1,
+ 16, 0, 16, 1, };
ByteBuffer corner_byte_buffer =
ByteBuffer.allocateDirect(4 * corner_array.length);
corner_byte_buffer.order(ByteOrder.nativeOrder());
@@ -580,6 +591,19 @@
}
}

+ public void pushRotationMatrixOpenGL(float angle) {
+ mGl.glMatrixMode(GL10.GL_MODELVIEW);
+ mGl.glPushMatrix();
+ mGl.glTranslatef(mSurfaceWidth / 2.0f, mSurfaceHeight / 2.0f, 0.0f);
+ mGl.glRotatef(angle, 0, 0, 1);
+ mGl.glTranslatef(-mSurfaceWidth / 2.0f, -mSurfaceHeight / 2.0f, 0.0f);
+ }
+
+ public void popMatrixOpenGL() {
+ mGl.glMatrixMode(GL10.GL_MODELVIEW);
+ mGl.glPopMatrix();
+ }
+
private int loadImageFromBitmapOpenGL(Bitmap bitmap) {
// Allocate a texture handle within the OpenGL context.
int[] texture_names = new int[1];
@@ -618,6 +642,12 @@
mGl.glTexParameterf(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_MAG_FILTER,
GL10.GL_NEAREST);
+ mGl.glTexParameterx(GL10.GL_TEXTURE_2D,
+ GL10.GL_TEXTURE_WRAP_S,
+ GL10.GL_REPEAT);
+ mGl.glTexParameterx(GL10.GL_TEXTURE_2D,
+ GL10.GL_TEXTURE_WRAP_T,
+ GL10.GL_REPEAT);

// The size must be manually stored for retrieval during the rendering
// process since the texture coordinate scheme under OpenGL is
normalized

Added: trunk/src/android/com/abb/Grappling.java
==============================================================================
--- (empty file)
+++ trunk/src/android/com/abb/Grappling.java Sat May 23 16:08:22 2009
@@ -0,0 +1,36 @@
+// Copyright 2008 and onwards Matthew Burkhart.
+//
+// This program is free software; you can redistribute it and/or modify it
under
+// the terms of the GNU General Public License as published by the Free
Software
+// Foundation; version 3 of the License.
+//
+// This program is distributed in the hope that it will be useful, but
WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+// details.
+
+package android.com.abb;
+
+
+public class Grappling {
+ public Grappling() {
+ }
+
+ public void step(float time_step) {
+ }
+
+ public void draw(Graphics graphics, float center_x, float center_y,
+ float zoom) {
+ for (Link link : mLinks) {
+ link.draw(graphics, center_x, center_y, zoom);
+ }
+ }
+
+ public class Link extends Entity {
+ }
+
+ private Link[] mLinks = new Link[kLinkCount];
+
+ private static final int kLinkCount = 5;
+ private static final float kLinkLength = 10;
+}

Modified: trunk/src/android/com/abb/LevelSelectActivity.java
==============================================================================
--- trunk/src/android/com/abb/LevelSelectActivity.java (original)
+++ trunk/src/android/com/abb/LevelSelectActivity.java Sat May 23 16:08:22
2009
@@ -11,11 +11,14 @@

package android.com.abb;

-import android.content.Context;
+import android.app.ProgressDialog;
import android.app.TabActivity;
+import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
import android.util.Log;
import android.view.animation.TranslateAnimation;
import android.view.LayoutInflater;
@@ -23,6 +26,7 @@
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
+import android.webkit.WebView;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
@@ -36,7 +40,7 @@
import junit.framework.Assert;


-public class LevelSelectActivity extends TabActivity implements
ListView.OnItemClickListener {
+public class LevelSelectActivity extends TabActivity implements
ListView.OnItemClickListener, Runnable {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -46,25 +50,47 @@
tab_host.addTab(tab_host.newTabSpec("levellistview")
.setIndicator("",
getResources().getDrawable(R.drawable.maps))
.setContent(R.id.levellistview));
- /*
tab_host.addTab(tab_host.newTabSpec("avatarview")
.setIndicator("",
getResources().getDrawable(R.drawable.avatar))
.setContent(R.id.avatarview));
- */
tab_host.addTab(tab_host.newTabSpec("settingsview")
.setIndicator("",
getResources().getDrawable(R.drawable.settings))
.setContent(R.id.settingsview));
+ tab_host.addTab(tab_host.newTabSpec("helpview")
+ .setIndicator("",
getResources().getDrawable(R.drawable.help))
+ .setContent(R.id.helpview));
tab_host.setCurrentTab(0);

- Content.initialize(getResources());
+ WebView web_view = (WebView)findViewById(R.id.helpview);
+ web_view.loadUrl("file:///android_asset/help.htm");
+
+ // Start the asset pre-caching and level loading. This is done in
another
+ // thread since it is relatively slow. Note that the loading thread
needs to
+ // signal this thread via a "handler" since Android views may only be
+ // touched via the main thread.
+ mPrecachingDialog = ProgressDialog.show(
+ this, null, "Precaching...", true, false);
+ mPrecachingDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
+ (new Thread(this)).start();
+ }

+ public void run() {
+ Content.initialize(this);
loadLevels();
- mLevelArrayAdapter = new LevelArrayAdapter(this);
- ListView list_view = (ListView)findViewById(R.id.levellistview);
- list_view.setAdapter(mLevelArrayAdapter);
- list_view.setOnItemClickListener(this);
+ mRunDoneHandler.sendEmptyMessage(0);
}

+ private Handler mRunDoneHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ mPrecachingDialog.dismiss();
+ mLevelArrayAdapter = new LevelArrayAdapter(mThis);
+ ListView list_view = (ListView)findViewById(R.id.levellistview);
+ list_view.setAdapter(mLevelArrayAdapter);
+ list_view.setOnItemClickListener(mThis);
+ }
+ };
+
@Override
public void onItemClick(AdapterView parent, View v, int position, long
id) {
// Since the loading may take a while, we hide the current view by
moving
@@ -100,9 +126,6 @@
@Override
public void onSaveInstanceState(Bundle saved_instance_state) {
super.onSaveInstanceState(saved_instance_state);
-
- // Clean up any temporary files used by the content management library.
- Content.cleanup();
}

private void loadLevels() {
@@ -196,10 +219,13 @@
float time;
}

+ private LevelSelectActivity mThis = this;
private LevelArrayAdapter mLevelArrayAdapter;
private ArrayList<Level> mLevels = new ArrayList<Level>();
+ private ProgressDialog mPrecachingDialog;

//private final String kRootDirectory = "content:///Classic/";
//private final String kRootDirectory = "content:///Demo/";
- private final String kRootDirectory = "content:///The_Second_Wave/";
+ //private final String kRootDirectory = "content:///The_Second_Wave/";
+ private final String kRootDirectory = "file:///android_asset/Maps/";
}

Modified: trunk/src/android/com/abb/Map.java
==============================================================================
--- trunk/src/android/com/abb/Map.java (original)
+++ trunk/src/android/com/abb/Map.java Sat May 23 16:08:22 2009
@@ -60,7 +60,7 @@
// Load level layout.
Uri level_uri =
Uri.withAppendedPath(mBaseUri, "level_" + mLevelOffset + ".txt");
- String level_path = Content.getTemporaryFilePath(level_uri);
+ String level_path = Content.getFilePath(level_uri);
loadLevelFromFile(level_path);

// Load tiles background image.
@@ -68,12 +68,12 @@
Uri.withAppendedPath(mBaseUri, "tiles_" + mLevelOffset + ".txt");
if (!Content.exists(tiles_uri))
tiles_uri = Uri.withAppendedPath(mBaseUri, "tiles_default.txt");
- String tiles_path = Content.getTemporaryFilePath(tiles_uri);
+ String tiles_path = Content.getFilePath(tiles_uri);
String[] image_paths = Content.readFileTokens(tiles_path);
- String tiles_image_path = Content.getTemporaryFilePath(
+ String tiles_image_path = Content.getFilePath(
Uri.withAppendedPath(mBaseUri, image_paths[0]));
loadTilesFromFile(tiles_image_path);
- String background_image_path = Content.getTemporaryFilePath(
+ String background_image_path = Content.getFilePath(
Uri.withAppendedPath(mBaseUri, image_paths[1]));
loadBackgroundFromFile(background_image_path);

@@ -82,9 +82,13 @@
Uri.withAppendedPath(mBaseUri, "effects_" + mLevelOffset + ".txt");
if (!Content.exists(effects_uri))
effects_uri = Uri.withAppendedPath(mBaseUri, "effects_default.txt");
- String effects_path = Content.getTemporaryFilePath(effects_uri);
+ String effects_path = Content.getFilePath(effects_uri);
loadEffectsFromFile(effects_path);

+ // Build the run length level encoding which is used to accelerate the
+ // rendering.
+ computeRunLengthEncoding();
+
// Pre-cache audio clips.
mGameState.preloadSound(kSoundExplosion);
}
@@ -173,6 +177,24 @@
}
}

+ private void computeRunLengthEncoding() {
+ mTilesRunLength = new char[mTiles.length];
+ for (int y = 0; y < kMapHeight; ++y) {
+ for (int x = 0; x < kMapWidth; ++x) {
+ char run_length = 1;
+ char tile_type = mTiles[kMapWidth * x + y];
+ while (x + run_length < kMapWidth &&
+ mTiles[kMapWidth * (x + run_length) + y] == tile_type &&
+ !mEffectsExplode[mTiles[kMapWidth * (x + run_length) + y]]
&&
+ mTriggers[kMapWidth * (x + run_length) + y] == null &&
+ run_length <= 16) {
+ ++run_length;
+ }
+ mTilesRunLength[kMapWidth * x + y] = run_length;
+ }
+ }
+ }
+
public void setTileAt(float x, float y, char tile_id) {
int index_x = (int)(x / kTileSize + 0.5f);
int index_y = (int)(y / kTileSize + 0.5f);
@@ -349,17 +371,19 @@
mTilesBitmap = null;
}

+ int canvas_width = graphics.getWidth();
+ int canvas_height = graphics.getHeight();
+
// Draw the background.
mRectSource.top = mRectSource.left = 0;
mRectSource.bottom = mRectSource.right = 256;
- int canvas_width = graphics.getWidth();
- int canvas_height = graphics.getHeight();
float kMinZoom = 0.6f;
float background_zoom = canvas_width / 3.0f * (zoom - kMinZoom);
mRectDest.top = mRectDest.left = -background_zoom;
mRectDest.right = canvas_width + background_zoom;
mRectDest.bottom = canvas_height + background_zoom;
- graphics.drawImage(mBackgroundImage, mRectSource, mRectDest, false,
false);
+ graphics.drawImage(
+ mBackgroundImage, mRectSource, mRectDest, false, false, 1);

// Draw the tiles.
mRectSource.top = mRectSource.left = 0;
@@ -370,10 +394,11 @@
float x_max = center_x + (half_canvas_width + kTileSize) / zoom;
float y_min = center_y - half_canvas_height / zoom;
float y_max = center_y + (half_canvas_height + kTileSize) / zoom;
- for (float x = x_min; x < x_max; x += kTileSize) {
- for (float y = y_min; y < y_max; y += kTileSize) {
+ for (float y = y_min; y <= y_max; y += kTileSize) {
+ for (float x = x_min; x <= x_max; ) {
int tile_index = indexAt(x, y);
if (tile_index < 0) {
+ x += kTileSize;
continue; // Tile out of bounds.
}

@@ -390,22 +415,23 @@

// Draw the tile.
int tile_id = mTiles[tile_index];
- if (tile_id == 0) {
- continue; // Not a visual tile.
+ int run_length = mTilesRunLength[tile_index];
+ if (tile_id != 0) { // Tile is a visual tile.
+ int index_x = (int)(x / kTileSize + 0.5f);
+ int index_y = (int)(y / kTileSize + 0.5f);
+ mRectSource.top = kTileSize * tile_id;
+ mRectSource.bottom = kTileSize * tile_id + kTileSize;
+ mRectDest.left = kTileSize * index_x * zoom;
+ mRectDest.top = kTileSize * index_y * zoom;
+ mRectDest.right = (kTileSize * index_x + kTileSize) * zoom;
+ mRectDest.bottom = (kTileSize * index_y + kTileSize) * zoom;
+ mRectDest.offset(
+ -center_x * zoom + half_canvas_width - kTileSize / 2 * zoom,
+ -center_y * zoom + half_canvas_height - kTileSize / 2 *
zoom);
+ graphics.drawImage(
+ mTilesImage, mRectSource, mRectDest, false, false,
run_length);
}
-
- int index_x = (int)(x / kTileSize + 0.5f);
- int index_y = (int)(y / kTileSize + 0.5f);
- mRectSource.top = kTileSize * tile_id;
- mRectSource.bottom = kTileSize * tile_id + kTileSize;
- mRectDest.left = kTileSize * index_x * zoom;
- mRectDest.top = kTileSize * index_y * zoom;
- mRectDest.right = (kTileSize * index_x + kTileSize) * zoom;
- mRectDest.bottom = (kTileSize * index_y + kTileSize) * zoom;
- mRectDest.offset(
- -center_x * zoom + half_canvas_width - kTileSize / 2 * zoom,
- -center_y * zoom + half_canvas_height - kTileSize / 2 * zoom);
- graphics.drawImage(mTilesImage, mRectSource, mRectDest, false,
false);
+ x += kTileSize * run_length;
}
}
}
@@ -463,6 +489,7 @@
private char[] mTiles;
private Bitmap mTilesBitmap;
private int mTilesImage = -1;
+ private char[] mTilesRunLength;
private String[] mTriggers;

private static final char kBaseValue = 'a';
@@ -473,7 +500,7 @@
private static final int kMapHeight = 100;
private static final int kMapWidth = 100;
private static final int kMaxTileCount = 25;
- private static final Uri kSoundExplosion =
Uri.parse("content://explosion.mp3");
+ private static final Uri kSoundExplosion =
Uri.parse("file:///android_asset/explosion.mp3");
private static final int kStartingTile = 10;
private static final int kTileSize = 64;
}

Modified: trunk/src/android/com/abb/Weapon.java
==============================================================================
--- trunk/src/android/com/abb/Weapon.java (original)
+++ trunk/src/android/com/abb/Weapon.java Sat May 23 16:08:22 2009
@@ -59,7 +59,7 @@
// Given a fully-specified default weapon parameters map, we can parse
and
// merge in the user defined values. Note that the following method
rejects
// all keys provided by the user which were not defined above.
- String file_path = Content.getTemporaryFilePath(uri);
+ String file_path = Content.getFilePath(uri);
String[] tokens = Content.readFileTokens(file_path);
Content.mergeKeyValueTokensWithMap(tokens, parameters);
Content.assertIntegerNotNone(parameters,
kParameterProjectileRectBottom);
@@ -108,6 +108,11 @@

((Integer)parameters.get(kParameterProjectileRectBottom)).intValue());
}

+ public void setTarget(float target_x, float target_y) {
+ mTargetX = target_x;
+ mTargetY = target_y;
+ }
+
public void enableShooting(boolean shooting) {
mShooting = shooting;
}
@@ -133,29 +138,15 @@
mCurrentDelay = mDelay;
mPhase += 10.0f;

- float shot_angle;
float shot_distance = sprite_rect.width() / 2;
float shot_velocity = mVelocity;
- float x_offset = shot_distance;
- float y_offset = -10.0f;
-
- if (!has_ground_contact) {
- shot_angle =
- (float)Math.atan2(dy, dx) + mSpread * (float)Math.sin(mPhase);
- x_offset = shot_distance * (float)Math.cos(shot_angle);
- y_offset = shot_distance * (float)Math.sin(shot_angle);
- } else {
- shot_angle = mSpread * (float)Math.sin(mPhase);
- }
-
+ float shot_angle = ((float)Math.atan2(mTargetY, mTargetX) +
+ mSpread * (float)Math.sin(mPhase));
+ float x_offset = shot_distance * (float)Math.cos(shot_angle);
+ float y_offset = shot_distance * (float)Math.sin(shot_angle);
float dx_offset = shot_velocity * (float)Math.cos(shot_angle);
float dy_offset = shot_velocity * (float)Math.sin(shot_angle);

- if (has_ground_contact && sprite_flipped_horizontal) {
- x_offset *= -1.0f;
- dx_offset *= -1.0f;
- }
-
if (mProjectileIsFlame) {
mGameState.createFireProjectile(x + x_offset, y + y_offset,
dx + dx_offset, dy + dy_offset,
@@ -187,7 +178,7 @@
// graphics class must only be interacted with from the main thread.
This is
// a product of the lack of thread safety in OpenGL.
if (mSpriteUri != null) {
- String image_path = Content.getTemporaryFilePath(mSpriteUri);
+ String image_path = Content.getFilePath(mSpriteUri);
Bitmap image_bitmap = BitmapFactory.decodeFile(image_path);
sprite_image = graphics.loadImageFromBitmap(image_bitmap);
mSpriteUri = null;
@@ -206,7 +197,7 @@
mDrawingMatrix.preScale(zoom * sprite_rect.width(),
zoom * sprite_rect.height());
graphics.drawImage(sprite_image, sprite_rect, mDrawingMatrix,
- false, sprite_flipped_horizontal);
+ false, sprite_flipped_horizontal, 1);
}
}

@@ -229,6 +220,8 @@
private boolean mShooting;
private float mSpread;
private Uri mSpriteUri;
+ private float mTargetX;
+ private float mTargetY;
private float mTimeout;
private float mVelocity;
private int mVibration;

Reply all
Reply to author
Forward
0 new messages