/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.replica.replicaisland; import com.replica.replicaisland.GameObject.ActionType; /** * A component that allows an object to spawn other objects and apply velocity to them at * specific intervals. Can be used to launch projectiles, particle effects, or any other type * of game object. */ public class LaunchProjectileComponent extends GameComponent { private GameObjectFactory.GameObjectType mObjectTypeToSpawn; private float mOffsetX; private float mOffsetY; private float mVelocityX; private float mVelocityY; private float mThetaError; private GameObject.ActionType mRequiredAction; private float mDelayBetweenShots; private int mProjectilesInSet; private float mDelayBetweenSets; private int mSetsPerActivation; private float mDelayBeforeFirstSet; private float mLastProjectileTime; private float mSetStartedTime; private int mLaunchedCount; private int mSetCount; private boolean mTrackProjectiles; private int mMaxTrackedProjectiles; private int mTrackedProjectileCount; private Vector2 mWorkingVector; private SoundSystem.Sound mShootSound; public LaunchProjectileComponent() { super(); setPhase(ComponentPhases.POST_COLLISION.ordinal()); mWorkingVector = new Vector2(); reset(); } @Override public void reset() { mRequiredAction = ActionType.INVALID; mObjectTypeToSpawn = GameObjectFactory.GameObjectType.INVALID; mOffsetX = 0.0f; mOffsetY = 0.0f; mVelocityX = 0.0f; mVelocityY = 0.0f; mDelayBetweenShots = 0.0f; mProjectilesInSet = 0; mDelayBetweenSets = 0.0f; mLastProjectileTime = 0.0f; mSetStartedTime = -1.0f; mLaunchedCount = 0; mSetCount = 0; mSetsPerActivation = -1; mProjectilesInSet = 0; mDelayBeforeFirstSet = 0.0f; mTrackProjectiles = false; mMaxTrackedProjectiles = 0; mTrackedProjectileCount = 0; mThetaError = 0.0f; mShootSound = null; } @Override public void update(float timeDelta, BaseObject parent) { GameObject parentObject = (GameObject) parent; final TimeSystem time = sSystemRegistry.timeSystem; final float gameTime = time.getGameTime(); if (mTrackedProjectileCount < mMaxTrackedProjectiles || !mTrackProjectiles) { if (parentObject.getCurrentAction() == mRequiredAction || mRequiredAction == ActionType.INVALID) { if (mSetStartedTime == -1.0f) { mLaunchedCount = 0; mLastProjectileTime = 0.0f; mSetStartedTime = gameTime; } final float setDelay = mSetCount > 0 ? mDelayBetweenSets : mDelayBeforeFirstSet; if (gameTime - mSetStartedTime >= setDelay && (mSetCount < mSetsPerActivation || mSetsPerActivation == -1)) { // We can start shooting. final float timeSinceLastShot = gameTime - mLastProjectileTime; if (timeSinceLastShot >= mDelayBetweenShots) { launch(parentObject); mLastProjectileTime = gameTime; if (mLaunchedCount >= mProjectilesInSet && mProjectilesInSet > 0) { mSetStartedTime = -1.0f; mSetCount++; } } } } else { // Force the timer to start counting when the right action is activated. mSetStartedTime = -1.0f; mSetCount = 0; } } } private void launch(GameObject parentObject) { mLaunchedCount++; GameObjectFactory factory = sSystemRegistry.gameObjectFactory; GameObjectManager manager = sSystemRegistry.gameObjectManager; if (factory != null && manager != null) { float offsetX = mOffsetX; float offsetY = mOffsetY; boolean flip = false; if (parentObject.facingDirection.x < 0.0f) { offsetX = parentObject.width - mOffsetX; flip = true; } if (parentObject.facingDirection.y < 0.0f) { offsetY = parentObject.height - mOffsetY; } final float x = parentObject.getPosition().x + offsetX; final float y = parentObject.getPosition().y + offsetY; GameObject object = factory.spawn(mObjectTypeToSpawn, x, y, flip); if (object != null) { mWorkingVector.set(1.0f, 1.0f); if (mThetaError > 0.0f) { final float angle = (float)(Math.random() * mThetaError * Math.PI * 2.0f); mWorkingVector.x = (float)Math.sin(angle); mWorkingVector.y = (float)Math.cos(angle); if (Utils.close(mWorkingVector.length2(), 0.0f)) { mWorkingVector.set(1.0f, 1.0f); } } mWorkingVector.x *= flip ? -mVelocityX : mVelocityX; mWorkingVector.y *= mVelocityY; object.getVelocity().set(mWorkingVector); object.getTargetVelocity().set(mWorkingVector); // Center the projectile on the spawn point. object.getPosition().x -= object.width / 2.0f; object.getPosition().y -= object.height / 2.0f; if (mTrackProjectiles) { object.commitUpdates(); LifetimeComponent projectileLife = object.findByClass(LifetimeComponent.class); if (projectileLife != null) { projectileLife.setTrackingSpawner(this); mTrackedProjectileCount++; } } manager.add(object); if (mShootSound != null) { SoundSystem sound = sSystemRegistry.soundSystem; if (sound != null) { sound.play(mShootSound, false, SoundSystem.PRIORITY_NORMAL); } } } } } public final void setObjectTypeToSpawn(GameObjectFactory.GameObjectType objectTypeToSpawn) { mObjectTypeToSpawn = objectTypeToSpawn; } public final void setOffsetX(float offsetX) { mOffsetX = offsetX; } public final void setOffsetY(float offsetY) { mOffsetY = offsetY; } public final void setVelocityX(float velocityX) { mVelocityX = velocityX; } public final void setVelocityY(float velocityY) { mVelocityY = velocityY; } public final void setRequiredAction(GameObject.ActionType requiredAction) { mRequiredAction = requiredAction; } public final void setDelayBetweenShots(float launchDelay) { mDelayBetweenShots = launchDelay; } public final void setDelayBetweenSets(float delayBetweenSets) { mDelayBetweenSets = delayBetweenSets; } public final void setDelayBeforeFirstSet(float delayBeforeFirstSet) { mDelayBeforeFirstSet = delayBeforeFirstSet; } public final void setShotsPerSet(int shotCount) { mProjectilesInSet = shotCount; } public final void setSetsPerActivation(int setCount) { mSetsPerActivation = setCount; } public final void enableProjectileTracking(int max) { mMaxTrackedProjectiles = max; mTrackProjectiles = true; } public final void disableProjectileTracking() { mMaxTrackedProjectiles = 0; mTrackProjectiles = false; } public final void trackedProjectileDestroyed() { assert mTrackProjectiles; if (mTrackedProjectileCount == mMaxTrackedProjectiles) { // Let's restart the set. mSetStartedTime = -1.0f; mSetCount = 0; } mTrackedProjectileCount--; } public final void setThetaError(float error) { mThetaError = error; } public final void setShootSound(SoundSystem.Sound shoot) { mShootSound = shoot; } }