package com.gebauz.pingK.game;
import java.util.Random;
import android.util.Log;
import com.gebauz.framework.util.GLUtil;
import com.gebauz.framework.util.Sprite2D;
import com.gebauz.pingK.MultitouchInput;
import com.gebauz.pingK.R;
import com.gebauz.pingK.MultitouchInput.Finger;
public class Paddle
implements IReflectable
{
public static final int PLAYER_1 =
0;
public static final int PLAYER_2 =
1;
private GameLogic mGameLogic =
null;
private int mPlayerIndex = -
1;
private boolean mIsAI =
true;
private float mAITimeOut = 0.0f
;
private float mAIRandom = 0.0f
;
private float mAIRandomTimer = 0.0f
;
private Sprite2D mPaddleSprite
;
private float mTargetPositionY = GameConsts.
VIRTUAL_SCREEN_HEIGHT / 2.0f
;
private float mLastDeltaTime = 0.0f
;
private float mLastPositionY = mTargetPositionY
;
public Paddle
(GameLogic gameLogic,
int playerIndex
)
{
mGameLogic = gameLogic
;
mPlayerIndex = playerIndex
;
mGameLogic.
addReflectable(this);
}
public void init
()
{
float x =
0;
float y =
0;
float angle =
0;
if (mPlayerIndex == PLAYER_1
)
{
x = GameConsts.
PADDLE_DISTANCE_FROM_EDGE_X;
angle = 180.0f
;
}
else
{
x = GameConsts.
VIRTUAL_SCREEN_WIDTH - GameConsts.
PADDLE_DISTANCE_FROM_EDGE_X;
}
y = mGameLogic.
getVirtualPlayFieldHeight() / 2.0f
;
//y = mGameLogic.getVirtualPlayFieldHeight() - 15.0f;
mTargetPositionY = y
;
mLastPositionY = mTargetPositionY
;
mPaddleSprite =
new Sprite2D
();
mPaddleSprite.
init(R.
drawable.
paddle, x, y, GameConsts.
PADDLE_WIDTH, GameConsts.
PADDLE_HEIGHT);
mPaddleSprite.
angle = angle
;
mAITimeOut = 0.0f
;
}
public void exit
()
{
mPaddleSprite =
null;
}
public void update
(float deltaTime
)
{
mLastPositionY = mPaddleSprite.
y;
mLastDeltaTime = deltaTime
;
mAITimeOut += deltaTime
;
mAIRandomTimer += deltaTime
;
// update positions
if (mPlayerIndex == PLAYER_1
)
{
Finger finger = MultitouchInput.
getInstance().
getTouchPointInside(0,
0, GameConsts.
VIRTUAL_SCREEN_WIDTH / 2.0f, mGameLogic.
getVirtualPlayFieldHeight());
if (finger
!=
null)
{
mTargetPositionY = finger.
y;
mIsAI =
false;
mAITimeOut = 0.0f
;
}
}
else
{
Finger finger = MultitouchInput.
getInstance().
getTouchPointInside(GameConsts.
VIRTUAL_SCREEN_WIDTH / 2.0f,
0, GameConsts.
VIRTUAL_SCREEN_WIDTH, mGameLogic.
getVirtualPlayFieldHeight());
if (finger
!=
null)
{
mTargetPositionY = finger.
y;
mIsAI =
false;
mAITimeOut = 0.0f
;
}
}
if ((!mIsAI
) && (mAITimeOut
> GameConsts.
PADDLE_AI_TIMEOUT))
{
mIsAI =
true;
}
if (mIsAI
)
{
if (mAIRandomTimer
> GameConsts.
PADDLE_AI_RANDOM_TIMER)
{
mAIRandomTimer = 0.0f
;
mAIRandom = mGameLogic.
getRandomizer().
nextFloat();
}
// try to reach ball, but only react when ball is inside own territory
float ballX = mGameLogic.
getBall().
getX();
if ( ((mPlayerIndex == PLAYER_1
) && (ballX
< (GameConsts.
VIRTUAL_SCREEN_WIDTH/1.5f
))) ||
((mPlayerIndex == PLAYER_2
) && (ballX
> (GameConsts.
VIRTUAL_SCREEN_WIDTH -
(GameConsts.
VIRTUAL_SCREEN_WIDTH/1.5f
)))) )
{
float aiTargetY = mGameLogic.
getBall().
getY() +
(-GameConsts.
PADDLE_AI_VARIANCE +
2 * mAIRandom
* GameConsts.
PADDLE_AI_VARIANCE);
float diff = aiTargetY - mTargetPositionY
;
mTargetPositionY +=
(diff
* deltaTime
* GameConsts.
PADDLE_AI_ACCEL);
}
else
{
// slowly go to center
float centerTarget = mGameLogic.
getVirtualPlayFieldHeight() / 2.0f +
(-GameConsts.
PADDLE_AI_VARIANCE2 +
2*mAIRandom
* GameConsts.
PADDLE_AI_VARIANCE2);
float diff = centerTarget - mTargetPositionY
;
mTargetPositionY +=
(diff
* deltaTime
* GameConsts.
PADDLE_AI_ACCEL_SLOW);
}
}
float distanceFromEdgeY = mPaddleSprite.
h / 2.0f + GameConsts.
PADDLE_DISTANCE_FROM_EDGE_Y;
if (mTargetPositionY
< distanceFromEdgeY
)
mTargetPositionY = distanceFromEdgeY
;
else if (mTargetPositionY
> (mGameLogic.
getVirtualPlayFieldHeight() - distanceFromEdgeY
))
mTargetPositionY =
(mGameLogic.
getVirtualPlayFieldHeight() - distanceFromEdgeY
);
if (mTargetPositionY
> mPaddleSprite.
y)
{
float diff = mTargetPositionY - mPaddleSprite.
y;
mPaddleSprite.
y +=
(diff
* deltaTime
* GameConsts.
PADDLE_INPUT_ACCEL);
if (mPaddleSprite.
y > mTargetPositionY
)
mPaddleSprite.
y = mTargetPositionY
;
}
else if (mTargetPositionY
< mPaddleSprite.
y)
{
float diff = mPaddleSprite.
y - mTargetPositionY
;
mPaddleSprite.
y -=
(diff
* deltaTime
* GameConsts.
PADDLE_INPUT_ACCEL);
if (mPaddleSprite.
y < mTargetPositionY
)
mPaddleSprite.
y = mTargetPositionY
;
}
mPaddleSprite.
update(deltaTime
);
}
public void render
()
{
mPaddleSprite.
mirrorX = mGameLogic.
getPowerUpEffect().
isConcaveActive();
mPaddleSprite.
render();
}
public float getMovementSpeed
()
{
return (mPaddleSprite.
y - mLastPositionY
) / mLastDeltaTime
;
}
public void reflect
(Ball ball,
float deltaTime
)
{
// check collision from the front
if (Math.
abs(ball.
getY() - mPaddleSprite.
y) < ((mPaddleSprite.
h+ ball.
getHeight())/2.0f
))
{
float offset =
((mPaddleSprite.
w/2.0f
)) - GameConsts.
PADDLE_HIT_OFFSET;
float paddleX = mPaddleSprite.
x;
// if ball is within Y coordinate space of paddle, check the two positions
if (mPlayerIndex == PLAYER_1
)
{
paddleX += offset
;
if ((ball.
getX() <= paddleX
) && (ball.
getLastX() > paddleX
))
{
// paddle touched, reflect the ball
ballHitsPaddleFront
(ball, deltaTime
);
ball.
setLastPaddleTouched(mPlayerIndex
);
if (mGameLogic.
getPowerUpEffect().
isConcaveActive())
mGameLogic.
getPaddleImpact().
addImpact(mPaddleSprite.
x + GameConsts.
PADDLE_IMPACT_CONCAVE_OFFSET, mPaddleSprite.
y, 0.0f
);
else
mGameLogic.
getPaddleImpact().
addImpact(mPaddleSprite.
x, mPaddleSprite.
y, 180.0f
);
mGameLogic.
playSound(R.
raw.
paddleimpact);
mGameLogic.
getCrystalHitCounter().
resetHits();
return;
}
}
else if (mPlayerIndex == PLAYER_2
)
{
paddleX -= offset
;
if ((ball.
getX() >= paddleX
) && (ball.
getLastX() < paddleX
))
{
// paddle touched, reflect the ball
ballHitsPaddleFront
(ball, deltaTime
);
ball.
setLastPaddleTouched(mPlayerIndex
);
if (mGameLogic.
getPowerUpEffect().
isConcaveActive())
mGameLogic.
getPaddleImpact().
addImpact(mPaddleSprite.
x - GameConsts.
PADDLE_IMPACT_CONCAVE_OFFSET, mPaddleSprite.
y, 180.0f
);
else
mGameLogic.
getPaddleImpact().
addImpact(mPaddleSprite.
x, mPaddleSprite.
y, 0.0f
);
mGameLogic.
playSound(R.
raw.
paddleimpact);
mGameLogic.
getCrystalHitCounter().
resetHits();
return;
}
}
}
// check collision from below & above
if (Math.
abs(ball.
getX() - mPaddleSprite.
x) < (mPaddleSprite.
w/2.0f
))
{
float halfHeight = mPaddleSprite.
h/2.0f
;
// for sides, use simple reflection
if ((ball.
getY() >=
(mPaddleSprite.
y - halfHeight
)) && (ball.
getLastY() < (mPaddleSprite.
y - halfHeight
)))
{
// above
ball.
reflectAlongNormal(180.0f
);
ball.
clampToAngle(GameConsts.
BALL_STEEPEST_ANGLE_HIT_PADDLE_SIDE);
ball.
setLastPaddleTouched(mPlayerIndex
);
mGameLogic.
playSound(R.
raw.
paddleimpact);
mGameLogic.
getCrystalHitCounter().
resetHits();
// TODO: impact
}
else if ((ball.
getY() <=
(mPaddleSprite.
y + halfHeight
)) && (ball.
getLastY() > (mPaddleSprite.
y + halfHeight
)))
{
// below
ball.
reflectAlongNormal(0.0f
);
ball.
clampToAngle(GameConsts.
BALL_STEEPEST_ANGLE_HIT_PADDLE_SIDE);
ball.
setLastPaddleTouched(mPlayerIndex
);
mGameLogic.
playSound(R.
raw.
paddleimpact);
mGameLogic.
getCrystalHitCounter().
resetHits();
// TODO: impact
}
}
// TODO: clamp ball's coordinates to play field
}
public void ballHitsPaddleFront
(Ball ball,
float deltaTime
)
{
float newX = mPaddleSprite.
x;
float yDifference =
(ball.
getY() - mPaddleSprite.
y) * GameConsts.
PADDLE_HIT_ZONE_DEVIATION;
if (mGameLogic.
getPowerUpEffect().
isConcaveActive())
yDifference = -yDifference
;
// TODO: concave handling
float direction = 0.0f
;
float paddleDirection = 0.0f
;
float invertPlayer2Paddle =
0;
if (mPlayerIndex == PLAYER_1
)
{
// left
paddleDirection = 270.0f
;
direction = 90.0f - yDifference
;
newX += mPaddleSprite.
w/3.0f
;
invertPlayer2Paddle = -
1;
}
else if (mPlayerIndex == PLAYER_2
)
{
// right
paddleDirection = 90.0f
;
direction = 270.0f + yDifference
;
newX -= mPaddleSprite.
w/3.0f
;
invertPlayer2Paddle =
1;
}
ball.
setX(newX
);
ball.
reflectAlongNormal(direction
);
float angularSpeed = getMovementSpeed
() * GameConsts.
BALL_TOP_SPIN_INTENSITY * invertPlayer2Paddle
;
ball.
setAngularVelocity(ball.
getAngularVelocity() + angularSpeed
);
ball.
clampToAngle(GameConsts.
BALL_STEEPEST_ANGLE_HIT_PADDLE_FRONT);
/*
if (paddle.paddle.belongtoplayer = 1) then
begin
paddledirection := 0;
direction:= 90 - ydifference;
newx := newx + 6;
invertplayer2paddle := 1;
end else
begin
paddledirection := 180;
direction:= 270 + ydifference;
newx := newx - 6;
invertplayer2paddle := -1;
end;
ball.lasthitplayer:=paddle.paddle.belongtoplayer;
settings.pos.x := newx;
reflectAlongNormal(direction);
generateImpact(paddle.settings.pos,paddledirection, SX_EIMPACT_MODE_PADDLE);
angularspeed := paddle.getMovementSpeed * getTopSpinIntensity * invertplayer2paddle;
setAngularVelocity(ball.angularspeed + angularspeed);
clampToAngle(getBallSteepestAngleHitPaddle);
*/
//Log.v(GameConsts.LOG_TAG, "AngularVelocity = " + ball.getAngularVelocity() + angularSpeed);
}
}