Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit 7f773105a64332d284a9ae2380597d3262a82a3a 0 parents
@waynebeaton authored
Showing with 1,106 additions and 0 deletions.
  1. +7 −0 .classpath
  2. +33 −0 .project
  3. +18 −0 AndroidManifest.xml
  4. BIN  bin/KittyMunch3Android.apk
  5. BIN  bin/classes.dex
  6. BIN  bin/resources.ap_
  7. +11 −0 default.properties
  8. BIN  res/drawable-hdpi/icon.png
  9. BIN  res/drawable-ldpi/icon.png
  10. BIN  res/drawable-mdpi/icon.png
  11. BIN  res/drawable/hand.png
  12. BIN  res/drawable/kitty1.png
  13. BIN  res/drawable/kitty2.png
  14. BIN  res/drawable/kitty3.png
  15. BIN  res/drawable/kitty4.png
  16. +11 −0 res/layout/main.xml
  17. +5 −0 res/values/strings.xml
  18. +23 −0 src/ca/rokc/kittymunch/PlayActivity.java
  19. +136 −0 src/ca/rokc/kittymunch/PlayView.java
  20. +37 −0 src/ca/rokc/kittymunch/game/Bloodstain.java
  21. +30 −0 src/ca/rokc/kittymunch/game/Brick.java
  22. +62 −0 src/ca/rokc/kittymunch/game/GameObject.java
  23. +105 −0 src/ca/rokc/kittymunch/game/Kitty.java
  24. +151 −0 src/ca/rokc/kittymunch/game/KittyMunch.java
  25. +28 −0 src/ca/rokc/kittymunch/game/Projectile.java
  26. +138 −0 src/ca/rokc/kittymunch/game/Protagonist.java
  27. +40 −0 src/ca/rokc/kittymunch/game/Score.java
  28. +86 −0 src/ca/rokc/kittymunch/geometry/Point.java
  29. +33 −0 src/ca/rokc/kittymunch/geometry/Rectangle.java
  30. +48 −0 src/ca/rokc/kittymunch/graphics/GameRenderer.java
  31. +24 −0 src/ca/rokc/kittymunch/graphics/ScoreRenderer.java
  32. +16 −0 src/ca/rokc/kittymunch/util/ChangeListener.java
  33. +64 −0 src/ca/rokc/kittymunch/util/DelayedChangeList.java
