Archive Page 2

Letting Others Play My Game

GunCore is my first game. Every mistake I’ve ever made in game development, I’ve made on GunCore. Despite my follies, through thick and thin, each month the game continues to grow and it’s finally able to be played outside of my Eclipse IDE.

I made a build a week ago and send it to 5 friends to give it a quick test.  Naturally, it was a disaster. The game is too early in development to be sent to someone without me beside them guiding them away from the incomplete sections.  As I answered my friends questions I realize that my prototype/feature priority needed to be changed. I need to focus more on patching the holes in my prototypes to allow the player to experience and critique the gameplay experience rather than the being lost in incomplete game states.

Since than I’ve been doing just that.  I’ve been cleaning up old test levels, rebalancing player and enemy attributes and temporarily removing all unnecessary, incomplete features.  My goal is to get an alpha build ready and start the play test phase of development.  GunCore is still far from alpha ready but at least it’s heading in the right direction.

Advertisements

New Test-Level Gameplay Video

Just in time for Screenshot Saturday 38.

This level uses the snap-to-grid feature to allow levels to feel more consistant with my old art. Also the new ImagePool class lets me fill the screen with many similar images with little performance difference. Now I don’t feel guilty with flooding the screen and building things out of objects for aesthetics and not just gameplay. I still consider a lot of the gameplay still in early development but here is a test level where timing the melee slash and enemy reload is the key to staying alive.

I whipped up these enemies last night while playing hours of DOOM on my iphone, dancing around imps with dual stick controls.  I liked in DOOM how an enemy’s corpse sticks around to remind you, on return trips, how hard you own (and that you’ve been there before) so  I added corpses to my new enemy monster.  They add the atmosphere I’m looking for but I’m not sure if they’re a final version feature.

Check out the video to see what I’m talking about.

ImagePool Singleton Class

While working on GunCore, Matt and I have been wearing many hats; The designer, programmer, marketing strategist, artist, sound designer, webmaster, and blogger. Because of this rush, I’ve been neglecting some of my code where I’m just programming and not software engineering and I regret it every time I have to modify them.

I’ve been applying to new graduate software eng jobs lately and it really was the excuse I needed to spend more time with the software eng textbooks I refused to sell.  I have been wanting to iterate through some of GunCores code anyway and now I can practice what I’m reading and make GunCore more efficient at the same time.

To start off I’d like to share my ImagePool Singleton Class, its implementation, problems I faced and am still facing and most importantly, the things I think I’m doing correctly but might not be.

Previously in my game each instance of a game object had all of the images associated with it. When an enemy class was created, its image would be loaded and stored in memory. This way, 10 monsters with 20 images for their animation each, will be 200 images in memory; all of which are copies of just 20 unique images.

At first I was just going to declare all of the game’s images at the initialization of the application and make every game object just point to the image they want to display. Now the same image won’t be repeated in memory but as levels and especially chapters change, lots of images will never be used again or will never be used at all.  This looks like a job for a Object Pool.

I wanted to be able to:

  • Store all images in one place
  • Have the ability to dynamically add images
  • Check for and eliminate copies
  • Remove images that haven’t been used recently
  • Provide global access to the entire application

An Object Pool design pattern allows me to encapsulate all the images, check for expiry and copies and a Singleton design pattern enforces the one and only instance of the pool that I will need, as well as global access through out the application.

Here is the implementation that I’m working on. I’m at the point where it’s working, I don’t have any crashes, but I do have some concerns.

//Singleton Object Pool for storing images.
public class ImagePool {

	private static ImagePool instance = null;
	private static HashMap<String, ImageHolder> imageMap = new HashMap<String, ImageHolder>();
	private static int mapSize = 0;
	private static final int expiryCutOff = 1000;
	private static int expireTimer = 0;
	private static int checkTimer = 0;
	private static int checkRate = (int) expiryCutOff / 10;

	private ImagePool() {

	}

	private static class ImagePoolHolder {
		public static final ImagePool instance = new ImagePool();
	}

	public static ImagePool getInstance() {
		return ImagePoolHolder.instance;
	}

