android

Auto Resize TextView for Android using Mono for Android

AutoResizeTextView Example

If you need your TextView to automatically shrink the text to fit (rather than truncating), Andreas Krings has a great solution. However, this solution is written in Java rather than C#. So here I present a version ported to Mono for Android using C#.

The implementation is pretty much identical, with a default minimum size of 10dp. The TextView will then attempt to find the largest size possible for the text that will fit the frame (the one limitation is that only the horizontal dimension is taken into account), with a maximum size of the initial size; and a minimum size of 10dp (unless overridden).  Usage is the same as well:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/com.danclarke.AutoResizeTextView"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <TextView
        android:text="Normal TextView"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textView1" />
    <TextView
        android:text="@string/longString"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="25dp"
        android:height="50dp" />

    <TextView
        android:text="AutoResizeTextView"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textView2"
        android:layout_marginTop="20dp" />
    <AutoResizeTextView.Controls.AutoResizeTextView
        android:text="@string/longString"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="25dp"
        android:height="50dp" />

    <TextView
        android:text="AutoResizeTextView with minTextSize"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textView3"
        android:layout_marginTop="20dp" />
    <AutoResizeTextView.Controls.AutoResizeTextView
        android:text="@string/longString"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="25dp"
        android:height="50dp"
        app:minTextSize="20dp" />
</LinearLayout>

Don’t forget to view the full project at GitHub!

Code Listing

For the impatient, here’s the full control’s code listing:

using System;

using Android.Content;
using Android.Runtime;
using Android.Widget;
using Android.Util;
using Android.Graphics;

namespace AutoResizeTextView.Controls
{
    /// <summary>
    /// TextView that automatically resizes it's content to fit the layout dimensions
    /// </summary>
    /// <remarks>Port of: http://ankri.de/autoscale-textview/</remarks>
    public class AutoResizeTextView : TextView
    {
        /// <summary>
        /// How close we have to be to the perfect size
        /// </summary>
        private const float Threshold = .5f;
        
        /// <summary>
        /// Default minimum text size
        /// </summary>
        private const float DefaultMinTextSize = 10f;
        
        private Paint _textPaint;
        private float _preferredTextSize;
        
        public AutoResizeTextView(Context context) : base(context)
        {
            Initialise(context, null);
        }
        
        public AutoResizeTextView(Context context, IAttributeSet attrs) : base(context, attrs)
        {
            Initialise(context, attrs);
        }
        
        public AutoResizeTextView(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle)
        {
            Initialise(context, attrs);
        }
        
        // Default constructor override for MonoDroid
        public AutoResizeTextView(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
        {
            Initialise(null, null);
        }
        
        private void Initialise(Context context, IAttributeSet attrs)
        {
            _textPaint = new Paint();
            
            if (context != null && attrs != null)
            {
                var attributes = context.ObtainStyledAttributes(attrs, Resource.Styleable.AutoResizeTextView);
                MinTextSize = attributes.GetDimension(Resource.Styleable.AutoResizeTextView_minTextSize, DefaultMinTextSize);
                attributes.Recycle();
                
                _preferredTextSize = TextSize;
            }
        }
        
        /// <summary>
        /// Minimum text size in actual pixels
        /// </summary>
        public float MinTextSize { get; set; }
        
        /// <summary>
        /// Resize the text so that it fits.
        /// </summary>
        /// <param name="text">Text</param>
        /// <param name="textWidth">Width of the TextView</param>
        protected virtual void RefitText(string text, int textWidth)
        {
            if (textWidth <= 0 || string.IsNullOrWhiteSpace(text))
                return;
            
            int targetWidth = textWidth - PaddingLeft - PaddingRight;
            _textPaint.Set(this.Paint);
            
            while ((_preferredTextSize - MinTextSize) > Threshold)
            {
                float size = (_preferredTextSize + MinTextSize) / 2f;
                _textPaint.TextSize = size;
                
                if (_textPaint.MeasureText(text) >= targetWidth)
                    _preferredTextSize = size; // Too big
                else
                    MinTextSize = size; // Too small
            }
            
            SetTextSize(ComplexUnitType.Px, MinTextSize);
        }
        
        protected override void OnTextChanged(Java.Lang.ICharSequence text, int start, int before, int after)
        {
            base.OnTextChanged(text, start, before, after);
            
            RefitText(text.ToString(), Width);
        }
        
        protected override void OnSizeChanged(int w, int h, int oldw, int oldh)
        {
            base.OnSizeChanged(w, h, oldw, oldh);
            
            if (w != oldw)
                RefitText(Text, Width);
        }
    }
}
Posted by Dan in Mono for Android, 2 comments

Implementing IParcelable in Mono for Android

If you want to pass values between activities in Android, you’ll probably want to implement Parcelable sooner or later. This isn’t particularly slick even when writing natively, but add Mono in and it becomes even murkier. Fortunately .NET’s Generics support helps us out a little. The reason for the rather heavy implementation is intents can cross process boundaries, meaning you can’t just provide a memory address. This gives you the ability to call apps / resources you haven’t programmed yourself, but unfortunately it means inter-activity communication is ‘heavy’ for want of a better term. If you’re thinking of using IParcelable in a brand new app that isn’t going to be receiving 3rd party parcels, consider the ‘alternatives’ at the end of this guide first. IParcelable is somewhat of a convenience API for serialising objects to binary and then de-serialising. You might be better off doing this yourself rather than using the ‘Android’ method.

Our Class

For this demo I want to pass an array of a really simple class:

public sealed class SelectListItem
{
	// Convenience constructors
	public SelectListItem() {}
	public SelectListItem(int id, string name)
	{
		Id = id;
		Name = name;
	}