7 .classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="gen"/>
+ <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
33 .project
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>KittyMunch3Android</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.ApkBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>com.android.ide.eclipse.adt.AndroidNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
18 AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="ca.rokc.kittymunch"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true">
+ <activity android:label="@string/app_name" android:screenOrientation="landscape" android:name=".PlayActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+
+</activity>
+
+ </application>
+ <uses-sdk android:minSdkVersion="4" />
+
+</manifest>
BIN  bin/KittyMunch3Android.apk
Binary file not shown
BIN  bin/classes.dex
Binary file not shown
BIN  bin/resources.ap_
Binary file not shown
11 default.properties
@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-4
BIN  res/drawable-hdpi/icon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  res/drawable-ldpi/icon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  res/drawable-mdpi/icon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  res/drawable/hand.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  res/drawable/kitty1.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  res/drawable/kitty2.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  res/drawable/kitty3.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  res/drawable/kitty4.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 res/layout/main.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<FrameLayout android:id="@+id/FrameLayout01"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <ca.rokc.kittymunch.PlayView android:id="@+id/PlayView"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" />
+
+</FrameLayout>
5 res/values/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="hello">Hello World, KittyMunchPlay!</string>
+ <string name="app_name">Kitty Munch 3: Because They Deserve It</string>
+</resources>
23 src/ca/rokc/kittymunch/PlayActivity.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Wayne Beaton.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wayne Beaton
+ *******************************************************************************/
+package ca.rokc.kittymunch;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class PlayActivity extends Activity {
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+ }
+}
136 src/ca/rokc/kittymunch/PlayView.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Wayne Beaton.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wayne Beaton
+ *******************************************************************************/
+package ca.rokc.kittymunch;
+
+import java.util.Queue;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import ca.rokc.kittymunch.game.KittyMunch;
+import ca.rokc.kittymunch.geometry.Point;
+import ca.rokc.kittymunch.geometry.Rectangle;
+import ca.rokc.kittymunch.graphics.GameRenderer;
+
+public class PlayView extends SurfaceView {
+
+ private Timer timer;
+ private TimerTask task;
+ private KittyMunch game;
+ private GameRenderer drawer;
+
+ Queue<GameEvent> events = new ConcurrentLinkedQueue<GameEvent>();
+ private final Context context;
+
+ interface GameEvent {
+ void process(KittyMunch game);
+ }
+
+ public PlayView(Context context, AttributeSet attributes) {
+ super(context, attributes);
+ this.context = context;
+ getHolder().addCallback(new SurfaceHolder.Callback() {
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ startTimer();
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ stopTimer();
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ // TODO Auto-generated method stub
+ }
+ });
+ }
+
+ protected synchronized void startTimer() {
+ if (timer != null) return; // bail out if the timer has already been started.
+
+ game = new KittyMunch(context, new Rectangle(0,0,getWidth(), getHeight()));
+ drawer = new GameRenderer(game, context);
+
+ timer = new Timer(true);
+ task = new TimerTask() {
+ @Override
+ public void run() {
+ tick();
+ }
+ };
+ timer.scheduleAtFixedRate(task, 0, 75);
+ }
+
+ protected void stopTimer() {
+ if (timer == null) return;
+ timer.cancel();
+ timer = null;
+ task = null;
+ }
+
+ protected void tick() {
+ while (!events.isEmpty()) {
+ events.remove().process(game);
+ }
+
+ Canvas canvas = null;
+ try {
+ canvas = getHolder().lockCanvas(null);
+ long start = System.currentTimeMillis();
+ game.tick();
+ doDraw(canvas);
+ long end = System.currentTimeMillis();
+
+ canvas.drawText(String.valueOf(end-start), 10, 10, new Paint());
+
+ } finally {
+ if (canvas != null) {
+ getHolder().unlockCanvasAndPost(canvas);
+ }
+ }
+ }
+
+ private void doDraw(Canvas canvas) {
+ drawer.drawOn(canvas);
+ }
+
+ @Override
+ public boolean onTouchEvent(final MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_MOVE:
+ events.add(new GameEvent() {
+ @Override
+ public void process(KittyMunch game) {
+ game.protagonist.moveToward(new Point((int)event.getX(), (int)event.getY()));
+ }
+ });
+ break;
+ case MotionEvent.ACTION_UP:
+ events.add(new GameEvent() {
+ @Override
+ public void process(KittyMunch game) {
+ game.protagonist.release();
+ }
+ });
+ }
+ return true;
+ }
+}
37 src/ca/rokc/kittymunch/game/Bloodstain.java
@@ -0,0 +1,37 @@
+package ca.rokc.kittymunch.game;
+
+import android.graphics.Color;
+import android.graphics.Paint;
+import ca.rokc.kittymunch.geometry.Point;
+
+public class Bloodstain extends GameObject {
+
+ private static final int MAX_AGE = 30;
+ private int countdown = MAX_AGE;
+
+ public Bloodstain(Point location) {
+ super(location);
+ }
+
+ @Override
+ public void doTick() {
+ if (countdown-- <= 0) game.remove(this);
+ }
+
+ @Override
+ public void collideWith(GameObject object) {
+ }
+
+ public void drawOn(android.graphics.Canvas canvas) {
+ Paint paint = new Paint();
+ paint.setStyle(Paint.Style.FILL_AND_STROKE);
+ paint.setColor(Color.RED);
+ paint.setAlpha(countdown * 255 / MAX_AGE);
+
+ int x = (int)location.x;
+ int y = (int)location.y;
+
+ canvas.drawCircle(x, y, 10, paint);
+ }
+
+}
30 src/ca/rokc/kittymunch/game/Brick.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Wayne Beaton.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wayne Beaton
+ *******************************************************************************/
+package ca.rokc.kittymunch.game;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import ca.rokc.kittymunch.geometry.Point;
+
+public class Brick extends Projectile {
+ public Brick(Point location, Point velocity, int height) {
+ super(location, velocity, height);
+ }
+
+ @Override
+ public void drawOn(Canvas canvas) {
+ Paint paint = new Paint();
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setColor(Color.RED);
+ canvas.drawCircle((int)location.x, (int)location.y, height, paint);
+ }
+}
62 src/ca/rokc/kittymunch/game/GameObject.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Wayne Beaton.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wayne Beaton
+ *******************************************************************************/
+package ca.rokc.kittymunch.game;
+
+import android.graphics.Canvas;
+import ca.rokc.kittymunch.geometry.Point;
+
+public abstract class GameObject {
+ protected KittyMunch game;
+ public final Point location;
+
+ public GameObject(Point location) {
+ this.location = location;
+ }
+
+ public void setGame(KittyMunch game) {
+ this.game = game;
+ }
+
+ public void tick() {
+ doTick();
+ resolveCollisions();
+ }
+
+ public abstract void doTick();
+
+ public void moveTo(Point target) {
+ location.x = target.x;
+ location.y = target.y;
+ }
+
+ public void moveBy(Point delta) {
+ location.x += delta.x;
+ location.y += delta.y;
+ }
+
+ private void resolveCollisions() {
+ for(GameObject object : game.targets) {
+ if (object == this) continue;
+ int distance = (int)location.distanceTo(object.location);
+ // TODO Magic number
+ if (distance > 20) continue; // No collision
+ collideWith(object);
+ }
+ }
+
+ public abstract void collideWith(GameObject object);
+
+ public void hitByKitty(Kitty object) {}
+
+ public void hitByBrick(Projectile projectile) {}
+
+ public void drawOn(Canvas canvas) {}
+}
105 src/ca/rokc/kittymunch/game/Kitty.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Wayne Beaton.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wayne Beaton
+ *******************************************************************************/
+package ca.rokc.kittymunch.game;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import ca.rokc.kittymunch.geometry.Point;
+
+public class Kitty extends GameObject {
+
+ public int speed;
+ public int direction;
+ private final Bitmap[] images;
+ private int count = 0;
+ private int turn = 0;
+
+ public Kitty(Bitmap[] images, Point location, int direction, int speed) {
+ super(location);
+ this.images = images;
+ this.direction = direction;
+ this.speed = speed;
+
+ }
+
+ @Override
+ public void doTick() {
+ if (turn > 0) {
+ turn -= 10;
+ return;
+ }
+ location.x += direction * speed;
+
+ if (!game.isVisible(this)) game.remove(this);
+ }
+
+ @Override
+ public void collideWith(GameObject object) {
+ location.x -= direction * speed;
+ turnAround();
+ object.hitByKitty(this);
+ }
+
+ private void turnAround() {
+ direction = -direction;
+ turn = 180;
+ speed = game.generateKittySpeed();
+ }
+
+ /**
+ * When a kitty collides with the receiver, put it back to
+ * where it was before the collision and change the direction
+ * on both the kitty and the receiver.
+ *
+ * TODO We need to be more clever. Fast kitty runs into slower kitty?
+ */
+ @Override
+ public void hitByKitty(Kitty object) {
+ }
+
+ @Override
+ public void hitByBrick(Projectile projectile) {
+ game.remove(this);
+ game.addBackground(new Bloodstain(new Point(location)));
+ game.addBackground(new Score(new Point(location), String.valueOf(speed * 100))); }
+
+ @Override
+ public void drawOn(Canvas canvas) {
+ Bitmap bitmap = images[count++ % images.length];
+
+ canvas.save();
+ Matrix matrix = canvas.getMatrix();
+ matrix.postTranslate( - bitmap.getWidth() / 2, - bitmap.getHeight() / 2);
+ if (direction == 1) {
+ matrix.postRotate(180);
+ }
+ if (turn > 0) {
+ matrix.postRotate(turn);
+ }
+ matrix.postTranslate((int)location.x, (int)location.y);
+ canvas.setMatrix(matrix);
+ //canvas.translate(direction * bitmap.getWidth() / 2, direction * bitmap.getHeight() / 2);
+ canvas.drawBitmap(bitmap, 0, 0, new Paint());
+ canvas.restore();
+
+// Paint paint = new Paint();
+// paint.setStyle(Paint.Style.STROKE);
+// paint.setColor(Color.BLUE);
+//
+// int x = (int)location.x;
+// int y = (int)location.y;
+//
+// canvas.drawCircle(x, y, 10, paint);
+// canvas.drawText(String.valueOf(speed), x, y, paint);
+ }
+}
151 src/ca/rokc/kittymunch/game/KittyMunch.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Wayne Beaton.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wayne Beaton
+ *******************************************************************************/
+package ca.rokc.kittymunch.game;
+
+import java.util.Random;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+import ca.rokc.kittymunch.R;
+import ca.rokc.kittymunch.geometry.Point;
+import ca.rokc.kittymunch.geometry.Rectangle;
+import ca.rokc.kittymunch.util.DelayedChangeList;
+
+/**
+ * This implementation purposefully avoids dealing with any
+ * concurrency issues. We assume that the game itself is
+ * running in a single thread.
+ */
+public class KittyMunch {
+
+ private Context context;
+
+ public DelayedChangeList<GameObject> background = new DelayedChangeList<GameObject>();
+ public DelayedChangeList<GameObject> targets = new DelayedChangeList<GameObject>();
+ public DelayedChangeList<GameObject> projectiles = new DelayedChangeList<GameObject>();
+ public Protagonist protagonist;
+
+ private final Rectangle bounds;
+
+ public final int ledge = 50;
+ public final int half_building_top = 300;
+ public final int half_building_bottom = 200;
+ public final int facade = 200;
+ public final int sidewalk = 50;
+
+ public final int drop_speed = 5;
+ public final int protagonist_speed = 50;
+
+ private int targetCreateCountdown = 0;
+ private final Bitmap[] kittyImages1;
+
+ public KittyMunch(Context context, Rectangle bounds) {
+ this.context = context;
+ this.bounds = bounds;
+ kittyImages1 = loadKittyImages();
+ initialize();
+ }
+
+ private Bitmap[] loadKittyImages() {
+ Bitmap kitty1 = BitmapFactory.decodeResource(context.getResources(), R.drawable.kitty1);
+ Bitmap kitty2 = BitmapFactory.decodeResource(context.getResources(), R.drawable.kitty2);
+ Bitmap kitty3 = BitmapFactory.decodeResource(context.getResources(), R.drawable.kitty3);
+ Bitmap kitty4 = BitmapFactory.decodeResource(context.getResources(), R.drawable.kitty4);
+
+ return new Bitmap[]{kitty1, kitty2, kitty3, kitty4, kitty3, kitty2};
+ }
+
+ public void addBackground(GameObject object) {
+ object.setGame(this);
+ background.add(object);
+ }
+
+ public void addTarget(GameObject target) {
+ target.setGame(this);
+ targets.add(target);
+ }
+
+ public void addProjectile(Projectile projectile) {
+ projectile.setGame(this);
+ projectiles.add(projectile);
+ }
+
+ public void remove(GameObject object) {
+ background.remove(object);
+ targets.remove(object);
+ projectiles.remove(object);
+ }
+
+ public void tick() {
+ randomlyCreateNewTargetsOrDont();
+ for(GameObject object : background) {
+ object.tick();
+ }
+ background.update();
+
+ for(GameObject object : targets) {
+ object.tick();
+ }
+ targets.update();
+
+ for(GameObject object : projectiles) {
+ object.tick();
+ }
+ projectiles.update();
+
+ protagonist.tick();
+ }
+
+ Random generator = new Random();
+
+ private void randomlyCreateNewTargetsOrDont() {
+ if (targetCreateCountdown-- > 0) return;
+
+ if (targets.size() > 4) return;
+ if (generator.nextInt(10) > 2) return;
+
+ int direction = generator.nextInt(2) == 0 ? 1 : -1;
+ int x = direction == 1 ? bounds.left : bounds.right;
+ int speed = generateKittySpeed();
+
+ addTarget(new Kitty(kittyImages1, new Point(x, bounds.bottom-(ledge+facade+5 + generator.nextInt(sidewalk-10))), direction, speed));
+
+ targetCreateCountdown = 10 + generator.nextInt(5);
+ }
+
+ public int generateKittySpeed() {
+ return generator.nextInt(5) + 3;
+ }
+
+ public boolean isVisible(GameObject object) {
+ return bounds.contains(object.location);
+ }
+
+ protected void initialize() {
+ int middle = bounds.getMiddle();
+ Rectangle movementBounds = new Rectangle(middle-half_building_top, bounds.bottom-(ledge+sidewalk), middle+half_building_top, bounds.bottom);
+ Rectangle releaseBounds = new Rectangle(middle-half_building_top, bounds.bottom-(ledge+sidewalk), middle+half_building_top, bounds.bottom-ledge);
+ setProtagonist(new Protagonist(context, movementBounds, releaseBounds, new Point(middle, bounds.bottom)));
+ }
+
+ public void setProtagonist(Protagonist protagonist) {
+ protagonist.setGame(this);
+ this.protagonist = protagonist;
+ }
+
+ public void addBrick(Point location) {
+ double p = (bounds.getMiddle() - location.x) / half_building_top;
+ double q = (half_building_top - half_building_bottom) / (facade / drop_speed);
+ addProjectile(new Brick(location, new Point(q*p, -drop_speed), facade / drop_speed));
+ }
+}
28 src/ca/rokc/kittymunch/game/Projectile.java
@@ -0,0 +1,28 @@
+package ca.rokc.kittymunch.game;
+
+import ca.rokc.kittymunch.geometry.Point;
+
+public class Projectile extends GameObject {
+ public int height;
+ private Point velocity;
+
+ public Projectile(Point location, Point velocity, int height) {
+ super(location);
+ this.velocity = velocity;
+ this.height = height;
+ }
+
+ @Override
+ public void doTick() {
+ if (--height == 0) {
+ game.remove(this);
+ }
+ location.moveBy(velocity);
+ }
+
+ @Override
+ public void collideWith(GameObject object) {
+ if (height > 1) return;
+ object.hitByBrick(this);
+ }
+}
138 src/ca/rokc/kittymunch/game/Protagonist.java
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Wayne Beaton.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wayne Beaton
+ *******************************************************************************/
+package ca.rokc.kittymunch.game;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import ca.rokc.kittymunch.R;
+import ca.rokc.kittymunch.geometry.Point;
+import ca.rokc.kittymunch.geometry.Rectangle;
+
+public class Protagonist extends GameObject {
+
+ public Rectangle movementBounds;
+ public Rectangle dropBounds;
+
+ private Point targetLocation;
+
+ private final Bitmap bitmap;
+
+ public Protagonist(Context context, Rectangle movementBounds, Rectangle dropBounds, Point location) {
+ super(location);
+ this.movementBounds = movementBounds;
+ this.dropBounds = dropBounds;
+ bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.hand);
+
+ }
+
+ /**
+ * Set the location that the receiver is to move toward. Note that
+ * it is very likely that this method will be called from a different
+ * thread than the game itself is running in. Care needs to be taken
+ * to ensure that we don't run into any threading issues. The
+ * {@link #tick()} method, for example, assigns this value into a
+ * local variable before doing anything with it.
+ *
+ * Note also that it is assumed that this object is not changed, but
+ * rather is replaced when new values are available.
+ *
+ * A <code>null</code> value indicates that movement is to stop.
+ *
+ * @param point May be <code>null</code>.
+ */
+ public void moveToward(Point point) {
+ targetLocation = point;
+ }
+
+ @Override
+ public void moveBy(Point delta) {
+ super.moveBy(delta);
+ location.moveInside(movementBounds);
+ }
+
+ @Override
+ public void moveTo(Point target) {
+ super.moveTo(target);
+ location.moveInside(movementBounds);
+ }
+
+ @Override
+ public void tick() {
+ // Use a local variable to avoid the need for synchronization.
+ // The targetLocation may be switched (or nulled-out) asynchronously;
+ // the state of the instance should never change.
+ Point targetLocation = this.targetLocation;
+ if (targetLocation == null) return;
+ if (location.isProximateTo(targetLocation, game.protagonist_speed)) {
+ moveTo(targetLocation);
+ targetLocation = null;
+ } else {
+ int distanceToTarget = (int)Math.min(game.protagonist_speed, location.distanceTo(targetLocation));
+ moveBy(location.unitVectorTo(targetLocation, distanceToTarget));
+ }
+ }
+
+ /**
+ * Release whatever we're holding, if anything.
+ */
+ public void release() {
+ targetLocation = null;
+
+ // TODO This may be causing threading issues.
+ if (dropBounds.contains(location)) {
+ // We have to copy the location, since the receiver;s
+ // location is a mutable object that might change.
+ game.addBrick(new Point(location));
+
+ }
+ }
+
+ @Override
+ public void doTick() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void collideWith(GameObject object) {
+ // Don't care about collisions by the protagonist.
+ }
+
+ @Override
+ public void drawOn(Canvas canvas) {
+// Paint paint = new Paint();
+// paint.setStyle(Paint.Style.FILL_AND_STROKE);
+// paint.setColor(Color.RED);
+// canvas.drawCircle(protagonist.location.x, protagonist.location.y, 15, paint);
+
+ canvas.drawBitmap(bitmap, (int)location.x - 35, (int)location.y - 45, new Paint());
+
+ drawRectangle(canvas, movementBounds, Color.GREEN);
+ drawRectangle(canvas, dropBounds, Color.RED);
+ }
+
+ private void drawRectangle(Canvas canvas, Rectangle rectangle, int color) {
+ Paint paint;
+ paint = new Paint();
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setColor(color);
+
+ canvas.drawRect(
+ rectangle.left,
+ rectangle.top,
+ rectangle.right,
+ rectangle.bottom, paint);
+ }
+}
40 src/ca/rokc/kittymunch/game/Score.java
@@ -0,0 +1,40 @@
+package ca.rokc.kittymunch.game;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import ca.rokc.kittymunch.geometry.Point;
+
+public class Score extends GameObject {
+ public static final int MAX_AGE = 50;
+
+ public String value;
+ public int countdown = MAX_AGE;
+
+ public Score(Point location, String value) {
+ super(location);
+ this.value = value;
+ }
+
+ @Override
+ public void doTick() {
+ if (--countdown <= 0) {
+ game.remove(this);
+ }
+ location.y -= 1;
+ }
+
+ @Override
+ public void collideWith(GameObject object) {
+ // TODO Auto-generated method stub
+ }
+
+ public void drawOn(Canvas canvas) {
+ Paint paint = new Paint();
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setColor(Color.BLACK);
+ paint.setAlpha(countdown * 255 / MAX_AGE);
+
+ canvas.drawText(value, (int)location.x, (int)location.y, paint);
+ }
+}
86 src/ca/rokc/kittymunch/geometry/Point.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Wayne Beaton.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wayne Beaton
+ *******************************************************************************/
+package ca.rokc.kittymunch.geometry;
+
+/**
+ * Instances of this class represent a point in two-dimensional space.
+ * The implementation is based on integer (int) values, so some calculations
+ * are approximate. Note that instances are intended to be mutable. A point
+ * can be moved.
+ */
+public class Point {
+
+ public double x;
+ public double y;
+
+ public Point(double x, double y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public Point(Point location) {
+ this(location.x, location.y);
+ }
+
+ /**
+ * Since we use int values to represent everything, it's really not possible
+ * represent an actual unit vector. Instead, as part of the request, we
+ * allow a flexible definition of "unit", returning a vector of
+ * approximately the given length (we are working with ints after all) in
+ * the direction of the given point.
+ *
+ * @param point
+ * An instance of {@link Point}. Must not be <code>null</code>.
+ * @param unit
+ * The definition of unit for the vector; the resulting vector
+ * will be approximately this long.
+ * @return A vector of the requested approximate length
+ */
+ public Point unitVectorTo(Point point, int unit) {
+ double length = distanceTo(point);
+ double h = ((point.x - x) * unit / length);
+ double v = ((point.y - y) * unit / length);
+ return new Point(h, v);
+ }
+
+ /**
+ * Answers true if the receiver is within a certain distance of a point.
+ *
+ * @param point
+ * The point we're testing against. Cannot be <code>null</code>.
+ * @param distance
+ * The distance threshold
+ * @return <code>true</code> or <code>false</code>.
+ */
+ public boolean isProximateTo(Point point, int distance) {
+ return distanceTo(point) < distance;
+ }
+
+ public double distanceTo(Point point) {
+ return Math.sqrt(Math.pow(point.x - x, 2) + Math.pow(point.y - y, 2));
+ }
+
+ /**
+ * Update the state of the receiver such that it is located within
+ * the rectangle.
+ *
+ * @param rectangle Must not be <code>null</code>.
+ */
+ public void moveInside(Rectangle rectangle) {
+ x = Math.min(Math.max(x, rectangle.left), rectangle.right);
+ y = Math.min(Math.max(y, rectangle.top), rectangle.bottom);
+ }
+
+ public void moveBy(Point velocity) {
+ x += velocity.x;
+ y += velocity.y;
+ }
+}
33 src/ca/rokc/kittymunch/geometry/Rectangle.java
@@ -0,0 +1,33 @@
+package ca.rokc.kittymunch.geometry;
+
+public class Rectangle {
+
+ public int left;
+ public int top;
+ public int right;
+ public int bottom;
+
+ public Rectangle(int left, int top, int right, int bottom) {
+ this.left = left;
+ this.top = top;
+ this.right = right;
+ this.bottom = bottom;
+ }
+
+ public boolean contains(Point point) {
+ if (point.x < left) return false;
+ else if (point.x > right) return false;
+ else if (point.y < top) return false;
+ else if (point.y > bottom) return false;
+ else
+ return true;
+ }
+
+ public int getWidth() {
+ return right-left;
+ }
+
+ public int getMiddle() {
+ return left + (right-left) / 2;
+ }
+}
48 src/ca/rokc/kittymunch/graphics/GameRenderer.java
@@ -0,0 +1,48 @@
+package ca.rokc.kittymunch.graphics;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import ca.rokc.kittymunch.game.GameObject;
+import ca.rokc.kittymunch.game.KittyMunch;
+
+public class GameRenderer {
+
+ private final KittyMunch game;
+
+ public GameRenderer(KittyMunch game, final Context context) {
+ this.game = game;
+ }
+
+ public void drawOn(Canvas canvas) {
+ canvas.drawColor(Color.WHITE);
+
+ int width = canvas.getWidth();
+ int height = canvas.getHeight();
+ Paint paint = new Paint();
+ paint.setColor(Color.BLACK);
+
+ int middle = width / 2;
+
+ // Front of roof
+ canvas.drawLine(middle - game.half_building_top, height-game.ledge, middle + game.half_building_top, height-game.ledge, paint);
+ // Left side of roof
+ canvas.drawLine(middle - game.half_building_top, height-game.ledge, middle - game.half_building_top, height, paint);
+ // Right side of roof
+ canvas.drawLine(middle + game.half_building_top, height-game.ledge, middle + game.half_building_top, height, paint);
+ // Left side of facade
+ canvas.drawLine(middle - game.half_building_top, height-game.ledge, middle - game.half_building_bottom, height-(game.ledge+game.facade), paint);
+ // Right side of facade
+ canvas.drawLine(middle + game.half_building_top, height-game.ledge, middle + game.half_building_bottom, height-(game.ledge+game.facade), paint);
+ // Sidewalk
+ canvas.drawLine(0, height-(game.ledge+game.facade), width, height-(game.ledge+game.facade), paint);
+ canvas.drawLine(0, height-(game.ledge+game.facade+game.sidewalk), width, height-(game.ledge+game.facade+game.sidewalk), paint);
+ canvas.drawLine(0, height-(game.ledge+game.facade+game.sidewalk+2), width, height-(game.ledge+game.facade+game.sidewalk+2), paint);
+
+ for (GameObject object : game.background) object.drawOn(canvas);
+ for (GameObject object : game.targets) object.drawOn(canvas);
+ for (GameObject object : game.projectiles) object.drawOn(canvas);
+ game.protagonist.drawOn(canvas);
+ }
+}
24 src/ca/rokc/kittymunch/graphics/ScoreRenderer.java
@@ -0,0 +1,24 @@
+package ca.rokc.kittymunch.graphics;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import ca.rokc.kittymunch.game.Score;
+
+public class ScoreRenderer {
+
+ private final Score score;
+
+ public ScoreRenderer(Score score) {
+ this.score = score;
+ }
+
+ public void drawOn(Canvas canvas) {
+ Paint paint = new Paint();
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setColor(Color.BLACK);
+ paint.setAlpha(score.countdown * 255 / Score.MAX_AGE);
+
+ canvas.drawText(score.value, (int)score.location.x, (int)score.location.y, paint);
+ }
+}
16 src/ca/rokc/kittymunch/util/ChangeListener.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Wayne Beaton.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wayne Beaton
+ *******************************************************************************/
+package ca.rokc.kittymunch.util;
+
+public abstract class ChangeListener<T> {
+ public void objectAdded(T object) {}
+ public void objectRemoved(T object) {}
+}
64 src/ca/rokc/kittymunch/util/DelayedChangeList.java
@@ -0,0 +1,64 @@
+package ca.rokc.kittymunch.util;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This implementation purposefully avoids dealing with any
+ * concurrency issues. We assume that the game itself is
+ * running in a single thread.
+ */
+public class DelayedChangeList<T> implements Iterable<T> {
+ public List<T> objects = new LinkedList<T>();
+ private List<T> objectsToRemove = new ArrayList<T>();
+ private List<T> objectsToAdd = new ArrayList<T>();
+
+ List<ChangeListener<T>> listeners = new ArrayList<ChangeListener<T>>();
+
+ public void add(T object) {
+ objectsToRemove.remove(object);
+ objectsToAdd.add(object);
+ }
+
+ public void remove(T object) {
+ objectsToAdd.remove(object);
+ objectsToRemove.add(object);
+ }
+
+ public void addChangeListener(ChangeListener<T> listener) {
+ if (listeners.contains(listener)) return;
+ listeners.add(listener);
+ }
+
+ public void removeChangeListener(ChangeListener<T> listener) {
+ listeners.remove(listener);
+ }
+
+ public void update() {
+ for(T object : objectsToAdd) {
+ objects.add(object);
+ for(ChangeListener<T> listener : listeners)
+ listener.objectAdded(object);
+ }
+ objectsToAdd.clear();
+
+ for(T object : objectsToRemove) {
+ objects.remove(object);
+ for(ChangeListener<T> listener : listeners)
+ listener.objectRemoved(object);
+ }
+ objectsToRemove.clear();
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return objects.iterator();
+ }
+
+ public int size() {
+ return objects.size() + objectsToAdd.size() - objectsToRemove.size();
+ }
+
+}
Please sign in to comment.
Something went wrong with that request. Please try again.