Subversion Repositories AndroidProjects

Rev

Rev 1508 | Rev 1560 | Go to most recent revision | 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.SimpleSprite;
import com.gebauz.bauzoid.graphics.sprite.Sprite;
import com.gebauz.bauzoid.graphics.sprite.SpriteInstance;
import com.gebauz.bauzoid.math.MathUtil;
import com.gebauz.bauzoid.math.Vector2;
import com.gebauz.bauzoid.math.collision.Shape;
import com.gebauz.burutaru.GameConsts;
import com.gebauz.burutaru.game.GameLogic;
import com.gebauz.burutaru.game.entities.CollisionWorld.CollisionInfo;

public class Ship extends Entity
{

        // Constants========================================================================================

        public static final int SHIP_WIDTH = 64;
        public static final int SHIP_HEIGHT = 64;
       
        // HACK: for powerup pickup
        public static final float SHIP_RADIUS_SQR = SHIP_WIDTH*SHIP_WIDTH * 0.5f;
       
        public static final int NUM_UP_FRAMES = 5;
        public static final int NUM_DOWN_FRAMES = 5;
        public static final int NUM_SHIP_FRAMES = 1 + NUM_UP_FRAMES + NUM_DOWN_FRAMES;
        public static final int SHIP_SPRITE_SIZE = 128;
        public static final int NUM_SHIP_FRAMES_X = 4;
        public static final int NUM_SHIP_FRAMES_Y = 4;
        public static final float UPDOWN_ANIM_SPEED = 4.0f;
        public static final float UPDOWN_THRESHOLD = 20.0f;
       
        public static final float MUZZLEFLASH_DURATION = 0.15f;
        public static final float MUZZLEFLASH_SIZE = 40.0f;
       
        public static final float EXHAUST_WIDTH = 28;
        public static final float EXHAUST_HEIGHT = 16;
       
        public static final float EXHAUST_BOOST_MAX = 0.3f;
        public static final float EXHAUST_BOOST_MIN = -0.1f;
        public static final float EXHAUST_BOOST_FACTOR = 11.0f;
        public static final float EXHAUST_ANIM_SPEED = 4000.0f;
       
       
        public static final float ENGINE_BOOST_DURATION = 0.5f;
       
        public static final float BEAMSHOT_COOLDOWN_TIME = 0.2f;
       
        public static final float DAMAGE_COOLDOWN_TIME = 0.5f;
        public static final float DAMAGE_DISPLACE = 3.0f;
       
        public static final int COLLISION_DAMAGE = 2;
       
        public static final float START_POSITION_X = 300;
        public static final float START_POSITION_Y = 300;
       
        // Embedded Types===================================================================================

        public enum MoveDirection
        {
                NONE,
                UP,
                DOWN
        }      
       
        // Fields===========================================================================================
       
        private SpriteInstance mShipInstance = null;
       
       
        //private float mPositionX = 100;
        //private float mPositionY = 100;
       
        /*private float mLastMoveX = 0.0f;
        private float mLastMoveY = 0.0f;*/

       
        private Vector2 mLastMove = new Vector2();
       
        private Shape mShipShape = null;
       
        private int mCurrentShipFrame = 0;
        private MoveDirection mMoveDirection = MoveDirection.NONE;     
       
        private Sprite mMuzzleFlash = null;
        private SpriteInstance mMuzzleFlashInstance = null;
        private SpriteInstance mEngineBoostInstance = null;
        private float mMuzzleFlashTimer = -1.0f;
       
        private float mBeamShotTimer = 0.0f;
       
        private SimpleSprite mEngineExhaust = null;
        private float mEngineExhaustScale = 1.0f;
        private float mEngineExhaustBoost = 0.0f;
       
        private float mMoveDirectionCoeff = 0.0f;
        private float mMoveDirectionCoeffTarget = 0.0f;
       
        private float mEngineBoostTimer = 0.0f;
       
        private Sound mEngineBoostSfx = null;
       
        private float mDamageCoolDown = 0.0f;
        private float mDamageTimer = 0.0f;
       
        private CollisionInfo mCollisionResult = new CollisionInfo();

       
        private float mTargetAngle = 0;
        private float mCurrentAngle = 0;
       
        // Methods==========================================================================================

        public Ship(GameLogic gameLogic)
        {
                super(gameLogic);
               
                mShipInstance = new SpriteInstance(new Sprite(getGraphics(), "data/textures/shipframes.png", "data/textures/ship.txt"));
                mEngineExhaust = new SimpleSprite(getGraphics(), "data/textures/engine_exhaust.png");
                mMuzzleFlash = new Sprite(getGraphics(), "data/textures/plasma_muzzleflash.png");
               
                mShipShape = new Shape(getGame(), "data/textures/ship.shape");
        }
       
