Page 2 – Pick Ups

Page One

Step Four:  Pick Ups

Alright, so one thing you need in any game is pick-up items, whether that be gold, health, magic, bananas, or in my case gems.  If you’ve played AdventureBall then you’ve seen the gems in that, and you can see them in pictures on my blog here.  This isn’t the exact same gem, this one is four instead of three sided, but it needs to act the same.  I was hoping to create the desired actions with LUA, and indeed did, but I had the problem of the LUA script not being copied with the sio2ObjectHardCopy or sio2ObjectSoftCopy.  I also couldn’t access the hard or soft copied objects from a LUA script.  Rom seemed to be saying on the forum that the HardCopy should copy the LUA script as well (I think, he is a man of few words), but I am a self taught programmer and don’t know what I am doing wrong.  So I didn’t use LUA.  I did it all in my gameLoading and gameRendering, and it works like a charm.

Pick-Ups Files

Creating the Gem

This is real easy.  Open Blender, select the default cube and tab into Edit Mode.  In Face Select Mode (ctrl+tab – 3 in Edit Mode) select the top face and press E to extrude it.  Press 1 to extrude it one unit.  Your object should now be half again as tall as it originally was.  In Vertices Select Mode (ctrl+tab – 1 in Edit Mode) select the top four vertices and press S, then 0 (zero) then Enter.  This will scale (S) the four vertices to zero, moving them all to the same spot, creating a point.  Now your box should look like a cube with a pyramid on top, or a simple house or something.  Do the same to the bottom four vertices, and you will have a simple gem shape.  I’m sure I adjusted the height of the top and bottom a little, but the only other thing to so is remove the double vertices.  Press A until all the vertices are yellow (selected), then press W to bring up the Specials Menu (in Edit Mode) and press Remove Doubles.  A pop up should tell you that 6 vertices have been removed.  Hopefully I haven’t forgotten anything, I’ve written this from memory.  The file is available at the top of the page.  The object really isn’t important though, it could be whatever you want to duplicate.

Xcode

I have separated the gem in it’s own .sio2 file for reasons that should hopefully become obvious as I continue my documentation of this game.  After loading the gem, I duplicate it using the code from the wiki.

Then in gemRendering I use a similar process to iterate through the copied gems rotating them, then checking to see if the player is within one unit of the current gem.  If it is this gem is moved vertically by 100 units, out of camera range.  I should probably make it invisible too using the same command from the last line of the previous code snippet, but I haven’t yet so it isn’t in the code here.  The line with all the sqrt functions is basically two a2 + b2 = c2 equations used to calculate the 3D distance between the player and the current gem.

Currently this just creates ten gems in a row, but soon it will load them from a vec3 array where I will specify the locations I want the gems to live.  For a lot of levels this could turn into a lot of manual data entry, but a clever person could easily make a python script that would let you place them all in Blender, then export only the xyz locations into a text file that is of the exact format you need.  I am too busy/lazy to go and learn enough python to do that right now so I will settle for a little manual entry.

I have also not textured the gems yet.  I was hoping to change the texture colour as I iterate through them in duplication, but the forum seems to say I can’t do this (until SIO2 1.5) without using some sort of modified HardCopy.  I tried using the code here but couldn’t get it to work due to my own inexperience coding I am sure.  I am not too worried about it though.  I hope 1.5 will be out before this version of my game is released and I don’t have to worry about modifying things.  That is all for today.

~KeithK

Step Four Point Five:  Pick Ups (continued)

Four Point Five Files

Gems and Empties

So despite whatever I said in the previous two paragraphs I decided to locate my gems in each level with empties. In Blender place a gem where you want then press Shift-S, to bring up the Snap menu, and select Cursor -> Selection. This moves the cursor to the centre of the current selection, the gem you just placed. Then press the spacebar and select Add -> Mesh -> Empty Mesh. I have named mine GemLoc_0, GemLoc_1, etc. Then delete the gem(s) and export the GemLoc_x empties with your level.

Lua Variables