	// The actual properties for this class
	public int Id { get; set; }
	public string Name { get; set; }
}

Reference ‘Mono.Android.Export’

Before we start, make sure to reference the ‘Mono.Android.Export’ assembly:

Mono.Android.Export Assembly Reference

Implementing IParcelable

This class will be used to populate a ListActivity with a series of items that can be selected. First we need to inherit from Java.Lang.Object, and implement the IParcelable interface:

public sealed class SelectListItem : Java.Lang.Object, IParcelable

So why do we have to inherit from Java.Lang.Object? The Android runtime needs to be able to call the methods that we define as part of IParcelable, to do this our class must have a dual-personality. One half of the class is .NET, the other half is Java, it is this Java side that Android can see. When a method is called on the Java side, it will execute the .NET code. Clever huh? Unfortunately this means we now have two objects instead of one in memory, it also means that Mono must keep track of both objects. To do this it uses a global ID or reference, this reference links the two instances together. Unfortunately GREFs, are a very, very limited resource. The emulator only supports ~2,000 and devices usually only support ~50,000 GREFs. For more information on GREFs, check the Architecture and Garbage Collection documents over at Xamarin.

Before we implement the interface, we need to add an additional constructor that can accept a Parcel type. This constructor will populate the instance with the values from the parcel – the parcel being the ‘wrapped’ data of an instance of the same type:

// Create a new SelectListItem populated with the values in parcel
private SelectListItem(Parcel parcel)
{
	Id = parcel.ReadInt();
	Name = parcel.ReadString();
}

Note the order we read in the values, this is very important and must mirror the order in WriteToParcel below.

Next we need to implement the interface:

public int DescribeContents()
{
	return 0;
}

// Save this instance's values to the parcel
public void WriteToParcel(Parcel dest, ParcelableWriteFlags flags)
{
	dest.WriteInt(Id);
	dest.WriteString(Name);
}

DescribeContents is used for flagging ‘special objects’ within the parcel. I’ve never had cause to use this field, and 0 means ‘no special objects’.

WriteToParcel is where we write the instance data to the parcel, pay special attention to the order you write the values. This same order must be mirrored when reading in the parcel above. The flags attribute gives additional information on how the data should be written, it’s unlikely you’ll need to check these flags.

The CREATOR field

All Parcelable objects must have a public static field called CREATOR. The instance behind this field is responsible for creating instances of the object and populating them from the parcel. This can be done in two ways, an internal class that is implementation-specific, or a generic class that can be re-used repeatedly. The first method is the method commonly used in Java applications. However, with .NET we gain a much more robust Generics implementation so we’ll go down that route. However if you’re interested in the Java-favoured implementation it’s available in the sample project as a comment.

Without further ado, let’s look at how to declare our creator:

// The creator creates an instance of the specified object
private static readonly GenericParcelableCreator<SelectListItem> _creator
	= new GenericParcelableCreator<SelectListItem>((parcel) => new SelectListItem(parcel));

[ExportField("CREATOR")]
public static GenericParcelableCreator<SelectListItem> GetCreator()
{
	return _creator;
}

First we declare a private static instance, it’s required to be static by the Android API. Because this instance is static, it’s critical that your creator is thread safe otherwise bad things will happen. After the actual instance declaration we create a public static method, and decorate it with the ExportField attribute. Unfortunately this attribute can only be used on methods, so we can’t decorate our field directly. ExportField will ensure the Java version of our class gains a public static field named CREATOR.

A Generic ParcelableCreator Implementation

Earlier I mentioned that when developing with Java, each Parcelable requires a custom creator. Fortunately with .NET we gain a robust Generic implementation and we can use a generic creator that we can use again and again:

public sealed class GenericParcelableCreator<T> : Java.Lang.Object, IParcelableCreator
	where T : Java.Lang.Object, new()
{
	private readonly Func<Parcel, T> _createFunc;

	/// <summary>
	/// Initializes a new instance of the <see cref="ParcelableDemo.GenericParcelableCreator`1"/> class.
	/// </summary>
	/// <param name='createFromParcelFunc'>
	/// Func that creates an instance of T, populated with the values from the parcel parameter
	/// </param>
	public GenericParcelableCreator(Func<Parcel, T> createFromParcelFunc)
	{
		_createFunc = createFromParcelFunc;
	}

	#region IParcelableCreator Implementation

	public Java.Lang.Object CreateFromParcel(Parcel source)
	{
		return _createFunc(source);
	}

	public Java.Lang.Object[] NewArray(int size)
	{
		return new T[size];
	}

	#endregion
}

The creator must also be usable directly by Android, so again we have to inherit from Java.Lang.Object. We add two restrictions to the generic type parameter, first it must inherit from Java.Lang.Object (as all Parcelables must), and second it must have an empty constructor. This allows us to create an array of instances of the type, as required by IParcelableCreator.

Next in the constructor we require a delegate that can create and populate an instance of T. If you check back at our instantiation of the creator, we use a lambda expression that instantiates the instance using the private constructor we created that accepts a Parcel. Finally we implement the two methods required by IParcelableCreator, these simply create and populate the type, or create an array of the type.

Also remember that the creator must be thread-safe, if it isn’t bad things happen. To ensure thread safety we’ve made the state immutable, immutable types are by definition thread safe. If you need to create your own creator, be careful to follow thread safety guidelines. Microsoft have a good book on patterns and thread safety you can download for free.

Sample Code

You can download the sample project from GitHub here.

Select Item Item Selection Item Selected

Alternative to IParcelable

The problem with Parcelables is that you’re using up your very limited GREF resource. Additionally running two instances of an object across two garbage collectors isn’t the best use of memory or CPU resources. You’ll actually double up on instances as well, the instances that get packaged up in a parcel, and the instances that get extracted. The first set (senders) you can often clear from memory quickly, however the second set (received values) could be memory resident for quite some time as they’re used by the activity. The alternative is to either send just enough information for the activity to generate its own data, or you can send the data in an alternative format. You can send byte arrays, so you can use ISerializable and serialise your objects to binary. The other option is to use JSON (or other text-based format) and pass JSON strings between activities instead.

Unfortunately there is no ‘best’ solution, only the solution that meets your specific needs best.

Posted by Dan in C#, Mono for Android, Programming, Tutorials, 2 comments

Cocos2D Sound in Android Tutorial

Update: This code is using an outdated version of the Cocos2D port. It’ll still work if you use the sample download linked at the end – but it’s using outdated API calls. Unfortunately I don’t have time to update the tutorial to the new release of Cocos2D. Sorry guys 🙁

Cocos2D for Android provides a very rudimentary sound system for playing background music, and simple sound effects. For the vast majority of games, this is plenty. However, if you have more advanced requirements you may need to look into either rolling out your own sound engine or sourcing something more complete elsewhere.

Overview

The Cocos2D ‘SoundEngine’ class provides all of the functionality you’ll need. It groups audio into two main groups: ‘Sound’ and ‘Effect’. Effects are the explosions, jump sounds, and other general effects you have within games. Sound is the background music and is the only audio type that can be paused and resumed. Sound effects should be kept under 5 seconds long, and ideally they should be under 3 seconds.

Android supports a wide range of different audio formats, you can view a complete list here. However, I’ve found that the SoundEngine doesn’t necessarily support all of these formats – so please do test your audio on a real device, preferably a few.

Let’s start coding!

Create a new Android project in your IDE of choice, IntelliJ Idea is my favourite, but Eclipse is very good also. You also need to download the latest source code for cocos2d-android-1, the downloadable jar doesn’t include the SoundEngine code. Include the source into your project – this also has the added advantage that you can poke around the code to see how everything works.

Also you need to add the two audio files in this zip, and put them in the ‘raw’ folder within the ‘resources’ folder. If you don’t have a raw folder, create it.

Before we get into any real coding, we’ll need to create a very rudimentary GUI to allow us to interact with the sound system. We’ll add two buttons to the main layout, one to play some background music and another to play a single sound effect:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <Button
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="10dp"
        android:text="BG Music Toggle"
        android:onClick="bgMusicClicked" />

