Subversion Repositories AndroidProjects

Rev

Rev 956 | Blame | Compare with Previous | Last modification | View Log | RSS feed

package com.gebauz.burutaru.game.entities;

import com.badlogic.gdx.audio.Sound;
import com.gebauz.bauzoid.graphics.sprite.AtlasSprite;
import com.gebauz.bauzoid.graphics.sprite.AtlasSpriteFrame;
import com.gebauz.bauzoid.graphics.sprite.AtlasSpriteInstance;
import com.gebauz.bauzoid.math.MathUtil;
import com.gebauz.bauzoid.math.Matrix4;
import com.gebauz.bauzoid.math.Vector2;
import com.gebauz.bauzoid.math.collision.AABoundingBox;
import com.gebauz.bauzoid.math.collision.Shape;
import com.gebauz.bauzoid.math.collision.ShapeUtil;
import com.gebauz.burutaru.GameConsts;
import com.gebauz.burutaru.game.GameLogic;

public class PowerUpMissile extends Entity
{

        // Constants========================================================================================
       
        public static final int MISSILE_DAMAGE = 10;
       
        public static final int MAX_MISSILES = 2;
       
        public static final int UPPER_MISSILE = 0;
        public static final int LOWER_MISSILE = 1;
       
        public static final float MISSILE_WIDTH = 40;
        public static final float MISSILE_HEIGHT = MISSILE_WIDTH/2;
       
        public static final float MISSILE_ROTATION_DURATION = 0.5f;
       
        public static final float MISSILE_SPEED = 400.0f;
       
        public static final float LAUNCH_TIME = 0.4f;
        public static final float LAUNCH_SPEED =  100.0f;
       
        public static final int NUM_MISSILE_FRAMES = 4;
        public static final int ROCKET_FIRE_FRAME = 4;
       
        public static final float ROCKET_FIRE_SIZE = 20;
        public static final float ROCKET_FIRE_SIZE_VARIANCE = 10;
        public static final float ROCKET_FIRE_OFFSET = 5;
       
        public static final float MAX_ANGLE = 20.0f;
        public static final float ANGULAR_SPEED = 25.0f;
       
        public static final float HEADING_UPDATE_INTERVAL = 0.125f;

        // Embedded Types===================================================================================
       
        public enum MissilePhase
        {
                PHASE_LAUNCHING,
                PHASE_HOAMING
        }
       
        public class Missile extends Projectile
        {
                public AtlasSpriteInstance spriteInstance = null;
               
                public int type = -1;
                public float lifeTime = 0.0f;
               
                private MissilePhase mPhase;
                private float angle = 0.0f;
                private float mCurrentAngle = 0.0f;
               
                private float mHeadingUpdateTimer = 0.0f;
               
                public Missile(int _type)
                {
                        super(MISSILE_DAMAGE);
                        type = _type;
                       
                        spriteInstance = new AtlasSpriteInstance(getGraphics(), mMissileSprite, mMissileFrames, mMissileShape);
                        setAlive(false);
                }
               
                public void launch(float x, float y)
                {
                        lifeTime = 0.0f;
                        angle = 0.0f;
                        mCurrentAngle = 0.0f;
                        mPhase = MissilePhase.PHASE_LAUNCHING;
                        mHeadingUpdateTimer = 0.0f;
                       
                        spriteInstance.param.x = x;
                        spriteInstance.param.y = y;
                        spriteInstance.param.w = MISSILE_WIDTH;
                        spriteInstance.param.h = MISSILE_HEIGHT;
                        spriteInstance.param.pivotX = spriteInstance.param.w;
                        spriteInstance.param.pivotY = spriteInstance.param.h / 2;
                        spriteInstance.param.angle = 0.0f;
                       
                        setAlive(true);
                }
               
