package com.gebauz.burutaru.game.entities;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Sound;
import com.gebauz.bauzoid.graphics.sprite.AtlasSprite;
import com.gebauz.bauzoid.graphics.sprite.AtlasSpriteFrame;
import com.gebauz.bauzoid.math.MathUtil;
import com.gebauz.bauzoid.math.Vector2;
import com.gebauz.burutaru.GameConsts;
import com.gebauz.burutaru.game.GameLogic;
public class PowerUpMissile
extends Entity
{
// Constants========================================================================================
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
{
public float x =
0;
public float y =
0;
public int type = -
1;
public boolean isAlive =
false;
public float lifeTime = 0.0f
;
public float angle = 0.0f
;
private MissilePhase mPhase
;
private float mCurrentAngle = 0.0f
;
private float mHeadingUpdateTimer = 0.0f
;
public Missile
(int _type
)
{
type = _type
;
}
public void launch
(float _x,
float _y
)
{
isAlive =
true;
x = _x
; y = _y
;
lifeTime = 0.0f
;
angle = 0.0f
;
mCurrentAngle = 0.0f
;
mPhase = MissilePhase.
PHASE_LAUNCHING;
mHeadingUpdateTimer = 0.0f
;
}
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
)
{
y -= LAUNCH_SPEED
* deltaTime
;
}
else if (type == LOWER_MISSILE
)
{
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
(x + 100.0f, y
);
getGameLogic
().
getNearestEnemyPosition(x, y, target
);
Vector2 heading =
new Vector2
(target.
x - x, target.
y - y
);
// TODO: best find target in field of view of rocket
mHeadingUpdateTimer += deltaTime
;
if (mHeadingUpdateTimer
> HEADING_UPDATE_INTERVAL
)
{
mHeadingUpdateTimer = 0.0f
;
//heading.normalize();
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
;
}
// angle = 315;
// currentAngle = angle;
heading.
x =
(float)Math.
cos(Math.
toRadians(mCurrentAngle
));
heading.
y = -
(float)Math.
sin(Math.
toRadians(mCurrentAngle
));
heading.
normalize();
x += MISSILE_SPEED
* deltaTime
* heading.
x;
y += MISSILE_SPEED
* deltaTime
* heading.
y;
/* // get heading
Vector2 heading = new Vector2(target.x - x, target.y - y);
heading.normalize();
angle = MathUtil.radToDeg((float)Math.atan2(-heading.y, heading.x));
float diff = MathUtil.turnDegrees(angle, currentAngle);
if (diff > MAX_ANGLE)
{
if (angle < currentAngle)
angle -= MAX_ANGLE;
else
angle += MAX_ANGLE;
heading.x = (float)Math.sin(Math.toRadians(angle));
heading.y = (float)Math.cos(Math.toRadians(angle));
heading.normalize();
}
x += MISSILE_SPEED * deltaTime * heading.x;
y += MISSILE_SPEED * deltaTime * heading.y;*/
break;
}
/*float angleDiff = angle - currentAngle;
currentAngle = angleDiff * deltaTime * 11;
currentAngle = angle;*/
if (getGameLogic
().
checkForHit(x, y,
3,
3))
{
isAlive =
false;
}
if ((x
> (GameConsts.
VIRTUAL_SCREEN_WIDTH + MISSILE_WIDTH
)) ||
(x
< (-MISSILE_WIDTH
)) ||
(y
> (GameConsts.
VIRTUAL_SCREEN_HEIGHT+ MISSILE_HEIGHT
)) ||
(y
< (-MISSILE_HEIGHT
)))
{
// out of screen -> make un alive
isAlive =
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);
mMissileFrames
[frame
].
param.
x = x
;
mMissileFrames
[frame
].
param.
y = y
;
mMissileFrames
[frame
].
param.
w = MISSILE_WIDTH
;
mMissileFrames
[frame
].
param.
h = MISSILE_HEIGHT
;
mMissileFrames
[frame
].
param.
pivotX = mMissileFrames
[frame
].
param.
w;
mMissileFrames
[frame
].
param.
pivotY = mMissileFrames
[frame
].
param.
h /
2;
mMissileFrames
[frame
].
param.
angle = mCurrentAngle
;
mMissileFrames
[frame
].
render();
float rocketPulse = MathUtil.
sin(lifeTime
* 2000.0f
) * 0.3f
;
if (mPhase == MissilePhase.
PHASE_HOAMING)
{
mMissileFrames
[ROCKET_FIRE_FRAME
].
param.
x = x
;
mMissileFrames
[ROCKET_FIRE_FRAME
].
param.
y = 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();
}
}
}
// Fields===========================================================================================
private Missile mMissiles
[] =
new Missile
[MAX_MISSILES
];
private AtlasSprite mMissileSprite =
null;
private AtlasSpriteFrame mMissileFrames
[] =
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
()
{
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==================================================================================
}