    <Button
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="10dp"
        android:text="Play Sound Effect"
        android:onClick="sfxClicked" />
</LinearLayout>

Using SoundEngine

The SoundEngine offers functionality to pre-load audio, this is critical to ensure sound effects are played instantly. It also means we can use compressed audio formats such as mp3, without slowing down our game. Add the following field to the top of the main activity:

private Context _cocos2dContext;

Next add the following code to the onCreate() method:

_cocos2dContext = this;

// Preload background music
SoundEngine.sharedEngine().preloadSound(_cocos2dContext, R.raw.background_music_aac);

// Preload sound effect
SoundEngine.sharedEngine().preloadEffect(_cocos2dContext, R.raw.pew_pew_lei);

This code sets the context we’ll use for playing audio, and preloads the background audio, and the sound effect. We set the context to the current activity; this is because we’re not actually using Cocos2D in this demo. In your actual games you would use CCDirector.sharedDirector().getActivity() instead of this.
Now, create the event handlers for the two buttons we created:

public void bgMusicClicked(View button)
{
    // Play the background music
    SoundEngine.sharedEngine().playSound(_cocos2dContext, R.raw.background_music_aac, true);
}

public void sfxClicked(View button)
{
    // Play the sound effect
    SoundEngine.sharedEngine().playEffect(_cocos2dContext, R.raw.pew_pew_lei);
}

Give it a test!

It won’t stop playing!

OK I may have let you walk into this one – the background music plays even when the activity is ‘closed’ or otherwise not being used by the user. This is very handy if you’re making an mp3 player, but not so useful when making a game. Fortunately we can fix this problem by hooking into a few events Android offers. As a refresher, here is the Activity Lifecycle in Android:

We need to cater for the activity being obscured by another activity, being hidden, and being closed down. The onResume, onPause, and onDestroy methods should be plenty for our needs. In onResume we’ll need to resume playback of the background sound if it was playing. onPause will pause the sound (if any) ready for resuming. When onDestroy is called we’ll close everything down and free up any applicable resources.

First, add the following fields to the activity class:

private boolean _soundPlaying = false;
private boolean _soundPaused = false;
private boolean _resumeSound = false;

We need to populate these fields as necessary when the user wants to play / pause the background music. Replace the bgMusicClicked method with:

public void bgMusicClicked(View button)
{
    // If we haven't started playing the sound - play it!
    if (!_soundPlaying)
    {
        SoundEngine.sharedEngine().playSound(_cocos2dContext, R.raw.background_music_aac, true);
        _soundPlaying = true;
    }
    else
    {
        // We've loaded the sound, now it's just a case of pausing / resuming
        if (!_soundPaused)
        {
            SoundEngine.sharedEngine().pauseSound();
            _soundPaused = true;
        }
        else
        {
            SoundEngine.sharedEngine().resumeSound();
            _soundPaused = false;
        }
    }
}

Now we only play the sound once, rather than starting fresh each time. We pause / resume the sound depending on whether it’s currently playing or not – your typical toggle pattern.
Now we’ll create the onPause handler:

@Override
public void onPause()
{
    super.onPause();

    // If the sound is loaded and not paused, pause it - but flag that we want it resumed
    if (_soundPlaying && !_soundPaused)
    {
        SoundEngine.sharedEngine().pauseSound();
        _soundPaused = true;
        _resumeSound = true;
    }
    else
        _resumeSound = false; // No sound playing, don't resume
}

In this method we check if the sound is playing, and if it is – whether it’s paused or not. If the sound is playing but it’s not paused, we pause it and request that it’s resumed at the earliest opportunity. If the sound isn’t playing or it’s paused, then we request that the sound isn’t resumed when the activity is.

Now it’s time for the onResume method:

@Override
public void onResume()
{
    super.onResume();

    // Resume playing sound only if it's loaded, paused and we want to resume it
    if (_soundPlaying && _soundPaused && _resumeSound)
    {
        SoundEngine.sharedEngine().resumeSound();
        _soundPaused = false;
    }
}

We check if the sound is playing, it’s paused, and a request is pending to resume the sound. If all of this is true (phew, that’s a lot of checking!) we resume the sound.

At this point we can run the app, and the audio will be handled properly. The user won’t be irritated by music playing when it shouldn’t, and our game can resume seamlessly when the user comes back. However, we haven’t yet implemented the onDestroy method – we never clean everything up.

Cleaning up our mess

Strictly speaking, cleaning up isn’t necessary in this app. Android will automatically reclaim the consumed resources when the app is destroyed. However, it’s always good to clean everything up anyway, if only so you know how to do it when it really is important. Add the following destroy method:

@Override
public void onDestroy()
{
    super.onDestroy();

    // Clean everything up
    SoundEngine.sharedEngine().realesAllSounds();
    SoundEngine.sharedEngine().realesAllEffects();

    // Completely shut down the sound system
    SoundEngine.purgeSharedEngine();
}

First we release all of the preloaded sounds and effects. You can selectively release individual sounds and effects if you need to. If your game is made up of multiple scenes with different audio in each, it’s a very good idea to release the audio you’re not using to save on memory.

Finally we shut down the sound engine itself. This isn’t really necessary, but it’s here for you to see how it can be done. If you have completely different areas in your game, you could feasibly want to have no trace of the SoundEngine between those scenes since the SoundEngine is a singleton by design.

And we’re done!

And that’s it; you now know everything you need to add basic audio to your Android Cocos2D games.

You can download the sample project here.

If you want more Cocos2D, don’t forget to check out the basic tutorial series starting here.

Posted by Dan in Android, Java, Tutorials, 3 comments

Honeycomb for Advent Vega

Honeycomb for the Advent Vega is now at a stage where it’s mostly usable day to day, you an pick it up at Tabletroms. Very impressive work by newbe5 and Corvus to not only get Honeycomb working so quickly, but to get it working so well so quickly after the initial releases!

Posted by Dan in Android, 0 comments

How To Make A Simple Android Game with Cocos2D Part 2 – Rotating Turrets

Update: This code is using an outdated version of the Cocos2D port. It’ll still work if you use the sample download linked at the end – but it’s using outdated API calls. Unfortunately I don’t have time to update the tutorial to the new release of Cocos2D. Sorry guys 🙁

This is the second tutorial in the Simple Android Cocos2D Game Tutorial series, originally written by Ray Wenderlich for the iPhone. This one builds on the first tutorial by replacing the ninja with a rotating turret, and the projectiles with cannon balls.

Getting Set Up

Ideally you’ll have followed the first tutorial, in which case you can continue from where you left of. Failing that you can download the code from the previous tutorial and use that as your base – however, I highly recommend starting from the beginning.

Now download a new player sprite and projectile sprite, put both in the ‘assets’ folder of your project. You’ll need to update your code to use these new sprites, so without further ado let’s get modifying. In the GameLayer constructor, update the player line with the following:

CCSprite player = CCSprite.sprite("Player2.png");

Next update the ccTouchesEnded method, find where you create the projectile sprite and replace with the following:

CCSprite projectile = CCSprite.sprite("Projectile2.png");

Compile and run your project, it should now look like the following screenshot:


You’ve probably noticed it doesn’t look quite right, the turret doesn’t rotate with the projectile direction. Let’s fix that now.

Rotating To Shoot

Before we can rotate the turret, we need to store a reference to the player sprite so we can rotate it elsewhere in the program. In the GameLayer class, add the following field:

protected CCSprite _player;

Next we need to use the new field, update the Constructor instantiation code to the following:

_player = CCSprite.sprite("Player2.png");
_player.setPosition(CGPoint.ccp(_player.getContentSize().width / 2.0f, winSize.height / 2.0f));

addChild(_player);

Rotating the turret with the projectile is easier said than done, we’re forced to use a little maths to work out the angle. For this we’ll use a little Trigonometry, which means remembering back to SOH CAH TOA. In this example we’ll be using the ‘TOA’, or Tangent of an angle is equal to the Opposite over the Adjacent. The following illustration should help:

As you can see from the graphic, the angle we want to rotate to is equal to the arctangent of the Y offset divided by the X offset. Seems easy enough right? Unfortunately there are two caveats you must be aware off before we can go implementing general geometry in our games:

  1. The maths functions in Java use and return radians, not degrees
  2. Cocos2D rotations are clockwise rather than anti-clockwise, which is the opposite to what is expected, as shown in the graphic below:

Fortunately the solutions are very simple. The Java Math class provides a method to convert to and from radians. The second solution is to invert the angle by multiplying by negative 1. So for example 20° x -1 = -20°. This will effectively convert the counter-clockwise rotation to the clockwise rotation Cocos2D expects:

Let’s put what we’ve learned into practice. Add the following code to the ccTouchesEnded code, just before we play the sound effect:

// Determine angle to face
double angleRadians = Math.atan((double)offRealY / (double)offRealX);
double angleDegrees = Math.toDegrees(angleRadians);
double cocosAngle = -1 * angleDegrees;
_player.setRotation((float)cocosAngle);

You may have noticed we’re using doubles rather than floats. According to Google doubles are just as fast as floats with the only trade-off being increased memory consumption. Since there is no float version of Math.atan or Math.toDegrees, it’s better to stick with doubles so we don’t waste CPU cycles converting between double and float repeatedly.

Now compile and run, and you should have a rotating turret!

Rotate Then Shoot

We’ve got a great game here, but it could be better. The turret rotates instantly, which is unlikely given we’re firing cannon balls. It would be much better for immersion and realism if we smoothly rotate the turret to its new direction. This will take a little refactoring.

Add the following field to the GameLayer class:

protected CCSprite _nextProjectile;

Replace the projectile instantiation code in ccTouchesEnded with the following:

_nextProjectile = CCSprite.sprite("Projectile2.png");

Next replace all occurrences of ‘projectile’ with ‘_nextProjectile’ within ccTouchesEnded. While you’re replacing these occurrences, make sure to delete the following lines:

addChild(projectile);
_projectiles.add(projectile);

Update the turret rotation code (also in ccTouchesEnded) with the following:

// Determine angle to face
double angleRadians = Math.atan((double)offRealY / (double)offRealX);
double angleDegrees = Math.toDegrees(angleRadians);
double cocosAngle = -1 * angleDegrees;
double rotationSpeed = 0.5 / Math.PI;
double rotationDuration = Math.abs(angleRadians * rotationSpeed);
_player.runAction(CCSequence.actions(
		CCRotateTo.action((float)rotationDuration, (float)cocosAngle),
		CCCallFunc.action(this, "finishShoot")));

This code will rotate the turret with a rotation speed of half a second (0.5) for half a circle’s worth of rotation (since full circle in radians is 2 PI, a half circle is 1 PI).
Once the rotation is complete, we then call a method called ‘finishShoot’. Since we haven’t created that method, we should create it now:

public void finishShoot()
{
	addChild(_nextProjectile);
	_projectiles.add(_nextProjectile);
}

This method adds the projectile to the game. Since it’s called once the turret has finished rotating we can guarantee that projectiles will only fire once the turret is in position.
That’s it, we’re all finished! Have a play, and enjoy your handiwork.

What’s Next?

You can download the full source code here.

In the future I should be porting Ray’s final part of the series, but in the meantime you could have a look at his tutorial and see if you can port it yourself!

Posted by Dan in Java, Programming, Tutorials, 31 comments

Honeycomb for Advent Vega (and other ‘Harmony’ tablets) Coming Soon

Update: The community took up the challenge and ported Honeycomb WITH hardware acceleration.

It looks increasingly unlikely that Honeycomb will appear on the NVIDIA Harmony platform, which includes the Advent Vega.

However, that doesn’t mean the community couldn’t make a custom rom, but it’ll take a lot of work. Google aren’t releasing the Honeycomb source (instead we’ll have to wait for Ice Cream), additionally the community will need to integrate the drivers manually from NVIDIA.

While I’m sure we’ll see Honeycomb on the platform, I doubt it’ll ever be a nice slick implementation that you would get from an OEM-based rom. To be frank, if you want Honeycomb, best start saving the pennies for one of the latest generation of Android tablets. The Asus Transformer looks especially tasty. Personally I’m waiting for the quad core Tegra and Ice Cream, Froyo is enough for me for the moment.

Posted by Dan in General, 0 comments

Resetting Android Vega Tablet

At some point you’re going to hard lock your tablet, at least if you’re like me. Only problem is there’s no physical power switch and you can’t take the battery out. Have no fear! Press and hold the Power and Back buttons simultaneously, after a while the tablet will turn off. Press the power button again to turn it back on, and now you’ve got your tablet back to working order!

Posted by Dan in General, 0 comments

How To Make A Simple Android Game with Cocos2D

Update: This code is using an outdated version of the Cocos2D port. It’ll still work if you use the sample download linked at the end – but it’s using outdated API calls. Unfortunately I don’t have time to update the tutorial to the new release of Cocos2D. Sorry guys 🙁

Cocos2D is a fantastic library / game engine for numerous platforms from PCs to smart phones. It supports the vast majority of the features necessary to make almost any 2D-based game, it even includes a fully-featured physics engine!

As part of learning Cocos2D for Android I followed Ray Wenderlich’s tutorials for the iPhone port of Cocos2D. Of course we’re dealing with Android here, so here is his tutorial recreated for Android. Ray deserves all credit for this tutorial – the tutorial is originally his, this is merely a port to Android. Credit should also go to Sketchydroide for his basic template for Cocos2D on Android.

Downloading and Installing Cocos2D

I’m going to assume you’ve already got the Android SDK installed, along with Eclipse. If not, you can follow the guides at Google. You’ll also need to test with a real device, the emulator is far too slow to test Cocos2D applications, even one as simple as this tutorial. I’m also going to assume you know Java, otherwise you’re going to get lost very quickly. There are plenty of Java tutorials out there, don’t worry we’ll wait here while you learn. The basics of Android (such as what Activities are, etc.) are helpful to know, but not critical.

First you need to download cocos2d-android-1. I’m going to assume you’re using the pre-compiled library (the .jar), although you’re welcome to include the full source code if you wish. In fact when you’re developing on your own, the source code is a better option since you gain full documentation along with the ability to tweak the code should you need to.

Open up Eclipse and create a new Android Project:


Now you need to copy the cocos2d-android.jar file into the ‘libs’ folder of your project. If the folder doesn’t exist, create it.

Go back to Eclipse, right-click on your project and select ‘Build Path/Add External Archives’.

Browse to where you saved the .jar file and select ‘open’.

Next download fps_images.png and put into the assets folder of your project. You are now setup with Cocos2D!

Initial Setup

Next you need to put some code into your default activity (SimpleGame) so that you can start making your game. At the top of the class add a protected field:

protected CCGLSurfaceView _glSurfaceView;

At this point Eclipse may be moaning about the line you’ve just added. This is because you haven’t imported the namespace. The easiest way to do this is to press CTRL+SHIFT+O. Any time you use a new class, try pressing this key combination any time a completed line has an error to do with missing identifiers. Next replace the onCreate method with the following:

@Override
public void onCreate(Bundle savedInstanceState)
{
	super.onCreate(savedInstanceState);

	requestWindowFeature(Window.FEATURE_NO_TITLE);
	getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
	getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

	_glSurfaceView = new CCGLSurfaceView(this);

	setContentView(_glSurfaceView);
}}

