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==================================================================================
}