Saturday, August 24, 2013

Game Syncing and Thermometers

I've been working with the Google Play Game Services some more trying to get a player's unlocked levels to sync for accounts across different devices in the scrolling shooter. The Game Services have some cloud saving abilities, but after spending a lot of time trying (and failing) to get it working, I decided to go a different route. Google's documentation of the cloud saving services leaves a lot to be desired, and I found their one example of how to implement it to be a bit of a complicated mess. For my solution, I tried something else, and it is not what Google would ever intend for someone to do and it probably isn't very good practice, but it's working well for me. What I'm doing is when the player starts up a game, I use the Game Services API to get a buffer filled with all the available achievements for the account. Then I step through the buffer and record how many of the achievements are unlocked. Since in the scrolling shooter game, the only achievements will be for completing a level, the number of achievements that are unlocked for the account is the same number of levels completed. Obviously this method wouldn't work if I had achievements for other things like reaching a certain score or beating a level in a certain time, but I have no intention of adding any such achievements so this works out pretty well. The game has a saved preference of how many levels are unlocked, so after I get how many achievements the player has, I compare that to the saved value of unlocked levels. If the number of unlocked levels is less than the number of achievements, I update the unlocked levels to be correct for the account. If the max number of unlocked levels is already saved in the preferences then I don't have to check for this level syncing in the first place and I just avoid any unnecessary calls to the Game Services. It's not how Google intends for people to do things and it's a bit of a hack job, but it's also pretty solid and it seems to be working well, so I'm going to stick with it on this particular app.

In addition to working on the Game Services for my scrolling shooter, I've been adding a bit to my platformer as well. Just recently I added my "danger meter" to the HUD. Its a thermometer and it shows how close the lava wave chasing the player is. As the lava wave gets closer, the level of the thermometer rises, filling the gauge when the lava actually reaches the player. It's really nice because you now have a way of telling when the lava is getting close before it actually appears on the screen. For the most part, its easy to keep the lava far enough away that the thermometer is empty, but since the lava speed ramps up over time, it will eventually catch up and the level of the meter rising lets you know its coming.

Here are a couple screenshots of the thermometer in action:


Monday, August 19, 2013

Gem Collecting and Game Services

I've recently updated a little bit of my platforming game. It is entirely cosmetic but I've made it so when the player collects a gem, the gem shoots up into the top left corner where their score is. It isn't that big of a change, but I think I pulled it off pretty well and it definitely looks cool, especial when you collect a couple gems right in a row. I don't think any players will need the confirmation that they did, in fact, collect the particular gem, but I suppose that is an added benefit of having the gem in question slide up to their score text.

I've also been playing around with some of the new Google Play Game Services on the scrolling shooter. I've added a leaderboard and achievement for each level and a Google+ login button on the main screen. Things seem to be going pretty well. I also made it so you now start only with the first level and to unlock each level, you have to first beat the previous level. I might try to get some cloud saving going on since its a part of the Google Plus Game Services package, but the documentation isn't all that great so I might have to scrap it. Conceptually though it would be pretty cool to be able to beat a level on your phone and have it unlocked on say a tablet as well. I'm also going to look into some in-app purchases stuff. All my previous projects have just had a lite version and a full version but I want to start just releasing a single version with limited access and then you can make an in-app purchase to remove ads and unlock all content. So I'm going to be checking that out really soon.

Wednesday, August 14, 2013

AndEngine PathModifier Tutorial

A lot of my recent AndEngine projects have used a PathModifier for one reason or another. I have a solid understanding of them now and they are pretty straight forward after you get to know them, but I decided to write this tutorial for people who are looking to start using some path modifiers, but don't know where to start. This tutorial assumes the reader is somewhat familiar with AndEngine and has a basic understanding of creating sprites and the like.

Simple Pathing
So, lets say we want to move a sprite along a path. Well first we need a sprite, but there is nothing special we need to do to set the sprite up for pathing. We just make a normal sprite:

  Sprite ourCharacter = new Sprite (100, 100, CharacterTextureRegion, this.getVertexBufferObjectManager());  

Now we have our sprite and we want to move it from its starting location at the coordinates (100, 100) to the coordinates (600, 350). We need to make a new path object for it to follow. In AndEngine, a Path is a series of coordinate points that the sprite will follow. It is important to remember that the sprite's origin point, or the top left corner, is what will actually moving to the points you specify in your path. So lets make our path:

 Path ourPath = new Path(2).to(100, 100).to(600, 350);  

In the first set of parentheses after the word "Path" we specify the number of points we are going to have in our path. In this case, we have two points. After that, we tack on our coordinate points using the ".to(x, y)" function. We start with our origin point in the series of points, then we add on any more points we want in the path.

We now have our Path object set up. We want to make our Sprite follow that path. To do this, we need to add our PathModifier on the Sprite using a call to registerEntityModifier and passing in a new PathModifier.

 ourCharacter.registerEntityModifier(new PathModifier(3.0f, ourPath, EaseLinear.getInstance()));  