This sets up the OpenGL surface for Cocos2D to utilise. We set some flags to ensure we always have a fullscreen view, then display the view to the user.

Replace the onStart method with the following:

@Override
public void onStart()
{
	super.onStart();

	CCDirector.sharedDirector().attachInView(_glSurfaceView);

	CCDirector.sharedDirector().setDisplayFPS(true);

	CCDirector.sharedDirector().setAnimationInterval(1.0f / 60.0f);
}

This is the initial setup for Cocos2D. First we tell Cocos2D which surface to render to (the OpenGL surface we set up earlier). We then ask Cocos2D to display the FPS and to run at 60fps. Note that the 60fps is our animation interval, not the framerate of the application itself which is often limited by the device.

Finally add the following extra overrides:

@Override
public void onPause()
{
	super.onPause();

	CCDirector.sharedDirector().pause();
}

@Override
public void onResume()
{
	super.onResume();

	CCDirector.sharedDirector().resume();
}

@Override
public void onStop()
{
	super.onStop();

	CCDirector.sharedDirector().end();
}

These notify Cocos2D with what’s going on with the device – such as when the user has switched to another application or the game is being stopped by the OS.

This is all the setup we really need. You can run the game now, but it won’t display anything at this early stage (we haven’t even set up a hello world scene!).