                public void update(float deltaTime)
                {
                        // search nearest enemy and adjust heading towards it
                        lifeTime += deltaTime;
                       
                        switch(mPhase)
                        {
                        case PHASE_LAUNCHING:
                                //float t = MathUtil.clamp((lifeTime / LAUNCH_TIME), 0.0f, 1.0f);
                               
                                if (type == UPPER_MISSILE)
                                {
                                        spriteInstance.param.y -= LAUNCH_SPEED * deltaTime;
                                }
                                else if (type == LOWER_MISSILE)
                                {
                                        spriteInstance.param.y += LAUNCH_SPEED * deltaTime;                                    
                                }
                               
                                if (lifeTime > LAUNCH_TIME)
                                {
                                        mPhase = MissilePhase.PHASE_HOAMING;
                                        mRocketFireSfx.play(0.3f);
                                }                              
                                break;
                        case PHASE_HOAMING:
                                // default target: just ahead
                                Vector2 target = new Vector2(spriteInstance.param.x + 100.0f, spriteInstance.param.y);
                                getGameLogic().getNearestEnemyPosition(spriteInstance.param.x, spriteInstance.param.y, target);

                                Vector2 heading = new Vector2(target.x - spriteInstance.param.x, target.y - spriteInstance.param.y);
                               
                                mHeadingUpdateTimer += deltaTime;
                                if (mHeadingUpdateTimer > HEADING_UPDATE_INTERVAL)
                                {
                                        mHeadingUpdateTimer = 0.0f;
                                        angle = MathUtil.radToDeg((float)Math.atan2(-heading.y, heading.x));
                                }
                               
                                float diff = MathUtil.turnDegrees(angle, mCurrentAngle);
                                if (diff > MAX_ANGLE)
                                        diff = MAX_ANGLE;
                                if (mCurrentAngle > angle)
                                {
                                        mCurrentAngle -= diff * deltaTime * ANGULAR_SPEED;
                                        if (mCurrentAngle < angle)
                                                mCurrentAngle = angle;
                                }
                                else if (mCurrentAngle < angle)
                                {
                                        mCurrentAngle += diff * deltaTime * ANGULAR_SPEED;
                                        if (mCurrentAngle > angle)
                                                mCurrentAngle = angle;
                                }
                               
                                heading.x = (float)Math.cos(Math.toRadians(mCurrentAngle));
                                heading.y = -(float)Math.sin(Math.toRadians(mCurrentAngle));
                                heading.normalize();
                               
                                spriteInstance.param.x += MISSILE_SPEED * deltaTime * heading.x;
                                spriteInstance.param.y += MISSILE_SPEED * deltaTime * heading.y;
                                spriteInstance.param.angle = mCurrentAngle;
                                break;
                        }

                        getGameLogic().checkProjectileHit(this);
                       
                        /*if ((spriteInstance.param.x > (GameConsts.VIRTUAL_SCREEN_WIDTH + MISSILE_WIDTH)) ||
                                (spriteInstance.param.x < (-MISSILE_WIDTH)) ||
                                (spriteInstance.param.y > (GameConsts.VIRTUAL_SCREEN_HEIGHT+ MISSILE_HEIGHT)) ||
                                (spriteInstance.param.y < (-MISSILE_HEIGHT)))*/

                        if (getGameLogic().isOutOfScreen(spriteInstance.param))
                        {
                                // out of screen -> make un alive
                                setAlive(false);
                        }
                }
               
                public void render()
                {
                        float t = (lifeTime % MISSILE_ROTATION_DURATION) / MISSILE_ROTATION_DURATION;
                        int frame = MathUtil.clamp((int)(t * NUM_MISSILE_FRAMES), 0, NUM_MISSILE_FRAMES-1);
                        spriteInstance.renderFrame(frame);

                        float rocketPulse = MathUtil.sin(lifeTime * 2000.0f) * 0.3f;
                       
                        if (mPhase == MissilePhase.PHASE_HOAMING)
                        {
                                mMissileFrames[ROCKET_FIRE_FRAME].param.x = spriteInstance.param.x;
                                mMissileFrames[ROCKET_FIRE_FRAME].param.y = spriteInstance.param.y;
                                mMissileFrames[ROCKET_FIRE_FRAME].param.w = ROCKET_FIRE_SIZE + ROCKET_FIRE_SIZE_VARIANCE * rocketPulse;
                                mMissileFrames[ROCKET_FIRE_FRAME].param.h = ROCKET_FIRE_SIZE;
                                mMissileFrames[ROCKET_FIRE_FRAME].param.pivotX = MISSILE_WIDTH + mMissileFrames[ROCKET_FIRE_FRAME].param.w - ROCKET_FIRE_OFFSET;
                                mMissileFrames[ROCKET_FIRE_FRAME].param.pivotY = mMissileFrames[ROCKET_FIRE_FRAME].param.h/2;
                                mMissileFrames[ROCKET_FIRE_FRAME].param.angle = mCurrentAngle;                 
                                mMissileFrames[ROCKET_FIRE_FRAME].render();
                        }
                }

                @Override
                public void processHit(ICollidable hitObject)
                {
                        // spawn impact effect
                        hitObject.hit(getDamage());
                        setAlive(false);
                }

                @Override
                public Shape getShape()
                {
                        return spriteInstance.getShape();
                }

                @Override
                public Matrix4 getShapeTransform()
                {
                        return spriteInstance.param.getTransform();
                }

                @Override
                public AABoundingBox getBounds()
                {
                        return spriteInstance.param.getBoundingBox();
                }
        }
       

        // Fields===========================================================================================
       
        private Missile mMissiles[] = new Missile[MAX_MISSILES];
       
        private AtlasSprite mMissileSprite = null;
        private AtlasSpriteFrame mMissileFrames[] = null;
       
        private Shape mMissileShape = null;
       
        private Sound mRocketFireSfx = null;

        // Methods==========================================================================================

        public PowerUpMissile(GameLogic gameLogic)
        {
                super(gameLogic);
                mMissileSprite = new AtlasSprite(getGraphics(), "data/textures/missile.png", "data/textures/missile.txt");
        }
       
        @Override
        public void initAsync()
        {
                mMissileSprite.initAsync();
        }

        @Override
        public void init()
        {
                mMissileShape = ShapeUtil.createShapeFromFile("data/textures/missile.shape");
               
                mRocketFireSfx = getAudio().newManagedSound("data/sounds/fire_rocket.wav");
               
                mMissileSprite.init();
                mMissileFrames = mMissileSprite.createSpriteInstances();
               
                for (int i = 0; i < MAX_MISSILES; i++)
                {
                        mMissiles[i] = new Missile(i);
                }
        }

        @Override
        public void exit()
        {
                mMissileFrames = null;
               
                if (mMissileSprite != null)
                {
                        mMissileSprite.dispose();
                        mMissileSprite = null;
                }
               
                if (mRocketFireSfx != null)
                {
                        getAudio().removeManagedSound(mRocketFireSfx);
                        mRocketFireSfx = null;
                }
        }

        @Override
        public void update(float deltaTime)
        {
                int i = 0;
                while (i < MAX_MISSILES)
                {
                        if (mMissiles[i].isAlive())
                                mMissiles[i].update(deltaTime);
                        i++;
                }

        }

        @Override
        public void render()
        {
                int i = 0;
                while (i < MAX_MISSILES)
                {
                        if (mMissiles[i].isAlive())
                                mMissiles[i].render();
                        i++;
                }
        }
       
        public void launch(float x, float y)
        {
                // launch one upper, one lower
               
                for (int i = 0; i < MAX_MISSILES; i++)
                {
                        if (!mMissiles[i].isAlive())
                        {
                                mMissiles[i].launch(x, y);
                        }
                }
        }
       
        // Getters/Setters==================================================================================

}