        @Override
        public void initAsync()
        {
                mShipInstance.initAsync();
                mEngineExhaust.initAsync();
                mMuzzleFlash.initAsync();
               
                //getGameLogic().getAssetManager().load("data/textures/ship.shape", Shape.class);
                mShipShape.initAsync();
        }

        @Override
        public void init()
        {
                mShipInstance.init();
                mEngineExhaust.init();
                mMuzzleFlash.init();
               
                //mShipShape = getGameLogic().getAssetManager().get("data/textures/ship.shape", Shape.class);
                mShipShape.init();
               
                mMuzzleFlashInstance = mMuzzleFlash.createSpriteInstance(0);
                mEngineBoostInstance = mMuzzleFlash.createSpriteInstance(0);
               
                mShipInstance.transform.x = START_POSITION_X;
                mShipInstance.transform.y = START_POSITION_Y;
                mShipInstance.transform.w = SHIP_WIDTH;
                mShipInstance.transform.h = SHIP_HEIGHT;
                mShipInstance.transform.angle = mCurrentAngle;
                mShipInstance.centerPivot();                   
               
                getGameLogic().getCollisionWorld().addShipCollider(this, mShipShape);
               
                mEngineBoostSfx = getAudio().newManagedSound("data/sounds/speedup.wav");
        }

        @Override
        public void exit()
        {
                if (mShipInstance != null)
                {
                        mShipInstance.dispose(true);
                        mShipInstance = null;
                }
               
                if (mEngineExhaust != null)
                {
                        mEngineExhaust.dispose();
                        mEngineExhaust = null;
                        mMuzzleFlashInstance = null;
                        mEngineBoostInstance = null;
                }
               
                if (mMuzzleFlash != null)
                {
                        mMuzzleFlash.dispose();
                        mMuzzleFlash = null;
                }
               
                if (mEngineBoostSfx != null)
                {
                        getAudio().removeManagedSound(mEngineBoostSfx);
                        mEngineBoostSfx = null;
                }
               
                mShipShape = null;
        }

        @Override
        public void update(float deltaTime)
        {
                //angle += 30*deltaTime;
                //setAngle(getAngle() + 10*deltaTime);
               
                if (mMoveDirection == MoveDirection.UP)
                {
                        // move towards -1
                        mMoveDirectionCoeff -= deltaTime * UPDOWN_ANIM_SPEED;
                        if (mMoveDirectionCoeff < mMoveDirectionCoeffTarget)
                                mMoveDirectionCoeff = mMoveDirectionCoeffTarget;
                }
                else if (mMoveDirection == MoveDirection.DOWN)
                {
                        // move towards +1
                        mMoveDirectionCoeff += deltaTime * UPDOWN_ANIM_SPEED;
                        if (mMoveDirectionCoeff > mMoveDirectionCoeffTarget)
                                mMoveDirectionCoeff = mMoveDirectionCoeffTarget;
                }
                else if (mMoveDirection == MoveDirection.NONE)
                {
                        // move towards 0
                        if (mMoveDirectionCoeff > 0)
                                mMoveDirectionCoeff = MathUtil.clamp(mMoveDirectionCoeff - deltaTime * UPDOWN_ANIM_SPEED, 0, 1);                               
                        else if (mMoveDirectionCoeff < 0)
                                mMoveDirectionCoeff = MathUtil.clamp(mMoveDirectionCoeff + deltaTime * UPDOWN_ANIM_SPEED, -1, 0);
                }
               
                mMoveDirectionCoeff = MathUtil.clamp(mMoveDirectionCoeff, -1, 1);
               
                if (mMoveDirectionCoeff > 0)
                {
                        mCurrentShipFrame = (int)(1 + (NUM_DOWN_FRAMES-1) * (mMoveDirectionCoeff));
                }
                else if (mMoveDirectionCoeff < 0)
                {
                        mCurrentShipFrame = (int)(1 + NUM_DOWN_FRAMES  + (NUM_UP_FRAMES-1) * (-mMoveDirectionCoeff));                  
                }
                else
                {
                        mCurrentShipFrame = 0;
                }
               
                //Gdx.app.log(GameConsts.LOG_TAG, "coeff = " + mMoveDirectionCoeff + ", frame = " + mCurrentShipFrame + ", dir = " + mMoveDirection);
               
                mCurrentShipFrame = MathUtil.clamp(mCurrentShipFrame, 0, NUM_SHIP_FRAMES-1);
                mShipInstance.setCurrentFrame(mCurrentShipFrame);
               
                if (mLastMove.x > 0.0f)
                {
                        // grow
                        float diff = EXHAUST_BOOST_MAX - mEngineExhaustBoost;
                        mEngineExhaustBoost += diff * deltaTime * EXHAUST_BOOST_FACTOR;
                }
                else if (mLastMove.x < 0.0f)
                {
                        float diff = EXHAUST_BOOST_MIN - mEngineExhaustBoost;
                        mEngineExhaustBoost += diff * deltaTime * EXHAUST_BOOST_FACTOR;
                }
                else
                {
                        float diff = 0.0f - mEngineExhaustBoost;
                        mEngineExhaustBoost += diff * deltaTime * EXHAUST_BOOST_FACTOR;
                }
                mEngineExhaustScale = 0.9f + MathUtil.sin(getGame().getTime() * EXHAUST_ANIM_SPEED) * 0.05f + mEngineExhaustBoost;
               
                if (mEngineBoostTimer > 0.0f)
                {
                        mEngineBoostTimer -= deltaTime;
                        if (mEngineBoostTimer < 0.0f)
                                mEngineBoostTimer = 0.0f;
                }
               
                mEngineExhaustScale += ((mEngineBoostTimer / ENGINE_BOOST_DURATION) * 1.8f);
               

                if (mMuzzleFlashTimer > 0.0f)
                        mMuzzleFlashTimer -= deltaTime;
               
                if (mBeamShotTimer > 0.0f)
                        mBeamShotTimer -= deltaTime;
               
                if (mDamageCoolDown > 0.0f)
                        mDamageCoolDown -= deltaTime;  
               
                mDamageTimer += deltaTime;
        }
       
       
        Vector2 contactPoint = null;

        @Override
        public void render()
        {
                float shipDisplaceX = 0.0f;
                float shipDisplaceY = 0.0f;
                if (mDamageCoolDown > 0.0f)
                {                      
                        mShipInstance.fogColor.set(1, 1, 1, getGameLogic().getGame().getRandomFloat(0.25f, 0.95f));
                        shipDisplaceX = getGameLogic().getGame().getRandomFloat(-DAMAGE_DISPLACE, DAMAGE_DISPLACE);
                        shipDisplaceY = getGameLogic().getGame().getRandomFloat(-DAMAGE_DISPLACE, DAMAGE_DISPLACE);
                }
                else
                {
                        mShipInstance.fogColor.set(1, 1, 1, 0.0f);                     
                }
               
                mShipInstance.transform.x += shipDisplaceX;
                mShipInstance.transform.y += shipDisplaceY;
               
                // render engine boost
                if (mEngineBoostTimer > 0.0f)
                {
                        mEngineBoostInstance.transform.x = mShipInstance.transform.x;
                        mEngineBoostInstance.transform.y = mShipInstance.transform.y - 1;
                        mEngineBoostInstance.transform.w = MUZZLEFLASH_SIZE * (1 + mEngineBoostTimer / ENGINE_BOOST_DURATION);
                        mEngineBoostInstance.transform.h = MUZZLEFLASH_SIZE * (1 + 0.5f*mEngineBoostTimer / ENGINE_BOOST_DURATION);
                        mEngineBoostInstance.transform.pivotX = mEngineBoostInstance.transform.w;
                        mEngineBoostInstance.transform.pivotY = mEngineBoostInstance.transform.h/2;
                        mEngineBoostInstance.transform.mirrorX = true;
                        mEngineBoostInstance.alpha = (mEngineBoostTimer / ENGINE_BOOST_DURATION);
                        mEngineBoostInstance.render();
                }
               
                // render engine exhaust
                mEngineExhaust.getSpriteTransform().x = mShipInstance.transform.x - EXHAUST_WIDTH/2;
                mEngineExhaust.getSpriteTransform().y = mShipInstance.transform.y - 2;
                mEngineExhaust.getSpriteTransform().w = EXHAUST_WIDTH * mEngineExhaustScale;
                mEngineExhaust.getSpriteTransform().h = EXHAUST_HEIGHT;
                mEngineExhaust.getSpriteTransform().pivotX = mEngineExhaust.getSpriteTransform().w;
                mEngineExhaust.getSpriteTransform().pivotY = mEngineExhaust.getSpriteTransform().h/2;
                mEngineExhaust.render();
               
                // render ship
                mShipInstance.render();
               
                // render muzzle flash
                if (mMuzzleFlashTimer > 0.0f)
                {
                        mMuzzleFlashInstance.transform.x = mShipInstance.transform.x + SHIP_WIDTH/2;
                        mMuzzleFlashInstance.transform.y = mShipInstance.transform.y;
                        mMuzzleFlashInstance.transform.w = MUZZLEFLASH_SIZE;
                        mMuzzleFlashInstance.transform.h = MUZZLEFLASH_SIZE;
                        mMuzzleFlashInstance.transform.pivotX = mMuzzleFlashInstance.transform.w/3 + 1.0f;
                        mMuzzleFlashInstance.transform.pivotY = mMuzzleFlashInstance.transform.h/2;
                        mMuzzleFlashInstance.transform.mirrorX = false;
                        mMuzzleFlashInstance.alpha = mMuzzleFlashTimer/MUZZLEFLASH_DURATION;
                        mMuzzleFlashInstance.render();
                }
               
                // reset
                mShipInstance.transform.x -= shipDisplaceX;
                mShipInstance.transform.y -= shipDisplaceY;

                /*
                mShipCollider.renderDebug(getGraphics());
               
                if (contactPoint != null)
                        RenderUtil.drawEllipse(getGraphics(), contactPoint.x-2, contactPoint.y-2, contactPoint.x+2, contactPoint.y+2, new Vector4(1, 0.5f, 0.5f, 1));*/

        }
       
        public void moveBy(float dx, float dy, float deltaTime)
        {
                float forwardX = dx * getForwardDirectionX();
                float forwardY = dx * getForwardDirectionY();
               
                float downX = dy * getUpDirectionX();
                float downY = dy * getUpDirectionY();
               
                float x = (forwardX + downX);
                float y = (forwardY + downY);
               
                mLastMove.x = x * deltaTime;
                mLastMove.y = y * deltaTime;
               
                // add movement due to rotation
               
                /*float rx = (mShipInstance.transform.x - GameConsts.VIRTUAL_SCREEN_WIDTH/2);
                float ry = (mShipInstance.transform.y - GameConsts.VIRTUAL_SCREEN_HEIGHT/2);
               
                float radius = (float)Math.sqrt(rx*rx+ry*ry);
               
                float tx = MathUtil.cos(mTargetAngle) * radius + GameConsts.VIRTUAL_SCREEN_WIDTH/2;
                float ty = -MathUtil.sin(mTargetAngle) * radius + GameConsts.VIRTUAL_SCREEN_HEIGHT/2;*/

               
                /*mLastMove.x += (tx - mShipInstance.transform.x);
                mLastMove.x += (ty - mShipInstance.transform.y);*/

               
                mShipShape.transform.set(mShipInstance.transform);
               
                //CollisionInfo result = getGameLogic().getCollisionWorld().collideWithResponsePassiveColliders(CollisionWorld.FILTER_LEVEL_ELEMENTS, mShipShape, new Vector2(mLastMoveX, mLastMoveY));

                //if (result.isColliding)
                if (getGameLogic().getCollisionWorld().checkCollisionSat(CollisionWorld.FILTER_LEVEL_ELEMENTS, mShipShape, mLastMove, mCollisionResult))
                {
                        mLastMove.x += mCollisionResult.penetrationVector.x;
                        mLastMove.y += mCollisionResult.penetrationVector.y;
                       
                        contactPoint = mCollisionResult.contactPoint;
                       
                        damage(COLLISION_DAMAGE);
                }
                else
                        contactPoint = null;

                //result.reset();

                //result = getGameLogic().getCollisionWorld().collideWithResponsePassiveColliders(CollisionWorld.FILTER_ENEMIES, mShipShape, new Vector2(mLastMoveX, mLastMoveY));
               
                //if (result.isColliding)
                if (getGameLogic().getCollisionWorld().checkCollisionSat(CollisionWorld.FILTER_ENEMIES, mShipShape, mLastMove, mCollisionResult))
                {
                        mLastMove.x += mCollisionResult.penetrationVector.x/2;
                        mLastMove.y += mCollisionResult.penetrationVector.y/2;
                       
                        mCollisionResult.collidingEnemyInstance.addImpulse(-mCollisionResult.penetrationVector.x/2, -mCollisionResult.penetrationVector.y/2);
                       
                        mCollisionResult.collidingEnemyInstance.damage(COLLISION_DAMAGE);
                        damage(COLLISION_DAMAGE);
                }

                mShipInstance.transform.x = MathUtil.clamp(mShipInstance.transform.x + mLastMove.x, 0.0f, GameConsts.VIRTUAL_SCREEN_WIDTH);
                mShipInstance.transform.y = MathUtil.clamp(mShipInstance.transform.y + mLastMove.y, 0.0f, GameConsts.VIRTUAL_SCREEN_HEIGHT);
               
                if (mTargetAngle != mCurrentAngle)
                {
                        /*float rx = (mShipInstance.transform.x - GameConsts.VIRTUAL_SCREEN_WIDTH/2);
                        float ry = (mShipInstance.transform.y - GameConsts.VIRTUAL_SCREEN_HEIGHT/2);
               
                        float radius = (float)Math.sqrt(rx*rx+ry*ry);
                       
                        float tx = MathUtil.cos(mTargetAngle) * radius;
                        float ty = -MathUtil.sin(mTargetAngle) * radius;
                       
                        float tx2 = MathUtil.cos(mCurrentAngle) * radius;
                        float ty2 = -MathUtil.sin(mCurrentAngle) * radius;              */
     
                       
                       
                        /*mShipInstance.transform.x += (tx2-tx);
                        mShipInstance.transform.y += (ty2-ty);*/

                        mCurrentAngle = mTargetAngle;
                        mShipInstance.transform.angle = mCurrentAngle;
                }
               
                // TODO: scale with amount of y
                if (dy < -UPDOWN_THRESHOLD)
                {
                        mMoveDirection = MoveDirection.UP;
                        //mMoveDirectionCoeffTarget = -1.0f;
                        mMoveDirectionCoeffTarget = (dy + UPDOWN_THRESHOLD) * 0.01f;
                }
                else if (dy > UPDOWN_THRESHOLD)
                {
                        mMoveDirection = MoveDirection.DOWN;
                        mMoveDirectionCoeffTarget = (dy - UPDOWN_THRESHOLD) * 0.01f;
                }
                else
                {
                        mMoveDirection = MoveDirection.NONE;
                        mMoveDirectionCoeffTarget = 0.0f;
                }
        }
       