When we make the PathModifier, we pass in a float representing the number of seconds we want it to take for the sprite to follow the path (in this case it is 3 seconds), our Path object, and and Ease Function. The ease function is how the sprite is going to follow the path. For example, the EaseLinear in the code above will have the sprite move from one point to the next at a consistent speed. When moving a character sprite along a path, I like to use EaseSineInOut, which will cause the sprite to slow down right before they reach a point in the path, and then speed up after leaving a point. I feel it gives a more "natural" feel as things slow down to change direction and such. There are a whole host of EaseFunctions to use. A few are listed below, but there are more and you can check out the AndEngine example app under "Modifiers & Animation" to see them in action.

EaseFunctions
  • EaseLinear
  • EaseBounceIn, EaseBounceOut, EaseBounceInOut
  • EaseElasticIn, EaseElasticOut, EaseElasticInOut
  • EaseSineIn, EaseSineOut, EaseSineInOut
  • EaseStrongIn, EaseStrongOut, EaseStrongInOut
And there you go. Our sprite will now move along the path we specified.

"Advanced" Pathing
The path we just did is cool, maybe for something like a title image sliding onto the screen or our character walking from one point to another. But maybe we want our character to patrol the perimeter of a square building and we want it to move along the path over and over. Well, we can do that.

First, we are going to make a longer, square path:

 Path ourPath = new Path(5).to(100, 100).to(100, 300).to(300, 300).to(300, 100).to(100, 100);  

Notice that this time our path has 5 points. But why do we need 5 points? We are moving in a square, and our square only has 4 corners. Well, we need the first one to establish the origin point of our path and the additional 4 points to move the sprite 4 times (sliding along the 4 sides of the square). We want the path to be a continuous loop, so our first point and our last point are the same. In the first figure in the image below, you can see the path the sprite will take with all five points. The second figure shows the path the sprite will take if we only use 4 points on the path.

So, we now have our path set to follow a square path and return to its original location just by plugging it into our PathModifier up above. But, we want our sprite to repeat this path indefinitely. So lets add in a loop entity modifier, shall we?

 LoopEntityModifier ourLoop = new LoopEntityModifier(new PathModifier(5.0f, ourPath, EaseSineInOut.getInstance()));  
 ourCharacter.registerEntityModifier(ourLoop);  

And there we go. Our sprite will move in this square continuously until you get rid of the entity modifiers on it.

But we aren't done yet. Path modifiers can be set up with listeners to determine when the path is finished, started, or hits a point on the path. Let's have our sprite do some things as it moves around our square. We'll set up our path modifier with an IPathModifierListener. The listener will require us to override 4 functions: onPathStarted, onPathFinished, onWaypointStarted, and onWaypointFinished. We'll add the path modifier listener and its requisite functions to our LoopEntityModifier.

 LoopEntityModifier ourLoop = new LoopEntityModifier(new PathModifier(speed, path, new IPathModifierListener()  
 {  
      @Override  
      public void onPathFinished(PathModifier pPathModifier, IEntity pEntity) { }
  
      @Override  
      public void onPathStarted(PathModifier pPathModifier, IEntity pEntity) { } 
 
      @Override  
      public void onPathWaypointFinished(final PathModifier pPathModifier, final IEntity pEntity,  
                final int pWaypointIndex) { }  

      @Override  
      public void onPathWaypointStarted(final PathModifier pPathModifier, final IEntity pEntity,  
                final int pWaypointIndex) { }  
 }, EaseSineInOut.getInstance()));  
 ourCharacter.registerEntityModifier(ourLoop);  

There we go. We're all set. We just need to add anything we want it to do. We'll start with the onPathFinished function. Lets say we have an integer variable called "LoopCount" and we simply want to increment the loop count whenever we the loop finishes. Piece of cake.

      @Override  
      public void onPathFinished(PathModifier pPathModifier, IEntity pEntity)   
      {  
            LoopCount++;  
      }  

Now, lets rotate our sprite to 180 degrees at the start of each path if LoopCount is even. Why would we do this? Nobody knows, but we can, so we're going to.

      @Override  
      public void onPathStarted(PathModifier pPathModifier, IEntity pEntity)   
      {   
           if(LoopCount % 2 == 0)  
                pEntity.setRotation(180);  
           else  
                pEntity.setRotation(0);  
      }  

In the code above, we check if the loop count is even like we wanted and set the rotation to 180 degrees if it is, or 0 degrees if it is odd. Notice that when we set the rotation of the sprite, we actually use the reference that was passed into the function. Here we have called it pEntity.

There we have it. Our sprite will swap rotations every time it loops around the square. We're almost done with our path here but we have one final thing we want our sprite to do. Every time the sprite reaches the bottom left or the top right corner of our square path, we want to Scale our sprite up to double its normal size and then reset the size back to normal on the other two corners.

