package com.gebauz.burutaru.game.entities;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.gebauz.bauzoid.graphics.sprite.AtlasSpriteFrame;
import com.gebauz.bauzoid.graphics.sprite.AtlasSprite;
import com.gebauz.bauzoid.graphics.sprite.AtlasSpriteInstance;
import com.gebauz.bauzoid.graphics.sprite.Sprite;
import com.gebauz.bauzoid.math.MathUtil;
import com.gebauz.bauzoid.math.Matrix4;
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 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.2f
;
// Embedded Types===================================================================================
public enum MoveDirection
{
NONE,
UP,
DOWN
}
// Fields===========================================================================================
private float mPositionX =
100;
private float mPositionY =
100;
private float mLastMoveX = 0.0f
;
private float mLastMoveY = 0.0f
;
private AtlasSprite mShipAtlas =
null;
private AtlasSpriteFrame mShipFrames
[] =
new AtlasSpriteFrame
[NUM_SHIP_FRAMES
];
private AtlasSpriteInstance mSpriteInstance =
null;
private Shape mShipShape =
null;
private int mCurrentShipFrame =
0;
private MoveDirection mMoveDirection = MoveDirection.
NONE;
private Sprite mMuzzleFlash =
null;
private float mMuzzleFlashTimer = -1.0f
;
private float mBeamShotTimer = 0.0f
;
private Sprite 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
;
// Methods==========================================================================================
public Ship
(GameLogic gameLogic
)
{
super(gameLogic
);
mShipAtlas =
new AtlasSprite
(getGraphics
(),
"data/textures/shipframes.png",
"data/textures/ship.txt");
mMuzzleFlash =
new Sprite
(getGraphics
(),
"data/textures/plasma_muzzleflash.png");
mEngineExhaust =
new Sprite
(getGraphics
(),
"data/textures/engine_exhaust.png");
}
@
Override
public void initAsync
()
{
mShipAtlas.
initAsync();
mMuzzleFlash.
initAsync();
mEngineExhaust.
initAsync();
}
@
Override
public void init
()
{
mEngineBoostSfx = getAudio
().
newManagedSound("data/sounds/speedup.wav");
mShipAtlas.
init();
mShipAtlas.
getTexture().
setFilter(TextureFilter.
Linear, TextureFilter.
Linear);
mShipAtlas.
createSpriteInstances(mShipFrames
);
mMuzzleFlash.
init();
mMuzzleFlash.
getTexture().
setFilter(TextureFilter.
Linear, TextureFilter.
Linear);
mEngineExhaust.
init();
mEngineExhaust.
getTexture().
setFilter(TextureFilter.
Linear, TextureFilter.
Linear);
mShipShape = ShapeUtil.
createShapeFromFile("data/textures/ship.shape");
mSpriteInstance =
new AtlasSpriteInstance
(getGraphics
(), mShipAtlas, mShipFrames, mShipShape
);
}
@
Override
public void exit
()
{
mShipShape =
null;
mSpriteInstance =
null;
for (int i =
0; i
< NUM_SHIP_FRAMES
; i++
)
{
mShipFrames
[i
] =
null;
}
if (mShipAtlas
!=
null)
{
mShipAtlas.
dispose();
mShipAtlas =
null;
}
if (mMuzzleFlash
!=
null)
{
mMuzzleFlash.
dispose();
mMuzzleFlash =
null;
}
if (mEngineExhaust
!=
null)
{
mEngineExhaust.
dispose();
mEngineExhaust =
null;
}
if (mEngineBoostSfx
!=
null)
{
getAudio
().
removeManagedSound(mEngineBoostSfx
);
mEngineBoostSfx =
null;
}
}
@
Override
public void update
(float 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);
if (mLastMoveX
> 0.0f
)
{
// grow
float diff = EXHAUST_BOOST_MAX - mEngineExhaustBoost
;
mEngineExhaustBoost += diff
* deltaTime
* EXHAUST_BOOST_FACTOR
;
}
else if (mLastMoveX
< 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
;
}
@
Override
public void render
()
{
if (mEngineBoostTimer
> 0.0f
)
{
mMuzzleFlash.
param.
x = mPositionX
;
mMuzzleFlash.
param.
y = mPositionY -
1;
mMuzzleFlash.
param.
w = MUZZLEFLASH_SIZE
* (1 + mEngineBoostTimer / ENGINE_BOOST_DURATION
);
mMuzzleFlash.
param.
h = MUZZLEFLASH_SIZE
* (1 + 0.5f
*mEngineBoostTimer / ENGINE_BOOST_DURATION
);
mMuzzleFlash.
param.
pivotX = mMuzzleFlash.
param.
w;
mMuzzleFlash.
param.
pivotY = mMuzzleFlash.
param.
h/
2;
mMuzzleFlash.
param.
mirrorX =
true;
mMuzzleFlash.
param.
alpha =
(mEngineBoostTimer / ENGINE_BOOST_DURATION
);
mMuzzleFlash.
render();
}
mEngineExhaust.
param.
x = mPositionX - EXHAUST_WIDTH/
2;
mEngineExhaust.
param.
y = mPositionY -
1;
mEngineExhaust.
param.
w = EXHAUST_WIDTH
* mEngineExhaustScale
;
mEngineExhaust.
param.
h = EXHAUST_HEIGHT
;
mEngineExhaust.
param.
pivotX = mEngineExhaust.
param.
w;
mEngineExhaust.
param.
pivotY = mEngineExhaust.
param.
h/
2;
mEngineExhaust.
render();
mSpriteInstance.
param.
x = mPositionX
;
mSpriteInstance.
param.
y = mPositionY
;
mSpriteInstance.
param.
w = SHIP_WIDTH
;
mSpriteInstance.
param.
h = SHIP_HEIGHT
;
mSpriteInstance.
param.
centerPivot();
mSpriteInstance.
renderFrame(mCurrentShipFrame
);
/*mShipFrames[mCurrentShipFrame].param.x = mPositionX;
mShipFrames[mCurrentShipFrame].param.y = mPositionY;
mShipFrames[mCurrentShipFrame].param.w = SHIP_WIDTH;
mShipFrames[mCurrentShipFrame].param.h = SHIP_HEIGHT;
mShipFrames[mCurrentShipFrame].centerPivot();
mShipFrames[mCurrentShipFrame].render();*/
if (mMuzzleFlashTimer
> 0.0f
)
{
mMuzzleFlash.
param.
x = mPositionX + SHIP_WIDTH/
2;
mMuzzleFlash.
param.
y = mPositionY
;
mMuzzleFlash.
param.
w = MUZZLEFLASH_SIZE
;
mMuzzleFlash.
param.
h = MUZZLEFLASH_SIZE
;
mMuzzleFlash.
param.
pivotX = mMuzzleFlash.
param.
w/
3 + 1.0f
;
mMuzzleFlash.
param.
pivotY = mMuzzleFlash.
param.
h/
2;
mMuzzleFlash.
param.
mirrorX =
false;
mMuzzleFlash.
param.
alpha = mMuzzleFlashTimer/MUZZLEFLASH_DURATION
;
mMuzzleFlash.
render();
}
}
public void moveBy
(float x,
float y,
float deltaTime
)
{
mPositionX += x
*deltaTime
;
mPositionY += y
*deltaTime
;
// TODO: scale with amount of y
if (y
< -UPDOWN_THRESHOLD
)
{
mMoveDirection = MoveDirection.
UP;
//mMoveDirectionCoeffTarget = -1.0f;
mMoveDirectionCoeffTarget =
(y + UPDOWN_THRESHOLD
) * 0.01f
;
}
else if (y
> UPDOWN_THRESHOLD
)
{
mMoveDirection = MoveDirection.
DOWN;
mMoveDirectionCoeffTarget =
(y - UPDOWN_THRESHOLD
) * 0.01f
;
}
else
{
mMoveDirection = MoveDirection.
NONE;
mMoveDirectionCoeffTarget = 0.0f
;
}
mPositionX = MathUtil.
clamp(mPositionX, 0.0f, GameConsts.
VIRTUAL_SCREEN_WIDTH);
mPositionY = MathUtil.
clamp(mPositionY, 0.0f, GameConsts.
VIRTUAL_SCREEN_HEIGHT);
mLastMoveX = x
* deltaTime
;
mLastMoveY = y
* deltaTime
;
}
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(mPositionX + SHIP_WIDTH/
2, mPositionY
);
mMuzzleFlashTimer = MUZZLEFLASH_DURATION
;
}
public void shootMissile
()
{
if (getGameLogic
().
getShipParameters().
areMissilesEnabled())
getGameLogic
().
getPowerUpMissile().
launch(mPositionX + SHIP_WIDTH/
3, mPositionY
);
}
public void shootBomb
()
{
if (getGameLogic
().
getShipParameters().
areBombsEnabled())
getGameLogic
().
getPowerUpBomb().
launch(mPositionX + SHIP_WIDTH/
3, mPositionY
);
}
public void shootBeamShot
()
{
if (mBeamShotTimer
<= 0.0f
)
{
getGameLogic
().
getBeamShots().
spawnShot(mPositionX + SHIP_WIDTH/
2, mPositionY
);
mBeamShotTimer = BEAMSHOT_COOLDOWN_TIME
;
}
}
public void boostEngine
()
{
// boost for speed up powerup
mEngineBoostTimer = ENGINE_BOOST_DURATION
;
mEngineBoostSfx.
play();
}
public void processHit
(ICollidable collidable
)
{
if (mDamageCoolDown
<= 0.0f
)
{
getGameLogic
().
getExplosions().
spawn(mPositionX, mPositionY,
100);
mDamageCoolDown = DAMAGE_COOLDOWN_TIME
;
}
}
// Getters/Setters==================================================================================
public float getPositionX
() { return mPositionX
; }
public float getPositionY
() { return mPositionY
; }
public AABoundingBox getBounds
() { return mSpriteInstance.
param.
getBoundingBox(); }
/** Get the shape of the projectile for testing. */
public Shape getShape
() { return mShipShape
; }
/** Get the transformation of the shape for testing. */
public Matrix4 getShapeTransform
() { return mSpriteInstance.
param.
getTransform(); }
}