Rev 87 | Details | Compare with Previous | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 32 | chris | 1 | package com.gebauz.pingK.game; |
| 2 | |||
| 69 | chris | 3 | import java.util.Random; |
| 4 | |||
| 43 | chris | 5 | import android.util.Log; |
| 6 | |||
| 32 | chris | 7 | import com.gebauz.framework.util.GLUtil; |
| 8 | import com.gebauz.framework.util.Sprite2D; |
||
| 43 | chris | 9 | import com.gebauz.pingK.MultitouchInput; |
| 32 | chris | 10 | import com.gebauz.pingK.R; |
| 43 | chris | 11 | import com.gebauz.pingK.MultitouchInput.Finger; |
| 32 | chris | 12 | |
| 46 | chris | 13 | public class Paddle implements IReflectable |
| 32 | chris | 14 | { |
| 15 | public static final int PLAYER_1 = 0; |
||
| 16 | public static final int PLAYER_2 = 1; |
||
| 17 | |||
| 18 | private GameLogic mGameLogic = null; |
||
| 19 | private int mPlayerIndex = -1; |
||
| 69 | chris | 20 | private boolean mIsAI = true; |
| 21 | private float mAITimeOut = 0.0f; |
||
| 22 | private float mAIRandom = 0.0f; |
||
| 23 | private float mAIRandomTimer = 0.0f; |
||
| 32 | chris | 24 | |
| 25 | private Sprite2D mPaddleSprite; |
||
| 26 | |||
| 48 | chris | 27 | private float mTargetPositionY = GameConsts.VIRTUAL_SCREEN_HEIGHT / 2.0f; |
| 28 | private float mLastDeltaTime = 0.0f; |
||
| 29 | private float mLastPositionY = mTargetPositionY; |
||
| 43 | chris | 30 | |
| 32 | chris | 31 | public Paddle(GameLogic gameLogic, int playerIndex) |
| 32 | { |
||
| 33 | mGameLogic = gameLogic; |
||
| 34 | mPlayerIndex = playerIndex; |
||
| 47 | chris | 35 | |
| 36 | mGameLogic.addReflectable(this); |
||
| 32 | chris | 37 | } |
| 38 | |||
| 39 | public void init() |
||
| 40 | { |
||
| 41 | float x = 0; |
||
| 42 | float y = 0; |
||
| 43 | float angle = 0; |
||
| 44 | |||
| 45 | if (mPlayerIndex == PLAYER_1) |
||
| 46 | { |
||
| 47 | x = GameConsts.PADDLE_DISTANCE_FROM_EDGE_X; |
||
| 48 | angle = 180.0f; |
||
| 49 | } |
||
| 50 | else |
||
| 51 | { |
||
| 52 | x = GameConsts.VIRTUAL_SCREEN_WIDTH - GameConsts.PADDLE_DISTANCE_FROM_EDGE_X; |
||
| 53 | } |
||
| 54 | |||
| 61 | chris | 55 | y = mGameLogic.getVirtualPlayFieldHeight() / 2.0f; |
| 80 | chris | 56 | |
| 57 | //y = mGameLogic.getVirtualPlayFieldHeight() - 15.0f; |
||
| 58 | |||
| 59 | mTargetPositionY = y; |
||
| 48 | chris | 60 | mLastPositionY = mTargetPositionY; |
| 32 | chris | 61 | |
| 62 | mPaddleSprite = new Sprite2D(); |
||
| 63 | mPaddleSprite.init(R.drawable.paddle, x, y, GameConsts.PADDLE_WIDTH, GameConsts.PADDLE_HEIGHT); |
||
| 64 | mPaddleSprite.angle = angle; |
||
| 69 | chris | 65 | |
| 66 | mAITimeOut = 0.0f; |
||
| 32 | chris | 67 | } |
| 68 | |||
| 69 | public void exit() |
||
| 70 | { |
||
| 71 | mPaddleSprite = null; |
||
| 72 | } |
||
| 73 | |||
| 45 | chris | 74 | public void update(float deltaTime) |
| 32 | chris | 75 | { |
| 49 | chris | 76 | mLastPositionY = mPaddleSprite.y; |
| 48 | chris | 77 | mLastDeltaTime = deltaTime; |
| 69 | chris | 78 | mAITimeOut += deltaTime; |
| 79 | mAIRandomTimer += deltaTime; |
||
| 48 | chris | 80 | |
| 81 | // update positions |
||
| 43 | chris | 82 | if (mPlayerIndex == PLAYER_1) |
| 83 | { |
||
| 75 | chris | 84 | Finger finger = MultitouchInput.getInstance().getTouchPointInside(0, 0, GameConsts.VIRTUAL_SCREEN_WIDTH / 2.0f, mGameLogic.getVirtualPlayFieldHeight()); |
| 43 | chris | 85 | if (finger != null) |
| 86 | { |
||
| 87 | mTargetPositionY = finger.y; |
||
| 69 | chris | 88 | mIsAI = false; |
| 89 | mAITimeOut = 0.0f; |
||
| 43 | chris | 90 | } |
| 91 | } |
||
| 92 | else |
||
| 93 | { |
||
| 74 | chris | 94 | Finger finger = MultitouchInput.getInstance().getTouchPointInside(GameConsts.VIRTUAL_SCREEN_WIDTH / 2.0f, 0, GameConsts.VIRTUAL_SCREEN_WIDTH, mGameLogic.getVirtualPlayFieldHeight()); |
| 43 | chris | 95 | if (finger != null) |
| 96 | { |
||
| 97 | mTargetPositionY = finger.y; |
||
| 69 | chris | 98 | mIsAI = false; |
| 99 | mAITimeOut = 0.0f; |
||
| 43 | chris | 100 | } |
| 101 | } |
||
| 102 | |||
| 69 | chris | 103 | if ((!mIsAI) && (mAITimeOut > GameConsts.PADDLE_AI_TIMEOUT)) |
| 104 | { |
||
| 105 | mIsAI = true; |
||
| 106 | } |
||
| 107 | |||
| 108 | if (mIsAI) |
||
| 109 | { |
||
| 110 | if (mAIRandomTimer > GameConsts.PADDLE_AI_RANDOM_TIMER) |
||
| 111 | { |
||
| 112 | mAIRandomTimer = 0.0f; |
||
| 113 | mAIRandom = mGameLogic.getRandomizer().nextFloat(); |
||
| 114 | } |
||
| 115 | |||
| 116 | // try to reach ball, but only react when ball is inside own territory |
||
| 117 | float ballX = mGameLogic.getBall().getX(); |
||
| 118 | if ( ((mPlayerIndex == PLAYER_1) && (ballX < (GameConsts.VIRTUAL_SCREEN_WIDTH/1.5f))) || |
||
| 119 | ((mPlayerIndex == PLAYER_2) && (ballX > (GameConsts.VIRTUAL_SCREEN_WIDTH - (GameConsts.VIRTUAL_SCREEN_WIDTH/1.5f)))) ) |
||
| 120 | { |
||
| 121 | float aiTargetY = mGameLogic.getBall().getY() + (-GameConsts.PADDLE_AI_VARIANCE + 2 * mAIRandom * GameConsts.PADDLE_AI_VARIANCE); |
||
| 122 | |||
| 123 | float diff = aiTargetY - mTargetPositionY; |
||
| 124 | mTargetPositionY += (diff * deltaTime * GameConsts.PADDLE_AI_ACCEL); |
||
| 125 | } |
||
| 126 | else |
||
| 127 | { |
||
| 128 | // slowly go to center |
||
| 129 | float centerTarget = mGameLogic.getVirtualPlayFieldHeight() / 2.0f + (-GameConsts.PADDLE_AI_VARIANCE2 + 2*mAIRandom * GameConsts.PADDLE_AI_VARIANCE2); |
||
| 130 | float diff = centerTarget - mTargetPositionY; |
||
| 131 | mTargetPositionY += (diff * deltaTime * GameConsts.PADDLE_AI_ACCEL_SLOW); |
||
| 132 | } |
||
| 133 | } |
||
| 134 | |||
| 48 | chris | 135 | float distanceFromEdgeY = mPaddleSprite.h / 2.0f + GameConsts.PADDLE_DISTANCE_FROM_EDGE_Y; |
| 44 | chris | 136 | |
| 48 | chris | 137 | if (mTargetPositionY < distanceFromEdgeY) |
| 138 | mTargetPositionY = distanceFromEdgeY; |
||
| 61 | chris | 139 | else if (mTargetPositionY > (mGameLogic.getVirtualPlayFieldHeight() - distanceFromEdgeY)) |
| 140 | mTargetPositionY = (mGameLogic.getVirtualPlayFieldHeight() - distanceFromEdgeY); |
||
| 48 | chris | 141 | |
| 44 | chris | 142 | if (mTargetPositionY > mPaddleSprite.y) |
| 143 | { |
||
| 144 | float diff = mTargetPositionY - mPaddleSprite.y; |
||
| 145 | mPaddleSprite.y += (diff * deltaTime * GameConsts.PADDLE_INPUT_ACCEL); |
||
| 146 | if (mPaddleSprite.y > mTargetPositionY) |
||
| 147 | mPaddleSprite.y = mTargetPositionY; |
||
| 148 | } |
||
| 149 | else if (mTargetPositionY < mPaddleSprite.y) |
||
| 150 | { |
||
| 151 | float diff = mPaddleSprite.y - mTargetPositionY; |
||
| 152 | mPaddleSprite.y -= (diff * deltaTime * GameConsts.PADDLE_INPUT_ACCEL); |
||
| 153 | if (mPaddleSprite.y < mTargetPositionY) |
||
| 154 | mPaddleSprite.y = mTargetPositionY; |
||
| 155 | } |
||
| 156 | |||
| 45 | chris | 157 | mPaddleSprite.update(deltaTime); |
| 32 | chris | 158 | } |
| 159 | |||
| 160 | public void render() |
||
| 161 | { |
||
| 85 | chris | 162 | mPaddleSprite.mirrorX = mGameLogic.getPowerUpEffect().isConcaveActive(); |
| 32 | chris | 163 | mPaddleSprite.render(); |
| 164 | } |
||
| 46 | chris | 165 | |
| 48 | chris | 166 | public float getMovementSpeed() |
| 167 | { |
||
| 168 | return (mPaddleSprite.y - mLastPositionY) / mLastDeltaTime; |
||
| 169 | } |
||
| 170 | |||
| 46 | chris | 171 | public void reflect(Ball ball, float deltaTime) |
| 172 | { |
||
| 48 | chris | 173 | // check collision from the front |
| 174 | if (Math.abs(ball.getY() - mPaddleSprite.y) < ((mPaddleSprite.h+ ball.getHeight())/2.0f)) |
||
| 47 | chris | 175 | { |
| 48 | chris | 176 | float offset = ((mPaddleSprite.w/2.0f)) - GameConsts.PADDLE_HIT_OFFSET; |
| 47 | chris | 177 | float paddleX = mPaddleSprite.x; |
| 178 | // if ball is within Y coordinate space of paddle, check the two positions |
||
| 179 | if (mPlayerIndex == PLAYER_1) |
||
| 180 | { |
||
| 48 | chris | 181 | paddleX += offset; |
| 47 | chris | 182 | if ((ball.getX() <= paddleX) && (ball.getLastX() > paddleX)) |
| 183 | { |
||
| 184 | // paddle touched, reflect the ball |
||
| 66 | chris | 185 | ballHitsPaddleFront(ball, deltaTime); |
| 186 | ball.setLastPaddleTouched(mPlayerIndex); |
||
| 87 | chris | 187 | if (mGameLogic.getPowerUpEffect().isConcaveActive()) |
| 188 | mGameLogic.getPaddleImpact().addImpact(mPaddleSprite.x + GameConsts.PADDLE_IMPACT_CONCAVE_OFFSET, mPaddleSprite.y, 0.0f); |
||
| 189 | else |
||
| 190 | mGameLogic.getPaddleImpact().addImpact(mPaddleSprite.x, mPaddleSprite.y, 180.0f); |
||
| 191 | |||
| 192 | mGameLogic.playSound(R.raw.paddleimpact); |
||
| 193 | |||
| 101 | chris | 194 | mGameLogic.getCrystalHitCounter().resetHits(); |
| 195 | |||
| 69 | chris | 196 | return; |
| 46 | chris | 197 | } |
| 198 | } |
||
| 47 | chris | 199 | else if (mPlayerIndex == PLAYER_2) |
| 200 | { |
||
| 48 | chris | 201 | paddleX -= offset; |
| 47 | chris | 202 | if ((ball.getX() >= paddleX) && (ball.getLastX() < paddleX)) |
| 203 | { |
||
| 204 | // paddle touched, reflect the ball |
||
| 48 | chris | 205 | ballHitsPaddleFront(ball, deltaTime); |
| 66 | chris | 206 | ball.setLastPaddleTouched(mPlayerIndex); |
| 87 | chris | 207 | if (mGameLogic.getPowerUpEffect().isConcaveActive()) |
| 208 | mGameLogic.getPaddleImpact().addImpact(mPaddleSprite.x - GameConsts.PADDLE_IMPACT_CONCAVE_OFFSET, mPaddleSprite.y, 180.0f); |
||
| 209 | else |
||
| 210 | mGameLogic.getPaddleImpact().addImpact(mPaddleSprite.x, mPaddleSprite.y, 0.0f); |
||
| 211 | |||
| 212 | mGameLogic.playSound(R.raw.paddleimpact); |
||
| 213 | |||
| 101 | chris | 214 | mGameLogic.getCrystalHitCounter().resetHits(); |
| 215 | |||
| 69 | chris | 216 | return; |
| 48 | chris | 217 | } |
| 47 | chris | 218 | } |
| 219 | } |
||
| 85 | chris | 220 | |
| 48 | chris | 221 | // check collision from below & above |
| 222 | if (Math.abs(ball.getX() - mPaddleSprite.x) < (mPaddleSprite.w/2.0f)) |
||
| 223 | { |
||
| 224 | float halfHeight = mPaddleSprite.h/2.0f; |
||
| 225 | // for sides, use simple reflection |
||
| 226 | if ((ball.getY() >= (mPaddleSprite.y - halfHeight)) && (ball.getLastY() < (mPaddleSprite.y - halfHeight))) |
||
| 227 | { |
||
| 228 | // above |
||
| 229 | ball.reflectAlongNormal(180.0f); |
||
| 230 | ball.clampToAngle(GameConsts.BALL_STEEPEST_ANGLE_HIT_PADDLE_SIDE); |
||
| 66 | chris | 231 | ball.setLastPaddleTouched(mPlayerIndex); |
| 87 | chris | 232 | |
| 233 | mGameLogic.playSound(R.raw.paddleimpact); |
||
| 101 | chris | 234 | |
| 235 | mGameLogic.getCrystalHitCounter().resetHits(); |
||
| 236 | |||
| 237 | // TODO: impact |
||
| 48 | chris | 238 | } |
| 239 | else if ((ball.getY() <= (mPaddleSprite.y + halfHeight)) && (ball.getLastY() > (mPaddleSprite.y + halfHeight))) |
||
| 240 | { |
||
| 241 | // below |
||
| 242 | ball.reflectAlongNormal(0.0f); |
||
| 243 | ball.clampToAngle(GameConsts.BALL_STEEPEST_ANGLE_HIT_PADDLE_SIDE); |
||
| 66 | chris | 244 | ball.setLastPaddleTouched(mPlayerIndex); |
| 87 | chris | 245 | |
| 246 | mGameLogic.playSound(R.raw.paddleimpact); |
||
| 101 | chris | 247 | |
| 248 | mGameLogic.getCrystalHitCounter().resetHits(); |
||
| 249 | |||
| 250 | // TODO: impact |
||
| 48 | chris | 251 | } |
| 85 | chris | 252 | } |
| 48 | chris | 253 | |
| 87 | chris | 254 | |
| 255 | // TODO: clamp ball's coordinates to play field |
||
| 46 | chris | 256 | } |
| 47 | chris | 257 | |
| 48 | chris | 258 | public void ballHitsPaddleFront(Ball ball, float deltaTime) |
| 47 | chris | 259 | { |
| 85 | chris | 260 | float newX = mPaddleSprite.x; |
| 49 | chris | 261 | float yDifference = (ball.getY() - mPaddleSprite.y) * GameConsts.PADDLE_HIT_ZONE_DEVIATION; |
| 47 | chris | 262 | |
| 85 | chris | 263 | if (mGameLogic.getPowerUpEffect().isConcaveActive()) |
| 264 | yDifference = -yDifference; |
||
| 265 | |||
| 47 | chris | 266 | // TODO: concave handling |
| 267 | float direction = 0.0f; |
||
| 268 | float paddleDirection = 0.0f; |
||
| 48 | chris | 269 | float invertPlayer2Paddle = 0; |
| 47 | chris | 270 | |
| 271 | if (mPlayerIndex == PLAYER_1) |
||
| 272 | { |
||
| 273 | // left |
||
| 274 | paddleDirection = 270.0f; |
||
| 275 | direction = 90.0f - yDifference; |
||
| 85 | chris | 276 | newX += mPaddleSprite.w/3.0f; |
| 277 | |||
| 49 | chris | 278 | invertPlayer2Paddle = -1; |
| 47 | chris | 279 | } |
| 280 | else if (mPlayerIndex == PLAYER_2) |
||
| 281 | { |
||
| 282 | // right |
||
| 283 | paddleDirection = 90.0f; |
||
| 284 | direction = 270.0f + yDifference; |
||
| 85 | chris | 285 | newX -= mPaddleSprite.w/3.0f; |
| 49 | chris | 286 | invertPlayer2Paddle = 1; |
| 47 | chris | 287 | } |
| 288 | |||
| 85 | chris | 289 | ball.setX(newX); |
| 47 | chris | 290 | ball.reflectAlongNormal(direction); |
| 291 | |||
| 85 | chris | 292 | float angularSpeed = getMovementSpeed() * GameConsts.BALL_TOP_SPIN_INTENSITY * invertPlayer2Paddle; |
| 48 | chris | 293 | ball.setAngularVelocity(ball.getAngularVelocity() + angularSpeed); |
| 85 | chris | 294 | ball.clampToAngle(GameConsts.BALL_STEEPEST_ANGLE_HIT_PADDLE_FRONT); |
| 49 | chris | 295 | |
| 85 | chris | 296 | /* |
| 297 | |||
| 298 | if (paddle.paddle.belongtoplayer = 1) then |
||
| 299 | begin |
||
| 300 | paddledirection := 0; |
||
| 301 | direction:= 90 - ydifference; |
||
| 302 | newx := newx + 6; |
||
| 303 | invertplayer2paddle := 1; |
||
| 304 | end else |
||
| 305 | begin |
||
| 306 | paddledirection := 180; |
||
| 307 | direction:= 270 + ydifference; |
||
| 308 | newx := newx - 6; |
||
| 309 | invertplayer2paddle := -1; |
||
| 310 | end; |
||
| 311 | |||
| 312 | ball.lasthitplayer:=paddle.paddle.belongtoplayer; |
||
| 313 | settings.pos.x := newx; |
||
| 314 | reflectAlongNormal(direction); |
||
| 315 | |||
| 316 | generateImpact(paddle.settings.pos,paddledirection, SX_EIMPACT_MODE_PADDLE); |
||
| 317 | |||
| 318 | angularspeed := paddle.getMovementSpeed * getTopSpinIntensity * invertplayer2paddle; |
||
| 319 | setAngularVelocity(ball.angularspeed + angularspeed); |
||
| 320 | clampToAngle(getBallSteepestAngleHitPaddle); |
||
| 321 | */ |
||
| 322 | |||
| 49 | chris | 323 | //Log.v(GameConsts.LOG_TAG, "AngularVelocity = " + ball.getAngularVelocity() + angularSpeed); |
| 47 | chris | 324 | } |
| 325 | |||
| 32 | chris | 326 | } |