        public void damage(int dmg)
        {
                if (mDamageCoolDown > 0.0f)
                        return;
               
                mDamageCoolDown = DAMAGE_COOLDOWN_TIME;
                getGameLogic().getShipParameters().damage(dmg);
        }
       
        public void resetNoUpDownMovement()
        {
                mMoveDirection = MoveDirection.NONE;
                mMoveDirectionCoeffTarget = 0.0f;
        }
       
        public void shoot()
        {
                switch (getGameLogic().getShipParameters().getWeaponType())
                {
                case PLASMA_SHOT:
                        shootPlasma();
                        break;
                case BEAM_SHOT:
                        shootBeamShot();
                        break;
                case SPREAD_SHOT:
                        break;
                case NAPALM_SHOT:
                        break;
                }
                shootMissile();
                shootBomb();           
        }
       
        public void shootPlasma()
        {
                getGameLogic().getPlasmaShots().spawnShot(mShipInstance.transform.x + SHIP_WIDTH/4, mShipInstance.transform.y);
                mMuzzleFlashTimer = MUZZLEFLASH_DURATION;
        }
       
        public void shootMissile()
        {
                if (getGameLogic().getShipParameters().areMissilesEnabled())
                        getGameLogic().getMissiles().launch(mShipInstance.transform.x + SHIP_WIDTH/3, mShipInstance.transform.y);
        }
       
        public void shootBomb()
        {
                if (getGameLogic().getShipParameters().areBombsEnabled())
                        getGameLogic().getBombs().launch(mShipInstance.transform.x + SHIP_WIDTH/3, mShipInstance.transform.y);
        }
       
        public void shootBeamShot()
        {
                if (mBeamShotTimer <= 0.0f)
                {
                        getGameLogic().getBeamShots().spawnShot(mShipInstance.transform.x + SHIP_WIDTH/2, mShipInstance.transform.y);
                        mBeamShotTimer = BEAMSHOT_COOLDOWN_TIME;
                }
        }
       
        public void boostEngine()
        {
                // boost for speed up powerup
                mEngineBoostTimer = ENGINE_BOOST_DURATION;
                mEngineBoostSfx.play();
        }

        // Getters/Setters==================================================================================
       
        public void setAngle(float a)
        {
                mTargetAngle = a;
        }
       
        public float getAngle()
        {
                return mTargetAngle;
        }
       
        public float getPositionX() { return mShipInstance.transform.x; }
        public float getPositionY() { return mShipInstance.transform.y; }
       
        public float getForwardDirectionX()
        {
                return MathUtil.cos(mCurrentAngle);
        }
       
        public float getForwardDirectionY()
        {
                return -MathUtil.sin(mCurrentAngle);
        }
       
        public float getUpDirectionX()
        {
                return MathUtil.sin(mCurrentAngle);
        }
       
        public float getUpDirectionY()
        {
                return MathUtil.cos(mCurrentAngle);
        }

}