Adding a Sprite

Sprites are small images in 2D games that move about. These can be characters, projectiles or even clouds. In this game we’ll have three separate types of sprite: Player, target (enemy), and projectile. First we need a graphic to use! You can either create your own, or use the tasty graphics provided by Ray Wenderlich’s wife: Player, Projectile, Target. Place your sprite graphics within the ‘assets’ folder of your project.

Now we need to place the sprite on the game screen. Cocos2D has an inverted coordinate system to what you’re used to – the origin is the bottom left of the screen. So as X increases you head to the right of the screen. As Y increases you go up the screen. Additionally by default the origin / anchor point of sprites is in the centre. The coordinate system is the same regardless of the platform you run Cocos2D on. The following graphic should help you visualise the coordinate system of Cocos2D:

Enough boring theory, let’s get some code down! Add a new class to your project, call it ‘GameLayer’ and make it extend ‘CCLayer’. Add the following static method at the top of the class declaration:

public static CCScene scene()
{
	CCScene scene = CCScene.node();
	CCLayer layer = new GameLayer();

	scene.addChild(layer);

	return scene;
}

Now add a default constructor:

protected GameLayer()
{
	CGSize winSize = CCDirector.sharedDirector().displaySize();
	CCSprite player = CCSprite.sprite("Player.png");

	player.setPosition(CGPoint.ccp(_player.getContentSize().width / 2.0f, winSize.height / 2.0f));

	addChild(_player);
}

At this point it may be worth a quick look at the earlier diagram to see exactly why we’ve chosen the coordinates we have for the player.

Now before we can see this running, we first need to tell Cocos2D to run our new scene & layer. Go back to SimpleGame.java and add the following code to the end of the onStart method:

CCScene scene = GameLayer.scene();
CCDirector.sharedDirector().runWithScene(scene);

Now run the application and admire your handywork!

Oh dear, the black character is barely visible on the black background! Never mind, we can modify the background colour of the layer easily by inheriting from CCColorLayer instead of CCLayer:

public class GameLayer extends CCColorLayer

Update the scene() static method’s layer declaration to:

CCColorLayer layer = new GameLayer(ccColor4B.ccc4(255, 255, 255, 255));

Finally, update the constructor to the following:

