package com.gebauz.pingk.entities;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Texture;
import com.gebauz.Bauzoid.graphics.sprite.Sprite;
import com.gebauz.Bauzoid.math.MathUtil;
import com.gebauz.Bauzoid.math.Vector2;
import com.gebauz.pingk.game.GameConsts;
import com.gebauz.pingk.game.GameLogic;
public class Ball
extends Entity
{
static public final int DIRECTION_LEFT =
0;
static public final int DIRECTION_RIGHT =
1;
private Sprite mBallSprite =
null;
// movement parameters
private float mRotation = 0.0f
;
private float mSpeed = GameConsts.
BALL_INITIAL_SPEED;
private float mSpeedUpTimer = 0.0f
;
private float mAngularVelocity = 0.0f
;
private Vector2 mLastPosition =
new Vector2
();
private int mLastPaddleTouched = -
1;
private Sound mWallImpact =
null;
public Ball
(GameLogic gameLogic
)
{
super(gameLogic
);
}
@
Override
public void init
()
{
mBallSprite =
new Sprite
(getGameLogic
().
getGraphics(),
new Texture
(Gdx.
files.
internal("data/textures/ball.png")));
mBallSprite.
x = GameConsts.
VIRTUAL_SCREEN_WIDTH/2.0f
;
mBallSprite.
y = getGameLogic
().
getPlayField().
getVirtualHeight()/2.0f
;
mBallSprite.
w = GameConsts.
BALL_SIZE;
mBallSprite.
h = GameConsts.
BALL_SIZE;
mBallSprite.
centerPivot();
mBallSprite.
color = GameConsts.
PINGK_COLOR;
//mWallImpact = Gdx.audio.newSound(Gdx.files.internal("data/sounds/wallimpact.wav"));
mWallImpact = getAudio
().
newManagedSound("data/sounds/wallimpact.wav");
reset
(DIRECTION_LEFT
);
}
@
Override
public void exit
()
{
if (mBallSprite
!=
null)
{
mBallSprite.
dispose();
mBallSprite =
null;
}
getAudio
().
removeManagedSound(mWallImpact
);
mWallImpact =
null;
}
/** Reset the ball for a new game round. */
public void reset
(int direction
)
{
mSpeed = GameConsts.
BALL_INITIAL_SPEED;
mSpeedUpTimer = 0.0f
;
mAngularVelocity = 0.0f
;
mLastPaddleTouched = -
1;
if (direction == DIRECTION_LEFT
)
{
mRotation = 270.0f
;
}
else if (direction == DIRECTION_RIGHT
)
{
mRotation = 90.0f
;
}
mBallSprite.
x = GameConsts.
VIRTUAL_SCREEN_WIDTH / 2.0f
;
mBallSprite.
y = getGameLogic
().
getPlayField().
getVirtualHeight() / 2.0f
;
getGameLogic
().
getBallTrail().
reset();
getGameLogic
().
getBallTrail().
addTrailPoint(mBallSprite.
x, mBallSprite.
y, mRotation
);
updateLastPosition
();
}
@
Override
public void update
(float deltaTime
)
{
// store last position then move forward
speedUp
(deltaTime
);
updateLastPosition
();
processAngularVelocity
(deltaTime
);
moveForward
(deltaTime
);
// check for collisions
reflectFromEntities
(deltaTime
);
reflectFromBoard
(deltaTime
);
checkPlayerGainsScore
();
getGameLogic
().
getBackground().
setMonkeyRotationSpeed(mAngularVelocity
);
mBallSprite.
update(deltaTime
);
}
public void speedUp
(float deltaTime
)
{
mSpeedUpTimer += deltaTime
;
if (mSpeedUpTimer
>= GameConsts.
BALL_SPEEDUP_TIMER)
{
mSpeedUpTimer = mSpeedUpTimer - GameConsts.
BALL_SPEEDUP_TIMER;
mSpeed += GameConsts.
BALL_SPEEDUP_INCREASE;
}
// decrease angular velocity
if (mAngularVelocity
> 0)
{
mAngularVelocity -=
(GameConsts.
BALL_ANGULAR_SPEED_DECREASE * deltaTime
);
if (mAngularVelocity
< 0.0f
)
{
mAngularVelocity = 0.0f
;
}
}
else if (mAngularVelocity
< 0)
{
mAngularVelocity +=
(GameConsts.
BALL_ANGULAR_SPEED_DECREASE * deltaTime
);
if (mAngularVelocity
> 0.0f
)
{
mAngularVelocity = 0.0f
;
}
}
}
public void processAngularVelocity
(float deltaTime
)
{
mRotation += mAngularVelocity
* deltaTime
;
}
public void moveForward
(float deltaTime
)
{
Vector2 move =
new Vector2
();
move.
x =
(float)Math.
sin(Math.
toRadians(mRotation
));
move.
y =
(float)Math.
cos(Math.
toRadians(mRotation
));
move.
setLength(mSpeed
* deltaTime
);
mBallSprite.
x += move.
x;
mBallSprite.
y += move.
y;
}
public void reflectFromBoard
(float deltaTime
)
{
float virtualPlayFieldHeight = getGameLogic
().
getPlayField().
getVirtualHeight();
float newY = MathUtil.
clamp(mBallSprite.
y, GameConsts.
PLAYFIELD_BORDER_Y,
getGameLogic
().
getPlayField().
getVirtualHeight() - GameConsts.
PLAYFIELD_BORDER_Y);
if ((mBallSprite.
y < GameConsts.
PLAYFIELD_BORDER_Y) && (mLastPosition.
y >= GameConsts.
PLAYFIELD_BORDER_Y))
{
// upper bounce
reflectAlongNormal
(0.0f
);
clampToAngle
(GameConsts.
BALL_STEEPEST_ANGLE_REFLECT_FROM_BOARD); // clamp to steepest angle from board
getGameLogic
().
getPlayField().
createImpact(mBallSprite.
x, GameConsts.
PLAYFIELD_BORDER_Y - GameConsts.
PLAYFIELD_IMPACT_OFFSET_Y, 180.0f
);
//mGameLogic.playSound(R.raw.wallimpact);
getAudio
().
playSound(mWallImpact
);
if (getGameLogic
().
getPowerUpLogic().
isCrystalActive())
{
getGameLogic
().
getCrystals().
spawnCrystal(getX
(), newY + GameConsts.
POWERUP_CRYSTAL_RADIUS/2.0f,
new Vector2
(0.0f, 1.0f
));
getGameLogic
().
getPowerUpLogic().
deactivateCrystal();
}
}
else if (mBallSprite.
y > (virtualPlayFieldHeight - GameConsts.
PLAYFIELD_BORDER_Y) &&
(mLastPosition.
y <=
(virtualPlayFieldHeight - GameConsts.
PLAYFIELD_BORDER_Y)))
{
// lower bounce
reflectAlongNormal
(180.0f
);
clampToAngle
(GameConsts.
BALL_STEEPEST_ANGLE_REFLECT_FROM_BOARD); // clamp to steepest angle from board
getGameLogic
().
getPlayField().
createImpact(mBallSprite.
x,
(virtualPlayFieldHeight - GameConsts.
PLAYFIELD_BORDER_Y + GameConsts.
PLAYFIELD_IMPACT_OFFSET_Y), 0.0f
);
//mGameLogic.playSound(R.raw.wallimpact);
getAudio
().
playSound(mWallImpact
);
if (getGameLogic
().
getPowerUpLogic().
isCrystalActive())
{
getGameLogic
().
getCrystals().
spawnCrystal(getX
(), newY - GameConsts.
POWERUP_CRYSTAL_RADIUS/2.0f,
new Vector2
(0.0f, -1.0f
));
getGameLogic
().
getPowerUpLogic().
deactivateCrystal();
}
}
mBallSprite.
y = newY
;
}
public void reflectFromEntities
(float deltaTime
)
{
for (int i =
0; i
< getGameLogic
().
getNumReflectables(); i++
)
{
IReflectable reflectable = getGameLogic
().
getReflectable(i
);
reflectable.
reflect(this, deltaTime
);
}
}
public void checkPlayerGainsScore
()
{
if (mBallSprite.
x < GameConsts.
PLAYFIELD_BORDER_X)
{
// reached left -> left player scores
getGameLogic
().
playerGainsScore(Paddle.
PLAYER_2, mLastPaddleTouched
);
getGameLogic
().
getBallTrail().
addTrailPoint(mBallSprite.
x, mBallSprite.
y, 270.0f
);
return;
}
else if (mBallSprite.
x > (GameConsts.
VIRTUAL_SCREEN_WIDTH - GameConsts.
PLAYFIELD_BORDER_X))
{
// reached right -> right player scores
getGameLogic
().
playerGainsScore(Paddle.
PLAYER_1, mLastPaddleTouched
);
getGameLogic
().
getBallTrail().
addTrailPoint(mBallSprite.
x, mBallSprite.
y, 90.0f
);
return;
}
}
public void updateLastPosition
()
{
mLastPosition.
x = mBallSprite.
x;
mLastPosition.
y = mBallSprite.
y;
}
public void clampToAngle
(float steepestAngle
)
{
mRotation = MathUtil.
stayInDegrees0to360(mRotation
);
if (steepestAngle
<=
0)
return;
if (mRotation
< steepestAngle
)
mRotation = steepestAngle
;
if (mRotation
> (360.0f - steepestAngle
))
mRotation = 360.0f - steepestAngle
;
if ((mRotation
> (180.0f - steepestAngle
)) && (mRotation
<= 180.0f
))
mRotation = 180.0f - steepestAngle
;
if ((mRotation
< 180.0f + steepestAngle
) && (mRotation
>= 180.0f
))
mRotation = 180.0f + steepestAngle
;
}
public void reflectAlongNormal
(float rot
)
{
mRotation += 180.0f
;
mRotation = MathUtil.
stayInDegrees0to360(mRotation
);
float difference = rot - mRotation
;
mRotation = rot + difference
;
mRotation = MathUtil.
stayInDegrees0to360(mRotation
);
if (MathUtil.
turnDegrees(mRotation, rot
) >= 90.0f
)
{
mRotation = 360.0f - mRotation
;
mRotation = MathUtil.
stayInDegrees0to360(mRotation
);
}
getGameLogic
().
getBallTrail().
addTrailPoint(getX
(), getY
(), rot
);
}
public void setLastPaddleTouched
(int paddle
)
{
mLastPaddleTouched = paddle
;
}
@
Override
public void render
()
{
mBallSprite.
render();
}
public float getX
() { return mBallSprite.
x; }
public float getY
() { return mBallSprite.
y; }
public void setX
(float x
) { mBallSprite.
x = x
; }
public void setY
(float y
) { mBallSprite.
y = y
; }
public float getLastX
() { return mLastPosition.
x; }
public float getLastY
() { return mLastPosition.
y; }
public float getWidth
() { return mBallSprite.
w; }
public float getHeight
() { return mBallSprite.
h; }
public float getAngularVelocity
() { return mAngularVelocity
; }
public void setAngularVelocity
(float angularSpeed
)
{
mAngularVelocity = MathUtil.
clamp(angularSpeed, -GameConsts.
BALL_MAXIMUM_ANGULAR_SPEED, GameConsts.
BALL_MAXIMUM_ANGULAR_SPEED);
}
public Vector2 getMoveDirection
()
{
Vector2 move =
new Vector2
();
move.
x =
(float)Math.
sin(Math.
toRadians(mRotation
));
move.
y =
(float)Math.
cos(Math.
toRadians(mRotation
));
move.
setLength(mSpeed
);
return move
;
}
}