	// Returns the image to the string imageName is referencing
	// with rotation and brightness attributes
	public static Image getImage(String imageName, int rot, float darkness) {
		String image = imageName;
		// Force the rotation angle to 0-360
		rot = rot % 360;
		if (rot < 0) {
			rot = 360 + rot % 360;
		}
		// Create unique key for each unique image
		String imageID = imageName.concat("" + rot + "" + darkness);
		// Add new images or update old ones.
		if (!(imageMap.containsKey(imageID))) {
			ImageHolder imageHolder = new ImageHolder(initImage(
					ImagePool.class.getResource(image).getPath(), darkness,
					rot, Color.RED), expireTimer);
			imageMap.put(imageID, imageHolder);
			mapSize++;
			System.out.println("ADDING   imageCount: " + mapSize
					+ " imageID: " + imageID);
		} else {
			imageMap.get(imageID).updateFrames(expireTimer);
		}

		return imageMap.get(imageID).getImage();
	}

	// Called externally every frame. In case of slow computers,
	// using real time will expire objects early so using frames instead
	public static void checkExpiry() {
		expireTimer++;
		checkTimer++;
		// Because this method will be called every frame, the checkRate allows
		// control of the checkExpiry frequency.
		// Currently set to 1/10 of the expire time.
		if (checkTimer > checkRate) {
			checkTimer = 0;
			Set<String> set = imageMap.keySet();
			Iterator<String> iter = set.iterator();
			ArrayList<String> keyList = new ArrayList<String>();
			// add all expired keys into the keyList.
			for (int i = 0; i < set.size(); i++) {
				String s = iter.next().toString();
				if (imageMap.containsKey(s)) {
					if (expireTimer - expiryCutOff > imageMap.get(s)
							.getFrames()) {
						keyList.add(s);
					}
				}
			}
			// Remove all images that have expired keys that are in
			// the keyList
			for (int i = 0; i < keyList.size(); i++) {
				if (imageMap.containsKey(keyList.get(i))) {
					imageMap.remove(keyList.get(i));
					mapSize--;
					System.out.println("REMOVING imageCount: " + mapSize
							+ " imageID: " + keyList.get(i));
				}
			}
		}
	}
}

^ ImagePool Class Source. Edit: I changed the Singleton structure to be more thread safe using the Bill Pugh design.

Let me break it down.

I start with a HashMap called imageMap. I needed a data structure with unique keys and because of the high amount of insertions and deletions, as images expire and are remade, a hashMap seems slightly better then its ordered brethren, the linkedHashMap.

Each unique image needs a unique key and hashMaps always have unique keys so I can check for similar images by checking if the key exists or not.  For a key I decided to use a String that holds the image’s path + rotation degree + brightness which are all the variables to defining a unique image.  Any other image modifiers will have to be done in the art phase and become a separate PNG or I’ll just have to concatenate another variable onto the String. For GunCore, I don’t expect to.

The values for the HashMap imageMap are images but I had to wrap them in a class with an expiry date to track images which have not been requested recently for removal. The ImageHolder class wraps the images.

//ImageHolder Class is created in line 37 of the ImagePool
//Wraps an image with an expiry date so that old images can be removed
public class ImageHolder {

	private Image image;
	private int expireFrames;

	public ImageHolder(Image i, int e) {
		image = i;
		expireFrames = e;
	}

	public Image getImage() {
		return image;
	}

	public int getFrames() {
		return expireFrames;
	}

	public void updateFrames(int f) {
		expireFrames = f;
	}

}

^ ImageHolder Class Source

Every object can be drawn by calling ImagePool like this:

//Global classes can call for an image like this
g2d.drawImage(
	ImagePool.getInstance().getImage(f.getImageName(), f.getRotation(), F.getBrightness()),
(int) f.getX(), (int) f.getY(), this);

^ Game Class Draw Method