Now, here is where things start to get tricky. First, lets mention how "onPathWaypointFinished" and "onPathWaypointStarted" work. In both of the functions, an integer value is passed in, which represents the point on the path that has resulted in the function call. For example, if it is the first point on the path, the number passed in will be 0. With "onPathWaypointFinished", the function is called sprite reaches a point on the path. Alternatively, "onPathWaypointStarted" is called as soon as the sprite starts heading to a point on the path from the previous point. In both cases it is important to realize that for the listener, the origin point is not point 0. Point 0 is the first point the sprite will move to after leaving the origin point.

We want our sprite to change scale every time it reaches the bottom left corner (point 0) or the top right corner (point 2) and have it change back to normal at every other point. Since we dont want it to scale as it move towards the bottom left corner of our path, but rather when it actually reaches the point, we are going to use "onPathWaypointFinished" instead of "onPathWaypointStarted". We're going to use a simple switch statement and the passed in value of pWaypointIndex:

      @Override  
      public void onPathWaypointFinished(PathModifier pPathModifier, IEntity pEntity,  
                int pWaypointIndex)             
      {   
           switch(pWaypointIndex)  
           {  
                case 0:  
                case 2:  
                     pEntity.setScale(2.0f);  
                     break;  
                default:  
                     pEntity.setScale(1.0f); 
                     break;
           }  
      }  

And there you have it. Our sprite is now moving in an endless square shape, upside down every time the loop count is even and doubling its size every time it reaches the bottom left or top right corners.

Path modifiers can be insanely helpful for things in your app. Making title images slide in from off screen, having characters move around, or perhaps having an item slide off the screen after your character collects it. There are a lot of possibilities and a strong understanding of Pathing is great to have if you are working with AndEngine.

I hope this tutorial helps anybody who might stumble across it. If I need to explain anything more clearly or I left something out, please leave me a comment or suggestion.

Monday, August 12, 2013

Breakable Platforms and Ramps

I've added a couple things to the platform game that I think are pretty cool. First, there is a new platform type that the player has to break through to advance. They can do this by jumping (swiping up on the screen) and then swiping downwards to perform a "Ground Pound" move that shatters the platform allowing the player to fall through. In the screenshot below, you can see the player breaking through a platform.

Also noticeable in the screenshot above is a ramp section in the tunnel. I've added a few new sectors or rooms to the game that have these ramp sections. They go up or down and provide a different type of area that the player can run through, especially in sections like the one in the screenshot below with a lava pit at the top or bottom of a lava pit.

Another addition that I've made is one that I think is pretty cool, but it is also purely cosmetic. When the tunnel background tiles (the pink squares with the blue star in them) are spawned for a sector, there is now about a 10% chance that the background tile will be spawned as a different image. Currently it is just a different color star in the circle, but eventually it can be something cool and related to the theme that will break up the background a little bit. In the screenshot below you can see an instance of two of the "rare" green star tunnel background tiles among the more common blue star tunnel backgrounds.

The game is really coming together now, and besides the addition of some more sector types, I've basically added all the functionality I was wanting. I am hoping to add a couple more HUD things though. One, a meter (possibly in the form of a thermometer to go with the lava theme) on the left side of the screen that acts as a gauge to show the player how close the lava is to reaching them. Second, I would really like to add in something for the gems the player collects where, instead of having them just disappear, the move from the place they are collected up to top left corner of the screen where the score text is located.

Friday, August 9, 2013

Scrolling Backgrounds and Lava Pits

I've been doing some more work on my platforming game. I'm up to 12 regular sectors now plus a bonus sector. The bonus sector is a really easy hallway with no real obstacles and a lot of easy to collect gems, but the odds of getting one are also much lower relative to the other sectors. I also have a scrolling background going behind the level now that moves at a different rate than the player. I think it gives it a cool look to have the scrolling going on whenever you run or change directions.

After play testing the game quite a bit, I decided that it was too easy to simply outrun the lava wave for long periods of time. Eventually it will catch up to you because it slowly revs up in speed, but you can still go pretty long stretches before it hits you. To up the difficulty a little without making the lava wave just impossible to outrun, I added some lava pit type obstacles to some of the new rooms I've made. These are just little animated pools of lava that the player has to jump over because touching one is an instant game over. They are pretty cool and I'm happy with how they turned out, but in some places I was having trouble with the jumping and making it over the lava pits. The jumping was a little unforgiving so I tweaked it a little to be a bit more accommodating and now players won't have quite so hard a time jumping from platform to platform.

Below we have a screenshot with one of the new lava pits and the background. Its just a dark brown background with some lighter brown spots. I'm thinking this game might eventually looks like its taking place under ground, so I made a "dirt-like" background, but it still looks weird with all my brightly colored platforms and such. Plus it's just a bad background in general. Anyway, here it is: