Billy the Box

by mach51
It's a box! It can move. Arrow keys and space bar. I think I put more time into the particles...
♥0 | Line 232 | Modified 2012-08-27 11:10:04 | MIT License
play

ActionScript3 source code

/**
 * Copyright mach51 ( http://wonderfl.net/user/mach51 )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/iGj9
 */

package
{
    
    import flash.display.MovieClip;
    import flash.events.KeyboardEvent;
    import flash.events.Event;
    import flash.ui.Keyboard;
    
    [SWF(width = '400', height = '600', backgroundColor = '#000000', frameRate = '30')]
    
    /** 
    * there is some reduncancy in the code
    * I was just playing around.
    */
    public class Main extends MovieClip
    {
        public var bill:Billy;
        public const g:Number = 1.5;
        public const kf:Number = 0.98;
        public const bounciness:Number = 0.5;
        public const PARTICLE_COUNT:int = 20;
        public const PARTICLE_LIFE:int = 30;
        
        public var particles:Vector.<Particle> = new Vector.<Particle>();
        
        public function Main()
        {
            bill = new Billy(5.0, new PhysicalWorld(1.5, 0.98, 0.5)); // (mass), g, kf, bounciness
            addChild(bill);
            
            bill.x = (stage.stageWidth - bill.width) / 2;
            bill.y = (stage.stageHeight - bill.height) / 2;
            
            stage.addEventListener(KeyboardEvent.KEY_DOWN, pushBox);
            stage.addEventListener(KeyboardEvent.KEY_UP, stopPushing);
            stage.addEventListener(Event.ENTER_FRAME, step);
            
        }
        
        public function pushBox(e:KeyboardEvent):void
        {
            switch(e.keyCode)
            {
                case Keyboard.LEFT:
                bill.ax = -1.0;
                break;
                case Keyboard.RIGHT:
                bill.ax = 1.0;
                break;
                case Keyboard.UP:
                bill.ay = -(g + 1.0);
                break;
                case Keyboard.DOWN:
                bill.ay = 1.0;
                break;
                case Keyboard.SPACE:
                if(bill.isOnGround){
                    bill.vy = -25.0;
                }
                break;
                case Keyboard.ENTER:
                bill.x = (stage.stageWidth - bill.width) / 2;
                bill.y = (stage.stageHeight - bill.height) / 2;
                bill.ax = 0.0;
                bill.ay = 0.0;
                bill.vx = 0.0;
                bill.vy = 0.0;
                break;
            }

        }
        
        public function stopPushing(e:KeyboardEvent):void
        {
            switch(e.keyCode)
            {
                case Keyboard.LEFT:
                bill.ax = 0.0;
                break;
                case Keyboard.RIGHT:
                bill.ax = 0.0;
                break;
                case Keyboard.UP:
                bill.ay = 0.0;
                break;
                case Keyboard.DOWN:
                bill.ay = 0.0;
                break;
            }
        }


        public function step(e:Event):void
        {
            
            bill.vy += bill.ay + g;
            bill.vx += bill.ax;
                
            bill.y += bill.vy;
            bill.x += bill.vx;
            
            bill.vy *= kf;
            bill.vx *= kf;
            
            stepParticles();
            
            if(bill.y + bill.height > stage.stageHeight)
            { // on ground
                bill.y = stage.stageHeight - bill.height;
                spawnParticlesAt(bill.x + bill.width/2, bill.y + bill.height);
                bill.vy *= -bounciness;
                bill.isOnGround = true;
            }
            else
            {
                bill.isOnGround = false;
            }

            
            if(bill.y < 0){ // hits roof
                bill.y = 0;
                spawnParticlesAt(bill.x + bill.width/2, bill.y);
                bill.vy *= -bounciness;
            }
            
            if(bill.x + bill.width > stage.stageWidth){ // on right wall
                bill.x = stage.stageWidth - bill.width;
                spawnParticlesAt(bill.x + bill.width, bill.y + bill.height/2);
                bill.vx *= -bounciness;
            }
            
            if(bill.x < 0){ // on left wall
                bill.x = 0;
                spawnParticlesAt(bill.x, bill.y + bill.height/2);
                bill.vx *= -bounciness;
            }

        }
        
        public function spawnParticlesAt(x:int, y:int):void
        {
            for(var i:int = particles.length; i < PARTICLE_COUNT; i++)
            {
                var p:Particle = new Particle(10, 10, PARTICLE_LIFE);
                particles.push(p);
                addChild(p);
                p.x = x;
                p.y = y;
                
                p.vx = -(bill.vx + (Math.random()*20));
                p.vy = -(bill.vy + (Math.random()*20));
            }
        }
        
        public function stepParticles():void
        {
            for(var k:int = 0; k < particles.length; k++)
            {
                var p:Particle = particles[k];
                p.alpha -= 1/p.frameLife; 
                if(p.alpha < 0)
                {
                    removeChild(particles[k]);
                    particles.splice(k, 1);
                }
                else
                {
                    p.x += p.vx;
                    p.y += p.vy;
                    
                    p.vx *= kf;
                    p.vy *= kf;
                }


            }
        }
    } // end class

} // end package

import flash.events.Event
import flash.display.MovieClip;

/**
* The Billy object is basically a MovieClip that can handle it's own physics, given a set of rules (the PhysicalWorld) and a mass.
* In that sense, you can use the Billy object as a generic 'PhysicalMovieClip' object to create any kind of MovieClip that also has
* physical properties.
*
* In a hardcore programming environment, TECHNICALLY you'd want PhysicalWorld to be an abstract class requiring the coder to fill in how
* the PhysicalWorld should actually use and execute the "laws of physics".
* In this case, I'll just let the Billy class deal with those methods--err sorry, functions. I'm a java person.
* ... Can you even have abstract classes in as3?
*
* Ahhh forget this... it's way beyond the scope of this program. Billy can't actually take care of all his
* own physics because he's not aware of where the 'bill' instance is on the stage's coordinate space.
* You can make this work by expanding the PhysicalWorld class so that it actually keeps a list of different
* instances of physical MovieClip objects (the world knows what's inside it) and you'd use the PhysicalWorld by adding
* objects to it. The PhysicalWorld will then take care of all the physics with an ENTER_FRAME event listener and handles the
* speeds, accelerations, etc of the MovieClips, and returns to the stage the new positions of the MovieClips. 
*
* Basically what I'm saying is the PhysicalWorld class is a simpler way of organizing and simulating physics of objects
* instead of dumping it all in the document class. Organizing the laws of physics into a single class also makes it easier 
* to mess with the laws of physics later on in the game or simulation or whatever it is you're coding. 
*
* okay so: DON'T BRUTE FORCE YOUR PHYSICS, ORGANIZE IT AND MAKE IT EPIC
* 
*/
class Billy extends MovieClip
{
    
    private var hasFlashed:Boolean = false;
    private var fCounter:int = 0;
    
    public var mass:Number = 5.0;
    public var pw:PhysicalWorld;
    
    private const dwidth:int = 50;
    private const dheight:int = 50;
    
    public var vx:Number = 0.0;
    public var vy:Number = 0.0;
    public var ax:Number = 0.0;
    public var ay:Number = 0.0;
    
    public var isOnGround:Boolean = false;
    
    public function Billy(mss:Number, p:PhysicalWorld)
    {
        mass = mss;
        pw = p;
        
        graphics.lineStyle(2, 0xffffff);
        graphics.beginFill(0x000000);
        graphics.drawRect(0, 0, dwidth, dheight);
        graphics.endFill();
        
        //addEventListener(Event.ENTER_FRAME, flash);
    }
    
    public function flash(e:Event):void
    {
        fCounter++;
        if(fCounter == 10)
        {
            if(hasFlashed)
            {
                graphics.beginFill(0x000000);
                graphics.drawRect(0, 0, dwidth, dheight);
                graphics.endFill();
                hasFlashed = !hasFlashed;
                fCounter = 0;
            }
            else
            {
                graphics.beginFill(0xffffff);
                graphics.drawRect(0, 0, dwidth, dheight);
                graphics.endFill();
                hasFlashed = !hasFlashed;
                fCounter = 0;
            }
        }
    }
} // end class

class PhysicalWorld
{
    
    public var g:Number;
    public var kf:Number;
    public var bounciness:Number;
    
    public function PhysicalWorld(gravity:Number, frictionKonstant:Number, collisionBounciness:Number)
    {
        g = gravity;
        kf = frictionKonstant;
        bounciness = collisionBounciness;
    }
    
    // functions that handle forces (acceleration)
    // you'll probably need one to start the force and another to end the force.
    
    // a function to actually change the speed and calculate the new position.
    
    // if this class is abstract it's basically letting you fuck with the laws of physics
    // and do whatever you want. Inertia? What's that? LET'S INCREASE ACCELERATION WITH EVERY SECOND?
    // (this makes running into the wall really exciting if you're wondering -- the longer you try to run through the wall the 'harder' it pushes you off.).

} // end 

class Particle extends MovieClip
{
    
    public var vx:Number = 0.0;
    public var vy:Number = 0.0;
    public var ax:Number = 0.0;
    public var ay:Number = 0.0;
    
    public var frameLife:int;
    
    public function Particle(width:Number, height:Number, frameLife:int) // frameLife is the number of frames the particle will be 'alive' in
    {
        this.frameLife = frameLife;
        graphics.lineStyle(2, 0xffffff);
        graphics.beginFill(0x000000);
        graphics.drawRect(0, 0, width, height);
        graphics.endFill();
        
        var randScale:Number = 1 + Math.random();
        scaleX *= randScale;
        scaleY *= randScale;
        
        addEventListener(Event.ENTER_FRAME, decaySize);
    }
    
    public function decaySize(e:Event):void
    {
        scaleX -= 0.09;
        scaleY -= 0.09
    }


}