Every time getImage is called with a path, rotation and brightness the HashMap checks the key and then either finds it, updates the expiry date and returns the image associated with it’s key, or doesn’t find it and creates it, stores it and returns it.  The goal is to minimise the creating and storing parts.

	public static Image getImage(String imageName, int rot, float darkness) {
		String image = imageName;
		// Force the rotation angle to 0-360
		rot = rot % 360;
		if (rot < 0) {
			rot = 360 + rot % 360;
		}
		// Create unique key for each unique image
		String imageID = imageName.concat("" + rot + "" + darkness);
		// Add new images or update old ones.
		if (!(imageMap.containsKey(imageID))) {
			ImageHolder imageHolder = new ImageHolder(initImage(
					ImagePool.class.getResource(image).getPath(), darkness,
					rot, Color.RED), expireTimer);
			imageMap.put(imageID, imageHolder);
			mapSize++;
			System.out.println("ADDING   imageCount: " + mapSize
					+ " imageID: " + imageID);
		} else {
			imageMap.get(imageID).updateFrames(expireTimer);
		}

		return imageMap.get(imageID).getImage();
	}

^ ImagePool Class Source

Now that I have the expiry date updating I need a method to check them all and remove the expired ones. The expiry date timer does not use real time to expire images.  For fun I tried to run this game on my netbook which looks like it’s running at about 10 frames a second. If I used real time, that slow computer would be even slower as recently used but infrequently used images are expired and replaced over and over again.  If instead I use a frame counter, slower computers will hold the images for the length of gameplay I intended.

I decided to encapsulate this expiry frame counter in the imagePool class, calling checkExpiry every frame and making it only really check the HashMap for expired images a fraction of those times. Alternately, I could just not call checkExpiry every frame and decide when to in the already crowded main game loop’s class. The first way allows me to stay on one page of code and not bounce around so I choose it.