As I am a total newb when it comes to programming I still haven’t figured out how to use SWIG to wrap my variables and functions, so to get variables back and forth between Lua and Xcode I am using the rotation of an object that is off screen. I used a plane object instead of an empty because I believe empties only have location data, not rotation and scale. With all three I have at least nine variables I will be able to transfer instead of just three. Of course right now I don’t even need three, so I have simply moved my plane off screen, and used the rotation. If I need more I will have to give the plane a material so that I can make it invisible, so that no matter the location or scale of the object it can not be seen. I think I also scaled the object down when I made it, but in the future when it is invisible, that totally wont matter.

Xcode

I probably didn’t mention this earlier but I declared these variables to facilitate the loading and rendering of the gems:

SIO2object* gem = NULL;
SIO2object* gem_duplicate = NULL;
SIO2object* obj_loc = NULL;
SIO2material* gemMaterial = NULL;
SIO2object* Lua = NULL;
unsigned int num_gems = 0;
float gem_count = 0.0f;

Then I have changed the loading code to reflect the change in the style of loading the gems, as well as to call the LUA script that I attached to the level. When making each level I will place all the gems as empties, then create the LUA script for the level which will tell the programs how many gems (and other objects not yet created) will be in this level (because I don’t plan on having the same number in every level as AdventureBall currently does).


/////LEVEL LOADING
unsigned int i = 0;
sio2ResourceCreateDictionary( sio2->_SIO2resource );
sio2ResourceOpen( sio2->_SIO2resource, "iMarble.sio2", 1 );
while( i != sio2->_SIO2resource->gi.number_entry )
{ sio2ResourceExtract( sio2->_SIO2resource, NULL );
++i; }
sio2ResourceClose( sio2->_SIO2resource );

sio2ExecLUA("Level.data();");
Lua = sio2ResourceGetObject( sio2->_SIO2resource, "object/Lua" );
num_gems = Lua->_SIO2transform->rot->x;

/////GEM LOADING
i = 0;
sio2ResourceOpen( sio2->_SIO2resource, "Gem.sio2", 1 );
while( i != sio2->_SIO2resource->gi.number_entry )
{ sio2ResourceExtract( sio2->_SIO2resource, NULL );
++i; }
sio2ResourceClose( sio2->_SIO2resource );

gemMaterial = ( SIO2material * ) sio2ResourceGet( sio2->_SIO2resource, SIO2_MATERIAL, "material/gem");
gemMaterial->diffuse->x = 0.0f;
gemMaterial->diffuse->y = 0.0f;
gemMaterial->diffuse->z = 1.0f;
gemMaterial->diffuse->w = 0.75f;

/////GEM DUPLICATION
for( int i = 0; i _SIO2resource, SIO2_OBJECT, "object/Gem" );
char name[ SIO2_MAX_CHAR ];
sprintf( name, "%s_%i", gem->name, i );
char name2[ SIO2_MAX_CHAR ];
sprintf( name2, "%sLoc_%i", gem->name, i );
obj_loc = ( SIO2object * ) sio2ResourceGet( sio2->_SIO2resource, SIO2_OBJECT, name2 );
gem->_SIO2transform->loc->x = obj_loc->_SIO2transform->loc->x;
gem->_SIO2transform->loc->y = obj_loc->_SIO2transform->loc->y;
gem->_SIO2transform->loc->z = obj_loc->_SIO2transform->loc->z;
gem_duplicate = sio2ObjectSoftCopy( gem, name );
sio2TransformCopy( gem_duplicate->_SIO2transform, gem->_SIO2transform );
sio2TransformBindMatrix( gem_duplicate->_SIO2transform );
}
sio2EnableState( &gem->flags, SIO2_OBJECT_INVISIBLE );

Currently this is what the LUA script for the level looks like.
Level = {};
Level.Lua = SIO2.sio2ResourceGetObject( SIO2.sio2._SIO2resource, "object/Lua" );

function Level.data()
--NUMBER OF GEMS
Level.Lua._SIO2transform.rot.x = 9;
end

The rendering code has not changed. I do believe that is all that is has been done at the moment. I am not sure because much of it was done before I went on vacation then moved across the country. I also did much more in a similar fashion with other objects but had much more problems with it, where I had relatively little trouble getting the gems to work like this. I have deleted all of the other stuff from Xcode and Blender I think though, so the files above should be clear of detritus. I think next I am going to try to create two animations that will play upon collection of a gem, the first is some sort of explosion of the gem, and the second being a 50 rising above the gem. That means I will have to incorporate an overall point structure, and that timing isn’t far behind. For now though, fare well.
~KeithK

Step Five: Particles

Step Five Files

So I have added a particle system that creates a mini explosion at the location of the gem as it is collected. It was relatively straight forward, first I took tutorial 12 and cut out everything except the first particle system (fire) and then adjusted it to look how I wanted. Second I took all the relevant code and put it into iMarble, and spent a few hours figuring out why it wasn’t working.

Declarations

These are the declarations I required for my particle system.

float MAX_LIFETIME;
float MAX_SPEED;
SIO2emitter *particleEmitter = NULL;
unsigned int ACTIVE = 0;

Loading

I added this to gameLoading after the binding section.

/////PARTICLE SETUP
SIO2material *particleMaterial = NULL;
SIO2image *particleImage = NULL;
SIO2stream *_SIO2stream = NULL;
particleEmitter = sio2EmitterInit ( "emitter" );
particleMaterial = sio2MaterialInit( "material" );
particleImage = sio2ImageInit( "stars" );
_SIO2stream = sio2StreamOpen( "stars.tga", 1 );
{
sio2ImageLoad( particleImage, _SIO2stream );
sio2ImageGenId( particleImage, SIO2_IMAGE_CLAMP, 0.0f );
}
_SIO2stream = sio2StreamClose( _SIO2stream );
particleEmitter->_SIO2material = particleMaterial;
particleMaterial->diffuse->x =
particleMaterial->diffuse->y = 0.0f;
particleMaterial->diffuse->z = 1.0f;
particleEmitter->_SIO2particlecreation = particle_creation;
particleEmitter->_SIO2particlerender = particle_render;
particleEmitter->maxp = 80;
sio2EmitterSetupParticles( particleEmitter );
MAX_LIFETIME = 0.20f;
MAX_SPEED = 0.15f;
particleEmitter->pps = 1.0f / 0.0f;
particleEmitter->_SIO2transform->dir->x =
particleEmitter->_SIO2transform->dir->y = 0.0f;
particleEmitter->_SIO2transform->dir->z = -0.75f;
particleEmitter->rad = 2.0f;
particleEmitter->_SIO2material->_SIO2image[ SIO2_MATERIAL_CHANNEL0 ] = sio2ResourceGetImage( sio2->_SIO2resource, "stars");
particleEmitter->_SIO2material->blend = SIO2_MATERIAL_ADD;
sio2TransformBindMatrix( particleEmitter->_SIO2transform );
sio2EmitterPlay( particleEmitter );

Particle Creation / Rendering

These two functions were ripped pretty much directly from tutorial 12, with a little bit of tweaking to make it look how I wanted.

void particle_creation( void *_ptr, SIO2particle *_SIO2particle )
{
memcpy( _SIO2particle->loc, particleEmitter->_SIO2transform->loc, 12 );
memcpy( _SIO2particle->col, particleEmitter->_SIO2material->diffuse, 16 );
_SIO2particle->lifetime = MAX_LIFETIME;
_SIO2particle->speed = MAX_SPEED;
_SIO2particle->size = ( float )sio2Randomui( 16 );
_SIO2particle->angle = ( float )sio2Randomui( 360 );
}

void particle_render( void *_ptr, SIO2particle *_SIO2particle )
{
float life = MAX_LIFETIME - _SIO2particle->lifetime;
float temp1 = life * life, temp2 = _SIO2particle->speed * life;
float h_factor = 5.0f * life;
temp1 *= particleEmitter->_SIO2transform->dir->z;
_SIO2particle->col->w = _SIO2particle->lifetime / MAX_LIFETIME;
_SIO2particle->loc->x += ( _SIO2particle->speed * sinf( _SIO2particle->angle * SIO2_DEG_TO_RAD ) ) * h_factor;
_SIO2particle->loc->y += ( _SIO2particle->speed * cosf( _SIO2particle->angle * SIO2_DEG_TO_RAD ) ) * h_factor;
_SIO2particle->loc->z += temp1 + temp2;
}

Rendering

In my gem rendering section I added a bit to move the emitter to the location of a gem that has been picked up, and then a little lower I activate my particle system momentarily. Be sure to activate SIO2_RENDER_EMITTER in sio2ResourceRender(). Also for some reason I had to divide the location of the gem by two for my particle system to be at the right spot. I have no clue why. If anyone knows, or can see where I am moving it again, please let me know.

/////RENDERING CODE
if( _SIO2camera )
{
sio2WindowEnterLandscape3D();
{
sio2CameraRender( _SIO2camera );
{
/////GEM RENDERING
for( int i = 0; i _SIO2resource, SIO2_OBJECT, name );
if(gem)
{
gem->_SIO2transform->rot->z++;
dif.x = (gem->_SIO2transform->loc->x - player->_SIO2transform->loc->x);
dif.y = (gem->_SIO2transform->loc->y - player->_SIO2transform->loc->y);
dif.z = (gem->_SIO2transform->loc->z - player->_SIO2transform->loc->z);
if((sqrt(sqrt((dif.x * dif.x) + (dif.y * dif.y))*sqrt((dif.x * dif.x) + (dif.y * dif.y)) + (dif.z * dif.z))) _SIO2transform->loc->x = gem->_SIO2transform->loc->x/2;
particleEmitter->_SIO2transform->loc->y = gem->_SIO2transform->loc->y/2;
particleEmitter->_SIO2transform->loc->z = gem->_SIO2transform->loc->z/2;
ACTIVE = 1;
gem->_SIO2transform->loc->z = gem->_SIO2transform->loc->z + 100;
sio2EnableState( &gem->flags, SIO2_OBJECT_INVISIBLE );
gem_count = gem_count + 1;
}
sio2TransformBindMatrix( gem->_SIO2transform );
sio2TransformBindMatrix( particleEmitter->_SIO2transform );

}
}

sio2ExecLUA("Player.render();");
//NSLog(@"%.3f %.1f",sio2->_SIO2window->fps, gem_count );
sio2CameraGetModelviewMatrix( _SIO2camera );
sio2CameraUpdateFrustum( _SIO2camera );
sio2ResourceCull( sio2->_SIO2resource, _SIO2camera );
sio2ResourceRender( sio2->_SIO2resource, sio2->_SIO2window, _SIO2camera, SIO2_RENDER_EMITTER | SIO2_RENDER_SOLID_OBJECT | SIO2_RENDER_ALPHA_TESTED_OBJECT | SIO2_RENDER_TRANSPARENT_OBJECT );
}
sio2PhysicRender( sio2->_SIO2physic, sio2->_SIO2window->d_time, 1 );
}
sio2WindowLeaveLandscape3D();

/////PARTICLE ACTIVATOR
if( ACTIVE )
{ ACTIVE = 0;
particleEmitter->pps = 1.0f / 80.0f; }
else if ( !ACTIVE )
{ particleEmitter->pps = 1.0f / 0.0f; }

}

I think that is all for now. Next I will add sound so when you pick up a gem it will go clink or something. God knows I will probably continue to tweak the particle system to make it work better, but I probably wont tell you, so if you download a later version of this and it looks different, that is why.

Step Six: Sound

Step Six Files

To finish off my gems, I have added a little ‘clink’ sound, the same as in AdventureBall. I haven’t added the other sounds from AdventureBall yet, as I’m not sure I am going to keep them. I may even change the clink sound a little at some point, we’ll see. But for now there is sound, and it is rather easy to get it working.

Blender