protected GameLayer(ccColor4B color)
{
	super(color);

Now when you run the application you should have a nice white background.

Moving Targets

While it’s cool to display a single ninja, because well, ninjas are cool – we don’t yet have much of a game. What we really need are some targets for our ninja to throw stars at. While we’re at it we might as well make them move to give them a fighting chance. What we’ll do is create the targets off the screen to the right, then have them move to the left of the screen at varying speeds. Add the following method after the constructor:

protected void addTarget()
{
	Random rand = new Random();
	CCSprite target = CCSprite.sprite("Target.png");

	// Determine where to spawn the target along the Y axis
	CGSize winSize = CCDirector.sharedDirector().displaySize();
	int minY = (int)(target.getContentSize().height / 2.0f);
	int maxY = (int)(winSize.height - target.getContentSize().height / 2.0f);
	int rangeY = maxY - minY;
	int actualY = rand.nextInt(rangeY) + minY;

	// Create the target slightly off-screen along the right edge,
	// and along a random position along the Y axis as calculated above
	target.setPosition(winSize.width + (target.getContentSize().width / 2.0f), actualY);
	addChild(target);

	// Determine speed of the target
	int minDuration = 2;
	int maxDuration = 4;
	int rangeDuration = maxDuration - minDuration;
	int actualDuration = rand.nextInt(rangeDuration) + minDuration;

	// Create the actions
	CCMoveTo actionMove = CCMoveTo.action(actualDuration, CGPoint.ccp(-target.getContentSize().width / 2.0f, actualY));
	CCCallFuncN actionMoveDone = CCCallFuncN.action(this, "spriteMoveFinished");
	CCSequence actions = CCSequence.actions(actionMove, actionMoveDone);

	target.runAction(actions);
}

The code is rather verbose to make it as easy to read & understand as possible. Near the bottom we’ve introduced a new concept: Actions. Actions are a very accessible way of getting sprites to do things without constant babysitting. You can get sprites to move, rotate, fade, jump, etc. We use three different actions in this method:

  • CCMoveTo: The CCMoveTo action moves a sprite from its current position to a new one. In this case we’re moving the sprite from just beyond the right edge of the screen to just beyond the left edge of the screen (remember the origin of a sprite is the centre, hence why we divide the width by two). The duration is specified in seconds between 2 and 4. As an exercise, try changing the type from int to float so we aren’t restricted to whole seconds.
  • CCCallFuncN: The CCCallFuncN action allows you to specify a callback. The ‘N’ means this action allows you to specify a parameter.
  • CCSequence: This is a rather special action in that it doesn’t do anything itself. Instead it lets you run a sequence of actions, one after the other in a linear fashion. We use this so that we can move the sprite, then when the movement has finished call our callback.

The eagle-eyed may have noticed that we have a callback, yet the method doesn’t yet exist! We better correct that right now, add the following method to our class:

public void spriteMoveFinished(Object sender)
{
	CCSprite sprite = (CCSprite)sender;
	this.removeChild(sprite, true);
}

This method will remove the sprite when it has finished animating to the left of the screen. The second parameter is to ‘cleanup’ the sprite, this means it is completely unloaded and we get the memory back. In a real game you would only clean up a sprite as a last resort, re-using a sprite is much better from a performance perspective. We’re going down the wasteful route to make the concept of the game as simple as possible – simple is good when learning!

Now we have code to create and animate targets, but we never call this code! What we’ll do is spawn a new target every second automatically giving the ninja plenty of shuriken practice. Add the following line of code to the bottom of the constructor:

this.schedule("gameLogic", 1.0f);

Also add the following new method to the class:

public void gameLogic(float dt)
{
	addTarget();
}

Now run the application and we should have some action:

Shooting Projectiles

I like to be able to shoot my targets, so let’s add some shooting! We’re going make things simple by having the user tap to shoot, where you tap is where the projectile goes.

We’ll use CCMoveTo to animate the projectile just like how we animated the targets. The problem is, CCMoveTo requires a destination to move to, but we can’t use the tap location since that means the projectile would stop in the middle of the screen. What we need to do is use the tap as a direction, rather than a destination.

This should look familiar to anyone who didn’t fall asleep in maths class – Pythagoras! Now before we fall asleep with yet more theory, let’s start coding. In the constructor add the following line:

this.setIsTouchEnabled(true);

Next add the following method to the class:

@Override
public boolean ccTouchesEnded(MotionEvent event)
{
	// Choose one of the touches to work with
	CGPoint location = CCDirector.sharedDirector().convertToGL(CGPoint.ccp(event.getX(), event.getY()));

	// Set up initial location of projectile
	CGSize winSize = CCDirector.sharedDirector().displaySize();
	CCSprite projectile = CCSprite.sprite("Projectile.png");

	projectile.setPosition(20, winSize.height / 2.0f);

	// Determine offset of location to projectile
	int offX = (int)(location.x - projectile.getPosition().x);
	int offY = (int)(location.y - projectile.getPosition().y);

	// Bail out if we are shooting down or backwards
	if (offX <= 0)
		return true;

	// Ok to add now - we've double checked position
	addChild(projectile);

	// Determine where we wish to shoot the projectile to
	int realX = (int)(winSize.width + (projectile.getContentSize().width / 2.0f));
	float ratio = (float)offY / (float)offX;
	int realY = (int)((realX * ratio) + projectile.getPosition().y);
	CGPoint realDest = CGPoint.ccp(realX, realY);

	// Determine the length of how far we're shooting
	int offRealX = (int)(realX - projectile.getPosition().x);
	int offRealY = (int)(realY - projectile.getPosition().y);
	float length = (float)Math.sqrt((offRealX * offRealX) + (offRealY * offRealY));
	float velocity = 480.0f / 1.0f; // 480 pixels / 1 sec
	float realMoveDuration = length / velocity;

	// Move projectile to actual endpoint
	projectile.runAction(CCSequence.actions(
			CCMoveTo.action(realMoveDuration, realDest),
			CCCallFuncN.action(this, "spriteMoveFinished")));

	return true;
}

What we are doing here is first enabling touch support. We’re telling Cocos2D that we are ready to handle touches for the current layer. Next we add code to handle touches from the user.

First we get the coordinates of the touch itself, and convert to the Cocos2D coordinate system. This method should work regardless of the orientation of the device.

Next we create the sprite and position it over the ninja. We then work out where the projectile should move to by extending the tap off the screen. This is done by getting the X and Y offset of the tap to the projectile’s starting position. We then get the ratio of Y to X, and simply scale the touch Y coordinate to match the scaled up X coordinate (which is just off the screen). The only problem with a simple algorithm like this is that the projectile must reach the right edge of the screen before it’s cleaned up, the projectile could leave the screen (top or bottom) long before it hits the right edge. There are solutions to this problem, but they’re beyond the scope of this tutorial.

After working out the destination, we need to work out the duration of the movement – we can’t have projectiles taking different amounts of time just because of the angle they’re shot at. To solve this problem we use Pythagoras to work out the distance the projectile needs to travel, then divide that by the velocity we want. This is because velocity = distance over time, or by re-arranging: time = distance over velocity.

Finally we run the actions on the projectile. Run the application and you should be able to start shooting shurikens!

Collision Detection

It’s no good if you can shoot shurikens, but they don’t actually do anything! To solve this problem we need to add some collision detection. To keep things simple we’ll use simple bounding box collision detection rather than the other more exotic methods Cocos2D provides.

To be able to run collision detection we need to be able to keep track of all of the sprites we have. Add the following fields to the top of the class declaration:

protected ArrayList<CCSprite> _targets;
protected ArrayList<CCSprite> _projectiles;

You’ll need to instantiate the arrays near the top of the constructor:

_targets = new ArrayList<CCSprite>();
_projectiles = new ArrayList<CCSprite>();

Now add the following to the addTarget() method just below the addChild(target) line:

target.setTag(1);
_targets.add(target);

In the ccTouchesEnded method add the following just below the addChild(projectile) line:

projectile.setTag(2);
_projectiles.add(projectile);

Finally update the spriteMoveFinished method to remove the sprite from the appropriate array:

if (sprite.getTag() == 1)
	_targets.remove(sprite);
else if (sprite.getTag() == 2)
	_projectiles.remove(sprite);

If you run the project now you shouldn’t notice any difference – but now we’re tracking all of our sprites! This gives us a great deal of extra power, and we shall use this power to add some collision detection. Add the following method to the class:

public void update(float dt)
{
	ArrayList<CCSprite> projectilesToDelete = new ArrayList<CCSprite>();

	for (CCSprite projectile : _projectiles)
	{
		CGRect projectileRect = CGRect.make(projectile.getPosition().x - (projectile.getContentSize().width / 2.0f),
											projectile.getPosition().y - (projectile.getContentSize().height / 2.0f),
											projectile.getContentSize().width,
											projectile.getContentSize().height);

		ArrayList<CCSprite> targetsToDelete = new ArrayList<CCSprite>();

		for (CCSprite target : _targets)
		{
			CGRect targetRect = CGRect.make(target.getPosition().x - (target.getContentSize().width),
											target.getPosition().y - (target.getContentSize().height),
											target.getContentSize().width,
											target.getContentSize().height);

			if (CGRect.intersects(projectileRect, targetRect))
				targetsToDelete.add(target);
		}

		for (CCSprite target : targetsToDelete)
		{
			_targets.remove(target);
			removeChild(target, true);
		}

		if (targetsToDelete.size() > 0)
			projectilesToDelete.add(projectile);
	}

	for (CCSprite projectile : projectilesToDelete)
	{
		_projectiles.remove(projectile);
		removeChild(projectile, true);
	}
}

This is a brute-force approach to collision detection. Basically we iterate through all of the projectiles and targets, creating a rectangle for each and then checking if they intersect. If there is an intersection we remove the sprites from the scene and arrays. We use the ‘toDelete’ arrays since we can’t manipulate an array while we’re iterating through it in the manner we’ve chosen. Before the collision detection will work, we need to schedule the method to be called every frame. Add the following line at the bottom of the constructor:

this.schedule("update");

Finishing Touches

We’re pretty close to a fully working game now (albeit a simple one!). All games have sound effects of some sort, and this one is no exception! First we should talk about the audio formats Android supports, since Cocos2D can’t do anything about the supported audio formats on the platform it’s running on. The current port of Cocos2D on Android doesn’t contain a full sound engine yet, certainly not on par with CocosDenshion offered on the iPhone. For this reason we’ll use basic wav files for this tutorial. We’ll also add some additional code logic so you can win/lose.

First you’ll need to get some audio for the background music and a sound effect for the shurikens. You can source your own, or download the wav version of the background music, and pew pew sound effect from Ray Wenderlich’s tutorial. Put the wav files in the res/raw folder of your project.

In the constructor add the following code after the addChild(player) line:

Context context = CCDirector.sharedDirector().getActivity();
SoundEngine.sharedEngine().preloadEffect(context, R.raw.pew_pew_lei);
SoundEngine.sharedEngine().playSound(context, R.raw.background_music_aac, true);

Next in the ccTouchesEnded method add the following code:

Context context = CCDirector.sharedDirector().getActivity();
SoundEngine.sharedEngine().playEffect(context, R.raw.pew_pew_lei);

Now we need to create a win/lose scene. Add a new class with the name ‘GameOverLayer’, have it inherit from CCColorLayer. Use the following code for the new class:

public class GameOverLayer extends CCColorLayer
{
	protected CCLabel _label;

	public static CCScene scene(String message)
	{
		CCScene scene = CCScene.node();
		GameOverLayer layer = new GameOverLayer(ccColor4B.ccc4(255, 255, 255, 255));

		layer.getLabel().setString(message);

		scene.addChild(layer);

		return scene;
	}

	public CCLabel getLabel()
	{
		return _label;
	}

	protected GameOverLayer(ccColor4B color)
	{
		super(color);

		this.setIsTouchEnabled(true);

		CGSize winSize = CCDirector.sharedDirector().displaySize();

		_label = CCLabel.makeLabel("Won't See Me", "DroidSans", 32);
		_label.setColor(ccColor3B.ccBLACK);
		_label.setPosition(winSize.width / 2.0f, winSize.height / 2.0f);
		addChild(_label);

		this.runAction(CCSequence.actions(CCDelayTime.action(3.0f), CCCallFunc.action(this, "gameOverDone")));
	}

	public void gameOverDone()
	{
		CCDirector.sharedDirector().replaceScene(GameLayer.scene());
	}

	@Override
	public boolean ccTouchesEnded(MotionEvent event)
	{
		gameOverDone();

		return true;
	}
}

Now we need to add some logic to the GameLayer to trigger the game over scene. Add the following field to the top of the GameLayer class:

protected int _projectilesDestroyed;

In the constructor, just after you initialise the arrays add the following line:

_projectilesDestroyed = 0;

In the update method, just after removeChild(projectile, true) add the following code:

if (++_projectilesDestroyed > 30)
{
	_projectilesDestroyed = 0;
	CCDirector.sharedDirector().replaceScene(GameOverLayer.scene("You Win!"));
}

Update the if statement in spriteMoveFinished to the following:

if (sprite.getTag() == 1)
{
	_targets.remove(sprite);

	_projectilesDestroyed = 0;
	CCDirector.sharedDirector().replaceScene(GameOverLayer.scene("You Lose, boo"));
}
else if (sprite.getTag() == 2)
	_projectiles.remove(sprite);

Go ahead and give the game a play!

Gimme The Code!

You can download the full source code here.

Where To Now?

This project provides a good basis for further development. Some possible changes were mentioned as part of the tutorial, others are limited only by your imagination! Check out the test projects that come with the source of Cocos2D, see if you can integrate some of them into the project here.

Alternatively, you can follow the next tutorial in the series here.

Or maybe follow the tutorial on audio to learn more about background music & sound effects in Cocos2D for Android.

This is my first tutorial, and I hope you’ve enjoyed it!

Posted by Dan in Java, Programming, Tutorials, 131 comments