Currently the rate of checking for expired images is 1/10 of the time allowed before an image expires. This seems to be a fair assumption for now. The real rate would be the optimization of performance and memory management. A challenge for another day.

	public static void checkExpiry() {
		expireTimer++;
		checkTimer++;
		// Because this method will be called every frame, the checkRate allows
		// control of the checkExpiry frequency.
		// Currently set to 1/10 of the expire time.
		if (checkTimer > checkRate) {
			checkTimer = 0;

^ ImagePool Class Source

The checkExpiry method iterates through the whole hashMap and stores all expired keys into an arrayList and then deletes all the keys in the arrayList out of the hashMap.  When I tried to delete the keys from the hashMap on the fly I was having null pointer errors as I assume were caused by removing images while iterating through.

</span>
<pre>// add all expired keys into the keyList.
			for (int i = 0; i < set.size(); i++) {
				String s = iter.next().toString();
				if (imageMap.containsKey(s)) {
					if (expireTimer - expiryCutOff > imageMap.get(s)
							.getFrames()) {
						keyList.add(s);
					}
				}
			}
			// Remove all images that have expired keys that are in
			// the keyList
			for (int i = 0; i < keyList.size(); i++) {
				if (imageMap.containsKey(keyList.get(i))) {
					imageMap.remove(keyList.get(i));
					mapSize--;
					System.out.println("REMOVING imageCount: " + mapSize
							+ " imageID: " + keyList.get(i));
				}
			}

^ ImagePool Class Source

I’ve noticed that if I load a level and immediately load a different one, both level’s images will fill up the hashMap and zero frames of expiry time will pass.  After about 10 levels I can fill up the hashMap and cause a full heap error.

To combat this I clear the hashMap of all images before every level load but a level with to many different images being requested at the same time could still crash the game.  Maybe I’ll add a max size to the hashMap to catch overflow.

As the game runs I get a list of added and removed images as they are requested (and are not available) and expire.

Printout of ImagePool actions

That’s my first attempt at an ImagePool. The game is currently using it without any noticeable problems and levels with large amounts of the same wall run smoother. I’m new to posting code publicly and have to admit it’s a little humbling but there is always more to learn, so any feedback at all is appreciated.

Slackin

You’ve caught me redhanded!

I’ve been slacking on my blog so here’s a recap of what we’ve been up to since last.

Playing With Art

I’ve been programming an image manager and when I needed a distraction from the code I decided to play with some art styles.

Our current walls have black borders around them, causing overlapping images to show their edges. This style creates a cut and paste look and I feel works well with my more cartoony colourful art.

Current Black Border Art Style

As an experiment I created some very simple images without black boundary lines or to much detail.  The level looks more continuous then previous. I can’t tell if I like it more or less without a test with some better placeholder art but it does give me a sense of mashed potatoes.

No Border, Less Detail Art Style

I had finally got around to implementing a grid on the level editor and snap-to-grid functionality to provide me with pixel accuracy placement of level objects. I had to draw up some quick pixel walls to give it a test.  This looks more like a regular 2D pixel game but my level editors rotate function ruins pixel art, so everything needs to be drawn to angle.

Pixel Grid Art Style

A.I. Fun

Matt has been working hard on our Flyer enemy A.I.  At first they would just chase the player but now they follow a state machine of actions that really brings them to life. The video below shows me playing around with a few.

Software Engineering

I’ve been working on a new image management system for the game.  I’m implementing a ObjectPool design pattern to manage all of the games images more efficiently.  I’m going to save the details for my next post. It’s almost done.

Next

I’m going to focus on programming.  Programming is my craft.  I’m going to limit my other indie game dev duties for a while and get back to the coding.

Framed Levels

For the last week Matt and I have been working hard at adding some camera control to Guncore. The game doesn’t need very much but as game designers we want to have more design options and room in the game for more potential.

This demo video shows the changes to some parts of our levels by adding level frames.

This is the first iteration. So far it helps us hint to the player which holes in the level are death and which are safe, maximize screen real estate in arena/boss levels, and show level start and end.

Level Editor Prototype

This video shows the basics of our level editor.

Note: The music track for the video is missing.

In this video I tried to build the level in the order that I developed the editor. Features were added based on what I felt the game needed at the time to make me stop staying, “something’s missing”.

First, all I had were foreground walls and collision walls; the level looked empty, each platform felt like it was floating. I tried to fill them in with more wall images but it looked to cluttered.

Black rectangle walls were added to fill in the levels and make it look like each separate platform is part of a whole world.  Copies of each walls image were added with 50% brightness to use as background walls. Now the levels had enough depth for me have fun again.

Once I threw in enemies and items, the level editor started doing its job and my efforts could be placed elsewhere (eg: adding more guns) until that, “something’s missing” feeling comes back.

My First Game

This is GunCore (working title). It’s a Megaman/Contra inspired  2D platformer that my friend and I have been working on for some time.

I programmed the game in Java, drew the art with pencil and paper and used Gimp for color. It’s all placeholder art but I admit it is nice to see my poor drawings come to life on the screen.

Were still prototyping and brainstorming so the game isn’t close to ready and this is my first game so I dont really know what I’m doing, but the game is already fun. I must be on the right track.

I wanted to start this blog after I did a two person play test and learned a great deal from watching someone, other then me, play my game for the first time. It showed me how important, in early development, it is to get others opinions. Though the game is far away from public beta this blog will be a place to publicly post design decisions and features in hope to get some constructive feedback.

Right now I just wanted to give you a peek at what I’ve been working on. As I get more organized I’ll have a lot more info available.


Follow the dev on Twitter.

About Me

Orun Irunmale
I'm Orun, an indie game developer. This is my development blog for all my software escapades.

RSS oruncode RSS

  • New Site & New Blog January 25, 2013
    All my blogging and game projects will be on our new site.  Come check it out. This is my last post here at oruncode.  Lazorun.com  Lazorun.com/blog
    oruncode
  • My Ludum Dare #23 Game April 25, 2012
    Made in just 48 hours, The Last Ride Home is a driving game that will test your reaction timing and your persistance as you try to drive through as many levels as possible. Here is a gameplay video. The game can be played in the Chrome Browser. You can play it now here is a link […]
    oruncode
  • March is my Month of JavaScript March 21, 2012
    March is turning out to be the month of JavaScript for me. Ever since I was asked to copy this game for a job interview a few weeks ago, I’ve been enjoying making anything I can think of with JS and HTML5 canvas. This was my first JS project. It’s an image matching game. I jacked […]
    oruncode