Saturday, January 1, 2011

Project Jumper Part 5: Killing the player, aka Failure Is Always an Option.

Happy New Year, everyone! I hope you had the most excellent of holidays. Me, I'm celebrating the new year by getting helmutguy killed.

Incidentally, my original plan for this installment was to get started with sound. On the surface, it seem like it's a straightforward and simple thing to do, right? Make sound, embed the sound into your program, play the sound when appropriate. Done. Simple. If only! It turns out, you can't embed a .wav file into flash! It only supports mp3s. I could just convert all the sounds I make into mp3 format first, but there are certain technical reasons why that's not super great for sound effects. There are workarounds, but I'm going to fiddle around with them and see what works best.

Meanwhile, it's time for danger!

Getting killed

As you probably noticed, nothing in particular happens when helmutguy meets up with Skel-monsta. Skel-monsta just does a little dance. That's because there's no code in place for when they collide. Let's start with something simple: When they touch, helmutguy explodes. That should be fun.

It turns out that this is one of the thing that Flixel makes super easy. First, we just have to tell it to look out for helmutguy and Skel-monsta trying to be in the same place at the same time. There's lots of ways to do this. I could put something if(overlaps(skelmonsta)) in player.Update(), but that would mean I'd have to change the player declaration and I'm too lazy for that. I could do it the way that Adam Atomic does it in Mode, which is to use FlxU.overlap(object1, object2, function) in playstate.Update(). That's actually probably a good way to do it, especially when you've got everything sorted properly into groups. I haven't started putting things properly into groups yet, so I'm just going to do this the most obvious (to me) way. In playstate.Update(), I add these lines of code:

 //Check for impact!
 if (player.overlaps(skelmonsta))
 {
     player.kill();
 }

This actually works as-is, sort of. As soon as helmutguy and Skel-monsta bump into each other, helmutguy disappears into thin air. Not exactly exciting, so let's spice it up a bit.

Getting killed better
I'm going to take my cue from Mode, and use Flixel's emitter class to make a nice little explosion effect for poor helmutguy.
Zoom in!

First, I recolored the gibs sprite that Mode uses to match helmutguy a little better. Obviously it would be better to make custom chunks. Obviously, I am lazy.

I did this the wrong way at first. See, I figured that since it's the player that's exploding, I'd put all the declarations and stuff in the player.as file. Turns out, I forgot that in order to actually display a sprite, you have to add() it in the playstate. So the best way to handle this is to declare and set up the gibs in the playstate, then pass it on to the player.
playstate.as looks a little like this now:

(...)
[Embed(source = '../../../../art/gibs.png')]public var imgGibs:Class;
(...) 
protected var gibs:FlxEmitter;
        
override public function create():void
{
    // Set up the gibs
    gibs= new FlxEmitter();
    gibs.delay = 3;
    gibs.setXSpeed( -150, 150);
    gibs.setYSpeed( -200, 0);
    gibs.setRotation( -720, -720);
    gibs.createSprites(imgGibs, 50, 15, true, 0.5, 0.65);
(...)
    add(player = new Player(1000, 640,gibs));  // need to change this line to include the gibs, thanks evgeny
(...)
    //Still in the Create() function 
    //Add the gibs after everything else, so they show up on top.
    add(gibs);
That's all just copied out of Mode. Most of that is pretty self explanatory, at least while FlashDevelop pops up the headers for you, except I'm still not sure what setRotation does. I tried some different values, and didn't see any obvious difference.

Edit: Over on the flixel forums, Survivor pointed out that createSprites() is only supposed to have 5 parameters, but I'm using 6. On the online documentation, it only lists the first 5 parameters (Graphics, Quanity, BakedRotation, Multiple, and Collide) but there's also a 6th one, Bounce. The documentation included in the Flixel package I downloaded DOES mention the 6th parameter, and of course since FlashDevelop looks at the class itself, it says exactly what parameters are expected. So I guess the lesson here is you can't always trust everything you read!

Anyway, on to the player.

(...)
protected var gibs:FlxEmitter;
(...)
public function Player(X:int,Y:int,Gibs:FlxEmitter):void // X,Y: Starting coordinates, Gibs is the gibs object we made over in PlayState.as
{
    super(X, Y);
( All the old stuff still goes here...)          
    gibs = Gibs;
}
(...)
//Here's our new function to kill poor helmutguy.
public override function kill():void
{
    if (dead) { return; }  // If he's already dead, no need to keep killing him, right?
    super.kill();
    FlxG.quake.start(0.005, .35);
    FlxG.flash.start(0xffDB3624, .35);
    if (gibs != null)
    {
        gibs.at(this);
        gibs.start(true, 2.80);
    }
}

Hey, it works! Poor helmutguy...


That was another quickie, but at least progress was made! Maybe soon I'll give helmutguy a way to fight back...
Source code here and flash file here

7 comments:

  1. also i modify:
    1) add(player = new Player(1000, 640,gibs));
    (added gibs)

    2) gibs.createSprites(imgGibs, 50, 15, true, 0.5);
    (remove last parameter - 0.65, becouse its only 5)

    ReplyDelete
  2. Whoops, good catch! Yes, you do need to change the add(player bit to include the gibs. I included that in my code, forgot to show it in the article.

    As I mentioned in the edit, there really are 6 parameters. The last one is bounce, and it does work, I tested it. :D

    ReplyDelete
  3. I don't know, the bounce didn't work for me either, and I have the latest stable build.

    ReplyDelete
  4. OK, I did a little more research. The standard stable build doesn't have a bounce parameter, but the beta and latest builds do. It's no big deal, if you're using the standard build just leave the last one out.

    ReplyDelete
  5. Excellent!

    Again some changes in the latest version of flixel (2.5+) :
    gibs.lifespan = 1 ; // no more delay
    gibs.setXSpeed( -100, 100);
    gibs.setYSpeed( -100, 0 );
    gibs.setRotation( -720, 720 );
    gibs.gravity = GRAVITY / 2 ; // add some gravity to the gibs
    gibs.makeParticles( m_gibsSprite, 50, 15, true, 0.5); // no more createSprites
    gibs.bounce = 0.65; // bounce is a separated member variable

    ReplyDelete
  6. I had every error I encountered fixed until it said: "Access of undefined property dead."

    For anyone following this tutorial, you'll need to use

    if (!exists) { return; }

    instead of

    if (dead) { return; }

    ReplyDelete
  7. Awesome work dude!

    There are a few things in addition to comments:

    Properties 'alive' and 'exist', it appears to function in the same way. Course, instead of property 'dead'

    And

    FlxG.shake(0.05, 0.35);
    FlxG.flash(0xffDB3624, 0.35);

    instead of

    FlxG.quake.start(0.005, .35);
    FlxG.flash.start(0xffDB3624, .35);

    Thansk a lot :)

    ReplyDelete