OpenGL ES Particle System Tutorial: Part 3/3

In this third part of our OpenGL ES particle system tutorial series, learn how to add your particle system into a simple 2D game! By Ricardo Rendon Cepeda.

Leave a rating/review
Save for later
Share

Welcome back to our 3-part OpenGL ES particle system tutorial series! Here you’ll learn how to make a cool and fun particle system from scratch, and integrate it into an iOS app.

Here’s an overview of the series:

  • Part 1: In the first part, you learned all about particle systems and point sprites, and created a small app to help you learn as you go.
  • Part 2: In the second part, you learned to create a generic particle-emitter paired system. That’s code word for “awesome and reusable”.
  • Part 3: You are here! In this final part, you’ll use your newly developed skills to integrate particle effects into a simple 2D game.

Keep reading for a quick review, then we’ll dive right in.

Particle System and 2D Game Series Review

The first two parts of this OpenGL ES particle system tutorial series covered the following concepts:

  • Particle-Emitter Hierarchies
  • Point Sprites
  • Vertex and Fragment Shaders
  • GPU-CPU Communication
  • Basic Math and Physics
  • Linear Animation
  • Abstracted Graphics Objects

The 2D game you will be integrating the particle system into comes from the simple OpenGL game series. This two part series covered the following concepts:

  • OpenGL ES 2.0 and GLKit: The project chassis is essentially the same as the one in your particle system. It uses a GLKit View Controller and implements the relevant delegate methods. However, the greatest difference between the tutorials is that the 2D Game series uses GLKBaseEffect instead of custom shaders.
  • Sprites: The 2D Game series uses points to draw sprites instead of textured quads.
  • Subclasses and Nodes: All classes in the 2D Game project are prefixed with SGG, which stands for Simple GLKit Game. Most classes in that series are subclasses of SGGNode, which provides the interface for the render and update cycles which are accessed through the SGGViewController’s GLKit delegate methods.
  • Linear Animation: In the 2D game, monsters and ninja stars move in straight lines as a function of time. Locations of the monsters are generated randomly, while the ninja stars are generated by tapping the screen.
  • Collision Detection: If a ninja star hits a monster’s bounding box, then both the ninja star and the monster sprites are removed from play.
  • Scene Hierarchies and Game Logic: The entire game belongs to a master scene, which controls the individual rendering, animation, and lifecycle of all sprites in the game.
  • Audio Playback: The project uses the CocosDenshion audio library from Cocos2D to handle background music and sound effects.

It’s highly recommended that you complete the simple OpenGL game series if you haven’t already done so. Both parts of the 2D Game series are great tutorials with plenty of valuable OpenGL ES 2.0, GLKit, and gaming information. As well, you’ll feel much more comfortable navigating the starter project for this last tutorial.

To those of you wondering why the particle system series didn’t use GLKBaseEffect, and to those who have worked through the previous tutorials in this series using OpenGL ES 2.0, I offer up the following image as an explanation:

20BE

Getting Started

First, download the starter code for this tutorial.

The starter project is essentially the finished and refactored project from the simple 2D game series: SimpleGLKitGame3. However, the project has been renamed to GLParticles3 for the sake of continuity and contains the ShaderProcessor files from the previous parts of this particle system series. It also includes some texture and sound resources you’ll use later.

Open up your project in Xcode. Now build and run — bet you weren’t expecting that so soon, were you? :]

Play around with the game — it should function just as it did at the end of the second part of the 2D game series. However, nothing really exciting happens when a ninja star hits a monster: both sprites simply disappear from the screen. You can use your knowledge of particle systems to add some spectacular effects each time you hit the monster!

Deciphering the Game Hierarchy

Open up SGGViewController.h and SGGViewController.m and read through each of them. You’ll notice that an SGGNode property named scene, which is initialized as an SGGActionScene, handles the touch events as well as the rendering and update cycles.

