Sunday, 30 December 2012

Unity, Futile & C# - Part 2

If you read the first part of this series you will know I am transitioning from Corona SDK to Unity. More specifically Unity and the 2D rendering framework, Futile. The purpose of this blog post is to further diarise the process as well as providing some level of documentation to Futile which is still in its infancy.

Day 8
This was very much a day of highs and lows. To match to the iOS version of Astavoid I wanted to replicate the screen transitions. However, within Futile at the moment there are no transitional effects between FContainers so they snap rather unattractively. Thankfully, and purely by chance, my screen transitions were straightforward and just gave the effect with text animations. As this has already been expressed in previous entries, this was achieved with the excellent GoKit by prime[31]. Definitely have a play around with this and to help you its featured heavily within the Banana Demo project.

With this in the bag I thought I would experiment with getting GameCenter integrated into the game as the one on the Appstore features OpenFeint which is now deprecated. I started off thinking this was going to be a straightforward exercise but got a little confused with how the GameCenterPlatform class worked with Unity, scripting and Futile.

This is where my day started to go a little downhill and this was typical of not knowing enough about how Unity worked. My first mistake having implemented the code was wondering why ads weren't appearing within the Game window of the Unity editor.

What I hadn't done was to enable GameCenter under iTunes Connect for a unique app. Only with this will ads works. To enable follow these steps:

  • Log on to iTunes Connect
  • Click on Manage Applications
  • Ensure you have an app which is in an edit state such as waiting upload or an equivalent to modify GameCenter state.
  • Click on Manage Game Center
  • Click "Enable for Single Game."
  • Click Disabled.

The Disabled button toggles between Disabled and Enabled. To disable your app for Game Center testing, click Enabled. Once you disable, you will no longer see your app in the Game Center sandbox. You are only permitted to disable up until a version of your app goes live with Game Center. Enabling Game Center for testing unlocks the Game Center interface to allow you to set up your leaderboards and achievements.

Once I had set this up I created one Leaderboard and one achievement to ensure there was content.

Alas, still no test advert coming through. It was at this point I thought that maybe they didn't come through within the editor and I need to test on my device. This was my second mistake of the day.

For some reason I didn't realise it was packaged into an Xcode project. Having come from Corona SDK this step didn't happen it just got compiled and you dragged the compiled .app file onto the iTunes to add to your device. This was when I realised I hadn't setup the bundle identifier properly either.

The next mistake I made was trying to compile the xcode project to the Xcode simulator. The reason I was trying this was that I wanted to ensure the project worked before trying to put it to my device. I was getting some fundamentals errors on compilation, over 200 in fact, which I felt just couldn't be right. After some twitter conversations and scouring the internet I found you can only compile to the device.

So after some wasted hours I now had my app on my device, but still no adverts. It was time to call it a day.

Day 9
A new day brought a clearer head and renewed vigor. When I first started out with game development I wanted to write my own code and therefore learn and understand the most. But having done it now for a year and having to balance my time with a full time job and two young children, I've concluded that using third party plugins is ok. Yes there is a cost to them sometimes but I weigh that up to cost I put on my spare time. Yes I may never make it back on my games in the near future but for the sake of $20 there is no point me struggling for a week trying to get something to work.

This clarity was reached to some degree during my investigations on Day 8 when I repeatedly came across postings and recommendations for prime[31]'s GameCenter and Ad plugins. Having already experienced the ease with which their GoKit was implemented I decided to take the plunge and bought the GameCenter and AdWhirl plugins.

The plugins are excellent and can be setup with a few very easy steps.

For AdWhirl first setup an account and get your Publisher ID as this is what the prime[31] plugin requires. In regards to ad providers I chose a distribution of iAd (70%) and AdMob (30%).

Assuming you have followed Matt's banana project to a point you would imported a futile package, dragged to the Unity hierarchy and assigned a script to your Futile game object. With this assumed open your script and declare a private variable such as private string publisherId = "your id goes here"; . Then within Start method, and this apparently is the important bit, make AdWhirlBinding.init( publisherId ); your first call.

Having implemented this I built for my device and tested and BINGO! adverts start coming through.

Again, buoyed on by this working I turned my attention to GameCenter. I had assumed I had setup everything up in the iTunes Connect steps explained above so I set about implementing it.

Like all implementation's of GameCenter you must first check that GameCenter is available and then you authenticate. For the purposes for testing I am resetting the achievements each time to ensure the banners etc come in. The code, again in my Start method is:

