Your first project
From Pixelwave
Contents |
Howdie. So you should be all set up now and ready to get started developing with Pixelwave. We're going to step through the process of creating a new project from start to finish. By the end of this tutorial you'll be able to make your very own Pixelwave projects (that hopefully compile) from scratch. Sweet!
1 Prerequisites
Before you start going through this tutorial you should have successfully set up Pixelwave (to test it, just run one of the included sample projects).
Also, you'll need to have the Pixelwave Xcode templates installed. If using custom Xcode templates is against your religion, or you're just a proponent of masochism, you can also set up a Pixelwave project from scratch. We of course encourage you to use the pre-made Xcode templates because they'll make your life like, at least 50 times simpler. lolz. Seriously.
2 Starting a new project
- Step 1 - Boot up Xcode
This tutorial was written using Xcode 3.2.5, iOS SDK 4.2, on Mac OS X 10.6. (Also compatible with Xcode 4, on OS X Lion)
- Step 2 - Create a new Xcode project
Navigate to (File -> New Project). Under the User Templates section choose the Pixelwave category. select the Blank Project item. Now you can choose whatever option you'd like for product, but we chose to go with Universal in order to support both the iPhone and iPad with a single app.
- Step 3 - Save it
Click 'Choose...' on the bottom right corner and pick a location to save your project. Choose anywhere on your machine except the directory where Pixelwave is located (the path of PIXELWAVE_SRC). Let's call our app 'HelloWorld'.
- Step 4 - Run it
If everything went well you should now have a new blank Pixelwave project ready to go. It would look something like this:
Just to make sure we're ready to start coding, press the big 'Build and Run' button at the top of the window. After your project compiles and runs you should see something like this:
It may not look like much, but it means that the Xcode gods have bestowed upon us the gift of compilation and we are now ready to start doing some real coding.
3 What are all these files?
Before we dive into coding, let's take a quick minute to discuss some of the classes that the Pixelwave Xcode template created. This way you'll have a better idea of their purpose:
- iPad/AppDelegate_iPad & iPhone/AppDelegate_iPhone - These are the default app delegate classes which are required for every iOS application. The Pixelwave template pre-populated these classes with the code necessary to setup and start the Pixelwave engine. You shouldn't need to interact with these classes unless you need perform iOS tasks that are unrelated to Pixelwave.
- Classes/HelloWorldRoot - This class was created for us by the Pixelwave template. It acts as the starting point of our Pixelwave app. The method
initializeAsRootwithin this class is called automatically when the app launches.
4 Our little project
We're going to create a very simple app that presents an image to the user. When the user touches anywhere on the screen we'll have the image slowly animate over to that position.
We'll be writing the code from scratch as we go through the tutorial. I'll try to explain each line as we add it to our code. If you need a complete reference though, the full source code is included at the end of the article.
5 Sourcing an image
If we're going to use an image in our project we need to include it in our application bundle first. I chose to use this awesome image of a pixelated turtle. Feel free to use this one or supply your own.
TiredTurtle.png
To add the image to the application bundle, just drag it from anywhere on your hard-drive into your Xcode project. Once you drag it in you should see this prompt:
Press 'Add' and, like magic, your image will be added to the application bundle.
6 Writing some code
The setting up is done, now let's write some code.
6.1 Creating ivars
Let's start by declaring all of the class-wide instance variables (ivars) in our application. Open up "HelloWorldRoot.h" and add three variables to the interface:
-
image(PXTexture) - This will hold the reference to our image -
targetX, targetY(float) - These two values will hold the position to which we want the image to animate.
The header should look like this:
#import "Pixelwave.h"
@interface HelloWorldRoot : PXSprite
{
PXTexture *image;
float targetX, targetY;
}
- (void) initializeAsRoot;
@end
6.2 Loading the image
Head over to HelloWorldRoot.m. Currently it should look like this:
Let's add some code to the method initializeAsRoot. We need to load the image "TiredTurtle.png" from the application bundle and place it in a TextureData object. This can be done with one line:
// Entry point for the App. A good place to start. PXTextureData *textureData = [PXTextureData textureDataWithContentsOfFile:@"TiredTurtle.png"];
A TextureData object simply represents image data in memory. To draw a TextureData to the screen we'll need to place it inside of a Texture display object (to read more about this check out the manual).
6.3 Adding the image to the screen
Remember our ivar image? It's going to represent our turtle on the screen. Let's set that up:
image = [[PXTexture alloc] initWithTextureData:textureData];
Now we have a Texture display object that uses "TiredTurtle.png" as its image source. Next, let's add it to the screen.
[self addChild:image];
Notice that in order to add the image to the screen we just added it to self. This is because self happens to be the root of the main display list. You can read more about it in the manual.
- Run it
We're not done yet, but you can give it a run. You should see your image in the top-left corner of the screen.
6.4 Positioning the image
Things usually look cooler in the center, so let's place the image in the center of the screen:
image.x = self.stage.stageWidth * 0.5f; image.y = self.stage.stageHeight * 0.5f;
Here's what our app should look like now:
Now you may be thinking, "wait, the image isn't in the middle...". Well, actually the origin of our image is in the center of the screen. The reason it doesn't look centered though is that the anchor of our image is in the top-left (this is the default anchor position). This image should explain:
Pixelwave is nice enough to let us change the anchor' position, so let's set it to the center of the display object instead of top-left.
[image setAnchorWithX:0.5f andY:0.5f];
Now our image is truly be in the middle of the screen:
As you may have guessed, the setAnchorWithX:andY: method accepts percentage values. An anchor point of {0, 0} means the top-left corner, while {1, 1} means bottom-right.
If we wanted to we could also set the anchor values individually like so:
image.anchorX = 0.5f; image.anchorY = 0.5f;
6.5 Listening to touch events
Alrighty, now we know how to load an image and draw it in the center of the screen. Virtual high five: o/\o.
Our next task is to make the image move. But first we need to figure out where it should go.
We said we want the user to be able to press where they want the image to travel, so we'll need to listen to touch events and use the position of a touch to tell the image where to go. Let's create our event listening method (in HelloWorldRoot.m):
- (void)onTouchDown:(PXTouchEvent *)event
{
}
Now, let's tell Pixelwave to call our new method whenever the user touches the screen. In the initializeAsRoot method add the following code:
[self.stage addEventListenerOfType:PXTouchEvent_TouchDown
listener:PXListener(onTouchDown:)];
We add our touch event listener tostageinstead of justselfbecause we want to be notified of every touch that occurs on the screen. If we were to add our listener to a specific display object other thanstage, we'd only receive touch events when the user presses that display object or any of its children.
Ok, let's give this a quick test. For now, instead of animating our image over to the user's finger, let's just make it appear there immediately. Edit the onTouchDown: method to look like this:
- (void)onTouchDown:(PXTouchEvent *)event
{
image.x = event.stageX;
image.y = event.stageY;
}
- Give it a run
The image should hop over to your finger whenever you touch the screen.
6.6 Animating it
Our app is looking better by the minute. To make it a little bit more awesome, let's have our image animate over to the user's finger instead of just showing up there.
To do any sort of animation we need to set up a running loop. Pixelwave makes it really easy, you just need to listen to the enterFrame event, which gets dispatched several times a second, depending on what you set your frameRate as. By default, the frame rate is 60Hz (60 frames per second).
So let's add another event listening method to handle these enterFrame events (in HelloWorldRoot.m):
- (void)onEnterFrame{
image.x += (targetX - image.x) * 0.1f;
image.y += (targetY - image.y) * 0.1f;
}
Now lets register our event listener with Pixelwave. Add the following In the initializeAsRoot method:
[self addEventListenerOfType:PXEvent_EnterFrame
listener:PXListener(onEnterFrame)];
That's it for event listeners. To make sure that our image doesn't try to animate to a weird location when the app starts up, let's initialize our target position to a sensible value:
targetX = image.x; targetY = image.y;
There's one last thing we need to do to make our image move to a touch. Remember how we put some temporary code in onTouchDown:? Let's replace it with this:
- (void)onTouchDown:(PXTouchEvent *)event
{
targetX = event.stageX;
targetY = event.stageY;
}
- Give it a go
it should now do everything we wanted. But we're not completely done yet because we didn't clean up our memory allocations.
6.7 Cleaning up
Last (but not least!), we need to take care of cleaning up the memory we used. Let's head over to our dealloc method and write:
// Cleaning up: Release retained objects, remove event listeners, etc.
[image release];
image = nil;
[self.stage removeEventListenerOfType:PXTouchEvent_TouchDown
listener:PXListener(onTouchDown:)];
[self removeEventListenerOfType:PXEvent_EnterFrame
listener:PXListener(onEnterFrame)];
7 Conclusion
So that was your first Pixelwave project. Your next one is bound to be even cooler. To recap, we learned how to:
- Create a new Pixelwave project
- Load an image
- Position display objects
- Interact with user touches
- Create a main loop for animations
But more importantly, we got to spend some quality time together. Let's do this again some time. I included the full source code for this project below if you need to double check what you wrote.
8 Going beyond the call
If you're feeling adventurous, here are a things you can add to the project as an extra challenge. I will only give you hints with these:
- Have the image follow the finger as it moves around the screen (hint: Look into
PXTouchEvent_TouchMove). - Make the image rotate slowly at a constant pace (hint: Look into the
rotationproperty of display objects). - Create two images, each to be controlled by a different finger (hint: You'll need to set
view.multiTouchEnabled = YESin the AppDelegate).
9 Complete source
HelloWorldRoot.h
#import "Pixelwave.h"
@interface HelloWorldRoot : PXSprite
{
PXTexture *image;
float targetX, targetY;
}
- (void) initializeAsRoot;
@end
HelloWorldRoot.m
#import "HelloWorldRoot.h"
@implementation HelloWorldRoot
- (void) initializeAsRoot
{
// Load our image
PXTextureData *textureData = [PXTextureData textureDataWithContentsOfFile:@"TiredTurtle.png"];
image = [[PXTexture alloc] initWithTextureData: textureData];
// Add the image to the display list
[self addChild:image];
// Place the image in the center of the screen
image.x = self.stage.stageWidth * 0.5f;
image.y = self.stage.stageHeight * 0.5f;
// Set the anchor of the image to the center
[image setAnchorWithX:0.5f andY:0.5f];
// Add event listeners
[self addEventListenerOfType:PXTouchEvent_TouchDown
listener:PXListener(onTouchDown:)];
[self addEventListenerOfType:PXEvent_EnterFrame
listener:PXListener(onEnterFrame)];
// Initialize variables
targetX = image.x;
targetY = image.y;
}
- (void) onTouchDown:(PXTouchEvent *)event
{
targetX = event.stageX;
targetY = event.stageY;
}
- (void) onEnterFrame
{
image.x += (targetX - image.x) * 0.1f;
image.y += (targetY - image.y) * 0.1f;
}
- (void) dealloc
{
// Cleaning up: Release retained objects, remove event listeners, etc.
[image release];
image = nil;
[self.stage removeEventListenerOfType:PXTouchEvent_TouchDown
listener:PXListener(onTouchDown:)];
[self removeEventListenerOfType:PXEvent_EnterFrame
listener:PXListener(onEnterFrame)];
[super dealloc];
}
@end
- This page was last modified on 12 August 2011, at 05:43.