Now open up SGGNode.h and SGGNode.m and read through those two files. These form the parent class for every sprite and scene — also known as nodes — in the game. This class contains many properties relevant to the nodes and visuals that it contains, but no actual rendering or game logic is involved. Instead, these tasks are handled by the nodes themselves as subclasses of SGGNode.

Take a close look at the following methods in SGGNode.m:

- (void)renderWithModelViewMatrix:(GLKMatrix4)modelViewMatrix 
{
    GLKMatrix4 childModelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, [self modelMatrix:NO]);

    for (SGGNode * node in self.children) 
    {
        [node renderWithModelViewMatrix:childModelViewMatrix];
    }
}

(void)update:(float)dt 
{    
    for (SGGNode * node in self.children) 
    {
        [node update:dt];
    }
    
    GLKVector2 curMove = GLKVector2MultiplyScalar(self.moveVelocity, dt);
    self.position = GLKVector2Add(self.position, curMove);
    
    float curRotate = self.rotationVelocity * dt;
    self.rotation = self.rotation + curRotate;

    float curScale = self.scaleVelocity * dt;
    self.scale = self.scale + curScale;
}

In particular, you’ll be interested in the following lines:

for (SGGNode * node in self.children)
{
    [node renderWithModelViewMatrix:childModelViewMatrix];
}

As well as:

for (SGGNode * node in self.children) 
{
    [node update:dt];
}

Note that the nodes run their own methods that are called from within these rendering and update cycles.

To see this in more detail, open up SGGSprite.m and examine the method renderWithModelViewMatrix: which renders a sprite. As well, open up SGGActionScene.m and take a look at the method update:, which handles the game logic and animation.

If you’re wondering why handleTap: in SGGNode has an empty implementation, that’s because it’s passed along the node chain to SGGActionScene, and you need at least a stub implementation to avoid compiler errors.

By looking through the files, it should be clear that in order to render and animate your particle effects you will need to create a subclass of SGGNode that implements the methods renderWithModelViewMatrix: and update:.

Creating the Emitter

Go to File\New\File… and create a new file with the iOS\Cocoa Touch\Objective-C class subclass template. Enter SGGEmitter for the class and SGGNode for the subclass. Make sure both checkboxes are unchecked, click Next, and click Create.

There’s no need to modify these new files yet. Before you do anything, you’ll first need to create a home for your SGGEmitter.

If you paid close attention to the SGGActionScene files, you will have noticed that this is where sprites are added to and removed from the game.

Open up SGGActionScene.m and add the following line near the top of the file with the other #import statements:

#import "SGGEmitter.h"

Just a little further down SGGActionScene.m, add the following line inside the property declarations:

@property (strong) NSMutableArray* emitters;

Still working in SGGActionScene.m, add the following line to initWithEffect:, just after the line self.targets = [NSMutableArray array];:

self.emitters = [NSMutableArray array];

The stage is now set for your emitters — you now need a method to add these emitter objects to your game.

Add the following code to SGGActionScene.m just above the @end statement at the bottom of the file:

- (void)addEmitter
{
    SGGEmitter* emitter = [[SGGEmitter alloc] init];
    [self.children addObject:emitter];
    [self.emitters addObject:emitter];
    NSLog(@"ADD EMITTER");
}

This code initializes a new SGGEmitter object and adds it to your emitters array as well as to this object’s children array.

Finally, locate the following loop within the update: method of SGGActionScene.m:

for (SGGSprite * target in targetsToDelete)

Add the following line to the very beginning of the loop:

[self addEmitter];

This simple line adds an emitter object to your game whenever a target — that is, an enemy — is removed from the game when it has been hit by a ninja star.

Build and run your project — you won’t notice any visual changes, but you should see an ADD EMITTER message on your console output whenever you hit a target, as shown below:

Run2

Ricardo Rendon Cepeda

Contributors

Ricardo Rendon Cepeda

Author

Over 300 content creators. Join our team.