// Do gamecenter stuff ... Is GC available?
if(GameCenterBinding.isGameCenterAvailable())
{
	// Yep looks like it is so authenticate the player;
	GameCenterBinding.resetAchievements();
	GameCenterBinding.authenticateLocalPlayer();
	GameCenterBinding.retrieveAchievementMetadata();
	GameCenterBinding.showCompletionBannerForAchievements();
}

Before testing on your device ensure you log out of GameCenter as when testing on your new game and you log in it will go into Sandbox mode while in development.

Success!!

Day 10
A very successful day on day 9 so to continue on with this I thought I would hook up the achievements when a certain distance was achieved. All I do is create a method within the Update method of my game scene to check whether a certain diatance has been achieved:

void checkAchievement(int _score)
{
	if(Main.instance.BestScore == 0)
	{
                // First play
		Main.instance.BestScore = _score;
		GameCenterBinding.reportAchievement( "AA001", 100.0f );
	}
	if(_score >= 5000 && _b5000 == false)
	{
                // Distance achieved
		GameCenterBinding.reportAchievement( "AA002", 100.0f );
		_b5000 = true;
	}
	if(_score >= 10000 && _b10000 == false)
	{
		GameCenterBinding.reportAchievement( "AA003", 100.0f );
		_b10000 = true;
	}
	if(_score >= 15000 && _b15000 == false)
	{
		GameCenterBinding.reportAchievement( "AA004", 100.0f );
		_b15000 = true;
	}
}

If a score has been reached then via the GameCenterBinding i.e. our prime[31] plugin, it sends a message to iTunes connect to see if an achievement has been completed. This is the case because we provide the id of the achievement and the percentage complete. As I specified GameCenterBinding.showCompletionBannerForAchievements(); in my initialisation method the player will get instant satisfaction as the achievement banner will be shown. This all happens on a separate thread so no effect on the game's performance.

The next challenge was to take on the music and sound effects within my game. I slightly misunderstood how this worked and didn't take advantage of Futile's sound manager, FSoundManager. So what I chose to do with this was to adapt the Banana project implementation and create a separate sound player class:

public class SoundPlayer
{
	static public void PlayBlipSound()
	{
		FSoundManager.PlaySound("Blup", 0.95f);
	}

	static public void PlayMusicSound()
	{
		FSoundManager.PlayMusic("music", 0.3f);
	}
}

This implements the in-game music and the button sound effect. The gotcha I had here for a little bit was I didn't notice the difference between the methods of PlaySound and PlayMusic. All I now need to do is within my Start method of my main class is to call SoundPlayer.PlayMusicSound(); and viola music a go-go. Similarly, in my SignalRelease (eventhandler) methods for my buttons I call SoundPlayer.PlayBlipSound(); to have a sound effect when my buttons are touched.

Day 11
Jumping around a little bit I refined the resolution logic:

FutileParams fparams = new FutileParams(true, true, false, false);
fparams.AddResolutionLevel(480.0f, 1.0f, 1.0f, "");
fparams.AddResolutionLevel(960.0f, 2.0f, 2.0f, "-hd");
fparams.AddResolutionLevel(1024.0f, 2.0f, 2.0f, "-hd");
fparams.AddResolutionLevel(1280.0f,	2.0f,	2.0f,	"-hd"); //Nexus 7

and worked on my Rocket retina graphics. Again, going back to old faithful in Texturepacker and recreating atlases with the appropriate suffixes.

I also worked on touch logic whereby a user clicking on the screen would allow the rocket to change "depths" giving the illusion of going in and out of the asteroids and in turn running the sprite animation of the rocket.

Day 12
I am unconvinced about whether the accelerometer is the right way forward for this rewrite. However, I want to make sure I don't over engineer this game as that was the original control system and move on to pastures new and new learnings. What I did decide to do is implement a Dpad and evade button just to see how it works.


I wanted to keep the style minimalist and non-intrusive as possible. How I implemented was to create shapes. One of the complete Dpad and then a further 4 for each direction which is then created as a separate FButton and placed over the top of the complete image. The evade button will be used to run the rocket sprite animation and change the alpha of the asteroids so the player knows which asteroids to avoid. Also a little rearranging on the screen to ensure it doesn't become too crowded. Tested on various resolutions to ensure all sits correctly.

Day 13
Back to graphics and animation today and that is to create a rocket flame / exhaust. I had a slight headache over how to implement this. In the current version using Corona this is a particle system using a third party plugin called Particle Candy which was very easy to use. However, the new Unity particle system Shuriken was something that my novice experience was struggling with and not one I could see how it could be directly implemented using Futile.