In Blender all I did was create a plane, scale it down a bunch, then translate it up by 100 units, then give it a sound. This way, even if it does somehow get on screen it is tiny, and I am not loading the sound nine times for each gem in the scene.

EAGLView

You have to add this line of code to your EAGLView.mm, in the same place you init LUA.

sio2InitAL();

gameLoading

In gameLoading I added one line to the binding section, and added a new section right after it for sound setup. The sio2ResourceBindAllSounds() has to come after GenId or ResetState or something (I’m not sure which), or your sound wont work. That is why it is with the sound settings instead of the binding, when it is clearly a binding command.

/////BINDING
sio2ResourceBindAllSoundBuffers( sio2->_SIO2resource );
sio2ResourceBindAllImages( sio2->_SIO2resource );
sio2ResourceBindAllMaterials( sio2->_SIO2resource );
sio2ResourceBindAllMatrix( sio2->_SIO2resource );
sio2ResourceBindAllPhysicObjects( sio2->_SIO2resource, sio2->_SIO2physic );
sio2ResourceGenId( sio2->_SIO2resource );
sio2ResetState();

/////SOUND SETTINGS
sio2ResourceBindAllSounds( sio2->_SIO2resource );
sio2->_SIO2window->volume = 1.0f;
sio2->_SIO2window->fx_volume = 1.0f;
sio2ResourceSetAmbientVolume( sio2->_SIO2resource, sio2->_SIO2window );
sio2ResourceSetFxVolume( sio2->_SIO2resource, sio2->_SIO2window );

Activating The Sound

Since I already have a callback for when you collect a gem, I just added the sound activation code to that.

>code>/////PARTICLE ACTIVATOR
if( ACTIVE )
{ ACTIVE = 0;
particleEmitter->pps = 1.0f / 80.0f;

/////ACTIVATE CLINK SOUND
SIO2object *clink = ( SIO2object * )sio2ResourceGet( sio2->_SIO2resource, SIO2_OBJECT, “object/Clink” );
unsigned int j = 0;
while( j != clink->n_sound )
{
sio2SoundPlay(clink->_SIO2sound[j]);
++j;
}
}

And I do believe that is all I did to get sound into the game. If you add this to your code and it doesn’t work then check the files, I probably missed something.
~KeithK

Page One

3 Responses to Page 2 – Pick Ups

  1. Ken Yen says:

    Hi KeithK
    I’m Ken from SIO2 forum, we talked a few times before hope you still remember? haha maybe not…
    Just wanna tell you that these tutorials are awesome and helped me a lot!! there are also a lot of new techniques on how you use SIO2 and LUA scripts(which i still don’t know the advantage of use it yet…)..

    I’m still struggling with this engine, hope that if I got some questions you may be able to help a bit, and I found SIO2 forum like a dead place…. :(…

    Anyway, just wanna say thank you for providing such a great tutorials on SIO2 🙂

  2. keithkarnage says:

    Unfortunately I haven’t used SIO2 in more than a year now, and have migrated somewhat to the Unity game engine, so I don’t know how much help I would be with SIO2. As for LUA, I think the idea is that you can attach small routines to game objects so they do not have to be hard coded. It is a bit of a different language, but can be really useful in keeping your coding brief. I’m sure there are other benefits to scripting, they just don’t come to mind at the moment. Good luck with your games.

    ~KeithK

    • Ken Yen says:

      Yes, I realized a lot of people already migrated to Unity now and that’s what I’m going to do for my next game, but gotta finish this game first… haha…

      The only problem is that the 3D integration for Blender & SIO2 (v1.4 the free version) is having really a lot of Mysterious black box stuff going on and they’re not clearly summarized in 1 place (eg. what parameters in blender affects in game engine..etc), also there are a lot of harsh stuff going on without a lot of support either… maybe the author is trying to force people to buy the source code to study so he didn’t share a lot of informations about the tricks inside.. that’s really a bad decision, 😦 anyway, just wanna say thanks for your great tutorial, Hope they can solve all my problems, haha 🙂

Leave a comment