void setTarget(GameObject target) { if (target != null && mTarget != target) { mPreInterpolateCameraPosition.set(mCurrentCameraPosition); mPreInterpolateCameraPosition.subtract(target.getPosition()); if (mPreInterpolateCameraPosition.length2() < MAX_INTERPOLATE_TO_TARGET_DISTANCE * MAX_INTERPOLATE_TO_TARGET_DISTANCE) { final TimeSystem time = sSystemRegistry.timeSystem; mTargetChangedTime = time.getGameTime(); mPreInterpolateCameraPosition.set(mCurrentCameraPosition); } else { mTargetChangedTime = 0.0f; mCurrentCameraPosition.set(target.getPosition()); } } mTarget = target; }
@Override public void update(float timeDelta, BaseObject parent) { mShakeOffsetY = 0.0f; if (mShakeTime > 0.0f) { mShakeTime -= timeDelta; mShakeOffsetY = (float) (Math.sin(mShakeTime * SHAKE_FREQUENCY) * mShakeMagnitude); } if (mTarget != null) { mTargetPosition.set(mTarget.getCenteredPositionX(), mTarget.getCenteredPositionY()); final Vector2 targetPosition = mTargetPosition; if (mTargetChangedTime > 0.0f) { final TimeSystem time = sSystemRegistry.timeSystem; final float delta = time.getGameTime() - mTargetChangedTime; mCurrentCameraPosition.x = Lerp.ease( mPreInterpolateCameraPosition.x, targetPosition.x, INTERPOLATE_TO_TARGET_TIME, delta); mCurrentCameraPosition.y = Lerp.ease( mPreInterpolateCameraPosition.y, targetPosition.y, INTERPOLATE_TO_TARGET_TIME, delta); if (delta > INTERPOLATE_TO_TARGET_TIME) { mTargetChangedTime = -1; } } else { // Only respect the bias if the target is moving. No camera motion without // player input! if (mBias.length2() > 0.0f && mTarget.getVelocity().length2() > 1.0f) { mBias.normalize(); mBias.multiply(BIAS_SPEED * timeDelta); mCurrentCameraPosition.add(mBias); } final float xDelta = targetPosition.x - mCurrentCameraPosition.x; if (Math.abs(xDelta) > X_FOLLOW_DISTANCE) { mCurrentCameraPosition.x = targetPosition.x - (X_FOLLOW_DISTANCE * Utils.sign(xDelta)); } final float yDelta = targetPosition.y - mCurrentCameraPosition.y; if (yDelta > Y_UP_FOLLOW_DISTANCE) { mCurrentCameraPosition.y = targetPosition.y - Y_UP_FOLLOW_DISTANCE; } else if (yDelta < -Y_DOWN_FOLLOW_DISTANCE) { mCurrentCameraPosition.y = targetPosition.y + Y_DOWN_FOLLOW_DISTANCE; } } mBias.zero(); } mFocalPosition.x = (float) Math.floor(mCurrentCameraPosition.x); mFocalPosition.x = snapFocalPointToWorldBoundsX(mFocalPosition.x); mFocalPosition.y = (float) Math.floor(mCurrentCameraPosition.y + mShakeOffsetY); mFocalPosition.y = snapFocalPointToWorldBoundsY(mFocalPosition.y); }
@Override public void update(float timeDelta, BaseObject parent) { if (mSprite != null) { GameObject parentObject = (GameObject) parent; final float velocityX = parentObject.getVelocity().x; final float velocityY = parentObject.getVelocity().y; GameObject.ActionType currentAction = parentObject.getCurrentAction(); if (mJetSprite != null) { mJetSprite.setVisible(false); } if (mSparksSprite != null) { mSparksSprite.setVisible(false); } final TimeSystem time = sSystemRegistry.timeSystem; final float gameTime = time.getGameTime(); if (currentAction != ActionType.HIT_REACT && mPreviousAction == ActionType.HIT_REACT) { mFlickerTimeRemaining = FLICKER_DURATION; } final boolean touchingGround = parentObject.touchingGround(); boolean boosting = mPlayer != null ? mPlayer.getRocketsOn() : false; boolean visible = true; SoundSystem sound = sSystemRegistry.soundSystem; // It's usually not necessary to test to see if sound is enabled or not (when it's disabled, // play() is just a nop), but in this case I have a stream that is maintained for the rocket // sounds. So it's simpler to just avoid that code if sound is off. if (sound.getSoundEnabled()) { if (boosting) { mLastRocketsOnTime = gameTime; } else { if (gameTime - mLastRocketsOnTime < MIN_ROCKET_TIME && velocityY >= 0.0f) { boosting = true; } } if (mRocketSound != null) { if (boosting) { if (mRocketSoundStream == -1) { mRocketSoundStream = sound.play(mRocketSound, true, SoundSystem.PRIORITY_HIGH); mRocketSoundPaused = false; } else if (mRocketSoundPaused) { sound.resume(mRocketSoundStream); mRocketSoundPaused = false; } } else { sound.pause(mRocketSoundStream); mRocketSoundPaused = true; } } } // Normally, for collectables like the coin, we could just tell the object to play // a sound when it is collected. The gems are a special case, though, as we // want to pick a different sound depending on how many have been collected. if (mInventory != null && mRubySound1 != null && mRubySound2 != null && mRubySound3 != null) { InventoryComponent.UpdateRecord inventory = mInventory.getRecord(); final int rubyCount = inventory.rubyCount; if (rubyCount != mLastRubyCount) { mLastRubyCount = rubyCount; switch (rubyCount) { case 1: sound.play(mRubySound1, false, SoundSystem.PRIORITY_NORMAL); break; case 2: sound.play(mRubySound2, false, SoundSystem.PRIORITY_NORMAL); break; case 3: sound.play(mRubySound3, false, SoundSystem.PRIORITY_NORMAL); break; } } } // Turn on visual effects (smoke, etc) when the player's life reaches 1. if (mDamageSwap != null) { if (parentObject.life == 1 && !mDamageSwap.getCurrentlySwapped()) { mDamageSwap.activate(parentObject); } else if (parentObject.life != 1 && mDamageSwap.getCurrentlySwapped()) { mDamageSwap.activate(parentObject); } } float opacity = 1.0f; if (currentAction == ActionType.MOVE) { InputGameInterface input = sSystemRegistry.inputGameInterface; final InputXY dpad = input.getDirectionalPad(); if (dpad.getX() < 0.0f) { parentObject.facingDirection.x = -1.0f; } else if (dpad.getX() > 0.0f) { parentObject.facingDirection.x = 1.0f; } // TODO: get rid of these magic numbers! if (touchingGround) { if (Utils.close(velocityX, 0.0f, 30.0f)) { mSprite.playAnimation(PlayerAnimations.IDLE.ordinal()); } else if (Math.abs(velocityX) > 300.0f) { mSprite.playAnimation(PlayerAnimations.MOVE_FAST.ordinal()); } else { mSprite.playAnimation(PlayerAnimations.MOVE.ordinal()); } final InputButton attackButton = input.getAttackButton(); if (attackButton.getPressed()) { // charge final float pressedTime = gameTime - attackButton.getLastPressedTime(); final float wave = (float) Math.cos(pressedTime * (float) Math.PI * 2.0f); opacity = (wave * 0.25f) + 0.75f; } } else { if (boosting) { if (mJetSprite != null) { mJetSprite.setVisible(true); } if (Math.abs(velocityX) < 100.0f && velocityY > 10.0f) { mSprite.playAnimation(PlayerAnimations.BOOST_UP.ordinal()); } else if (Math.abs(velocityX) > 300.0f) { mSprite.playAnimation(PlayerAnimations.BOOST_MOVE_FAST.ordinal()); } else { mSprite.playAnimation(PlayerAnimations.BOOST_MOVE.ordinal()); } } else { if (Utils.close(velocityX, 0.0f, 1.0f)) { mSprite.playAnimation(PlayerAnimations.IDLE.ordinal()); } else if (Math.abs(velocityX) > 300.0f) { mSprite.playAnimation(PlayerAnimations.MOVE_FAST.ordinal()); } else { mSprite.playAnimation(PlayerAnimations.MOVE.ordinal()); } } } } else if (currentAction == ActionType.ATTACK) { mSprite.playAnimation(PlayerAnimations.STOMP.ordinal()); if (touchingGround && gameTime > mLandThumpDelay) { if (mLandThump != null && sound != null) { // modulate the sound slightly to avoid sounding too similar sound.play( mLandThump, false, SoundSystem.PRIORITY_HIGH, 1.0f, (float) (Math.random() * 0.5f) + 0.75f); mLandThumpDelay = gameTime + LAND_THUMP_DELAY; } } } else if (currentAction == ActionType.HIT_REACT) { mSprite.playAnimation(PlayerAnimations.HIT_REACT.ordinal()); if (velocityX > 0.0f) { parentObject.facingDirection.x = -1.0f; } else if (velocityX < 0.0f) { parentObject.facingDirection.x = 1.0f; } if (mSparksSprite != null) { mSparksSprite.setVisible(true); } } else if (currentAction == ActionType.DEATH) { if (mPreviousAction != currentAction) { if (mExplosionSound != null) { sound.play(mExplosionSound, false, SoundSystem.PRIORITY_NORMAL); } // by default, explode when hit with the DEATH hit type. boolean explodingDeath = parentObject.lastReceivedHitType == HitType.DEATH; // or if touching a death tile. HotSpotSystem hotSpot = sSystemRegistry.hotSpotSystem; if (hotSpot != null) { // TODO: HACK! Unify all this code. if (hotSpot.getHotSpot( parentObject.getCenteredPositionX(), parentObject.getPosition().y + 10.0f) == HotSpotSystem.HotSpotType.DIE) { explodingDeath = true; } } if (explodingDeath) { mExplodingDeath = true; GameObjectFactory factory = sSystemRegistry.gameObjectFactory; GameObjectManager manager = sSystemRegistry.gameObjectManager; if (factory != null && manager != null) { GameObject explosion = factory.spawnEffectExplosionGiant( parentObject.getPosition().x, parentObject.getPosition().y); if (explosion != null) { manager.add(explosion); } } } else { mSprite.playAnimation(PlayerAnimations.DEATH.ordinal()); mExplodingDeath = false; } mFlickerTimeRemaining = 0.0f; if (mSparksSprite != null) { if (!mSprite.animationFinished()) { mSparksSprite.setVisible(true); } } } if (mExplodingDeath) { visible = false; } } else if (currentAction == ActionType.FROZEN) { mSprite.playAnimation(PlayerAnimations.FROZEN.ordinal()); } if (mFlickerTimeRemaining > 0.0f) { mFlickerTimeRemaining -= timeDelta; if (gameTime > mLastFlickerTime + FLICKER_INTERVAL) { mLastFlickerTime = gameTime; mFlickerOn = !mFlickerOn; } mSprite.setVisible(mFlickerOn); if (mJetSprite != null && mJetSprite.getVisible()) { mJetSprite.setVisible(mFlickerOn); } } else { mSprite.setVisible(visible); mSprite.setOpacity(opacity); } mPreviousAction = currentAction; } }
@Override public void update(float timeDelta, BaseObject parent) { if (mRenderComponent != null) { final TimeSystem time = sSystemRegistry.timeSystem; final float currentTime = time.getGameTime(); // Support repeating "phases" on top of the looping fade itself. // Complexity++, but it lets this component handle several // different use cases. if (mActivateTime == 0.0f) { mActivateTime = currentTime; mInitialDelayTimer = mInitialDelay; } else if (mPhaseDuration > 0.0f && currentTime - mActivateTime > mPhaseDuration) { mActivateTime = currentTime; mInitialDelayTimer = mInitialDelay; mStartTime = 0.0f; } if (mInitialDelayTimer > 0.0f) { mInitialDelayTimer -= timeDelta; } else { if (mStartTime == 0) { mStartTime = currentTime; } float elapsed = currentTime - mStartTime; float opacity = mInitialOpacity; if (mLoopType != LOOP_TYPE_NONE && elapsed > mDuration) { final float endTime = mStartTime + mDuration; elapsed = endTime - currentTime; mStartTime = endTime; if (mLoopType == LOOP_TYPE_PING_PONG) { float temp = mInitialOpacity; mInitialOpacity = mTargetOpacity; mTargetOpacity = temp; } } if (elapsed > mDuration) { opacity = mTargetOpacity; } else if (elapsed != 0.0f) { if (mFunction == FADE_LINEAR) { opacity = Lerp.lerp(mInitialOpacity, mTargetOpacity, mDuration, elapsed); } else if (mFunction == FADE_EASE) { opacity = Lerp.ease(mInitialOpacity, mTargetOpacity, mDuration, elapsed); } } if (mTexture != null) { // If a texture is set then we supply a drawable to the render component. // If not, we take whatever drawable the renderer already has. final DrawableFactory factory = sSystemRegistry.drawableFactory; if (factory != null) { GameObject parentObject = ((GameObject) parent); DrawableBitmap bitmap = factory.allocateDrawableBitmap(); bitmap.resize((int) mTexture.width, (int) mTexture.height); // TODO: Super tricky scale. fix this! bitmap.setWidth((int) parentObject.width); bitmap.setHeight((int) parentObject.height); bitmap.setOpacity(opacity); bitmap.setTexture(mTexture); mRenderComponent.setDrawable(bitmap); } } else { DrawableObject drawable = mRenderComponent.getDrawable(); // TODO: ack, instanceof! Fix this! if (drawable != null && drawable instanceof DrawableBitmap) { ((DrawableBitmap) drawable).setOpacity(opacity); } } } } }