Instead I chose to animate via Flash and export the frames from Flash into my atlases and create an object to play and scale the exhaust appropriately. The effect I am pleased with but feel I will need to tackle the particle system sooner rather than later.

Day 14
Big subjects were tackled today, collision detection and multi-touch. Let's start with the latter.

Multi-touch is important for my game as I want to move and evade at the same time and the normal signal release (eventhandler) won't even queue messages as its first come first served.

I'll confess I made a major oversight with implementing this and wasted a lot of time. An important point is to ensure you also inherit your class from FMultiTouchableInterface and then to update your Stage Handlers to include and remove multitouchtargets.

Code:
override public void HandleAddedToStage()
{
	Futile.instance.SignalUpdate += HandleUpdate;
	Futile.touchManager.AddMultiTouchTarget(this);
	base.HandleAddedToStage();	
}

override public void HandleRemovedFromStage()
{
	Futile.instance.SignalUpdate -= HandleUpdate;
	Futile.touchManager.RemoveMultiTouchTarget(this);
	base.HandleRemovedFromStage();	
}

with the final thing being is to implement what should happen when multiple touches occur with the public void HandleMultiTouch(FTouch[] touches) method. This should now allow your game to detect and react to multiple touches.

The next thing to tackle was collision detection. I managed to setup a collision detection of sorts by again having a method within the Update method checking whether one FSprite's position overlapped with another FSprite's i.e. rocket and asteroids, While it worked I found it wasn't responsive enough.

Day 15
Having thought about this some more I was coming to a realisation that maybe I needed to dig a little further into the Physics system. While there isn't one setup specifically within Futile the community has written FPhysics which allowed more realistic collisions to happen between objects. This in itself through up some interesting points of research. The main problem still was that neither Futile nor FPhysics implement fully a method to programmatically initialise rigidbody and in turn a collider in order to take advantage of collision detection inbuilt to the Unity Physic system. Where it should be possible to create something like the following:

void OnCollisionEnter(Collision collision) {
    foreach (ContactPoint contact in collision.contacts) {
        Debug.DrawRay(contact.point, contact.normal, Color.white);
    }
    if (collision.relativeVelocity.magnitude > 2)
        audio.Play();
    
}
this will not fire in either of the two earlier instances. On discussion with Matt what it has highlighted is that it is very possible but in my novice state my understanding of Unity's components means that I am going round in circles.

So that brings me on to what to expect from part 3 of this series. The focus will be on bridging the gap between Futile and 2D in Unity to tackle the particle system (Shuriken) and the physic system to implement an equivalent experience to my Corona SDK game.

It should be noted for those that use Corona that this seems like a huge amount of work when Corona wraps this all up for you and that is indeed true and one of its big advantages. However, I have seen enough of the potential of Unity and getting familiar with its setup to know the short term pain will be more than worth it.

Until next time, Happy New Year!

4 comments:

Nici G said...

Hey - I've been using Prime31 Game Centre plug-in and came across an issue that if an achievement has already been rewarded to the player, if they satisfy the parameters of that achievement again the banner will trigger again...

I've been looking for a way around this that was simple, but no luck. What did you do?

James Parker said...

Hi Nici G

It sounds like you aren't setting your achievement to 100%.

First up on my main page I do something like this

// Do gamecenter stuff ... Is GC available?
if(GameCenterBinding.isGameCenterAvailable())
{
// Yep looks like it is so authenticate the player;
GameCenterBinding.authenticateLocalPlayer();
GameCenterBinding.retrieveAchievementMetadata();
GameCenterBinding.showCompletionBannerForAchievements();
}

Then when checking an achievement I do something like:
if(Score == 1800 && !PlayerPrefs.HasKey("1800"))
{
GameCenterBinding.reportAchievement( "01", 100.0f );

PlayerPrefs.SetInt("1800", 1);
}

Nici G said...

Thanks.... yeah I had originally used PlayerPrefs to track a player's achievements... And I would delete those prefs should another player log in to the GC from in the game... I had it working quite perfectly.

Then Prime said I should be using getAchievements method to load the current players data.... I spent 10 hours trying to make that happen! I'm still new to C# and Events/Listeners, so it's been impossible for me. Someone finally said that i need to do this...

// Fired when loading achievements completes successfully
public static event Action> achievementsLoaded;

"Just loop through and check for yourself"

Problem is, I have no clue how to do this. I know how to loop etc, but not sure how to do it with an event and what it spits out.

mygamingproject said...

Not sure if this is you asking the question but try here:

http://stackoverflow.com/questions/16554445/unity4-and-prime31-game-center-plug-in-event

Post a Comment

 
;