1cfd74d65d832137e20e193c960802afba73b5d38sm/* 23c1e67e433728684b5f228c5d4f3e5b1457bb271sm * Copyright (C) 2010 The Android Open Source Project 3cfd74d65d832137e20e193c960802afba73b5d38sm * 4cfd74d65d832137e20e193c960802afba73b5d38sm * Licensed under the Apache License, Version 2.0 (the "License"); 5cfd74d65d832137e20e193c960802afba73b5d38sm * you may not use this file except in compliance with the License. 6cfd74d65d832137e20e193c960802afba73b5d38sm * You may obtain a copy of the License at 7cfd74d65d832137e20e193c960802afba73b5d38sm * 8cfd74d65d832137e20e193c960802afba73b5d38sm * http://www.apache.org/licenses/LICENSE-2.0 9cfd74d65d832137e20e193c960802afba73b5d38sm * 10cfd74d65d832137e20e193c960802afba73b5d38sm * Unless required by applicable law or agreed to in writing, software 11cfd74d65d832137e20e193c960802afba73b5d38sm * distributed under the License is distributed on an "AS IS" BASIS, 12cfd74d65d832137e20e193c960802afba73b5d38sm * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cfd74d65d832137e20e193c960802afba73b5d38sm * See the License for the specific language governing permissions and 14cfd74d65d832137e20e193c960802afba73b5d38sm * limitations under the License. 15cfd74d65d832137e20e193c960802afba73b5d38sm */ 16cfd74d65d832137e20e193c960802afba73b5d38sm 17cfd74d65d832137e20e193c960802afba73b5d38smpackage com.replica.replicaisland; 18cfd74d65d832137e20e193c960802afba73b5d38sm 19cfd74d65d832137e20e193c960802afba73b5d38smimport com.replica.replicaisland.GameObject.ActionType; 20cfd74d65d832137e20e193c960802afba73b5d38sm 21cfd74d65d832137e20e193c960802afba73b5d38sm/** 22cfd74d65d832137e20e193c960802afba73b5d38sm * A component that allows an object to spawn other objects and apply velocity to them at 23cfd74d65d832137e20e193c960802afba73b5d38sm * specific intervals. Can be used to launch projectiles, particle effects, or any other type 24cfd74d65d832137e20e193c960802afba73b5d38sm * of game object. 25cfd74d65d832137e20e193c960802afba73b5d38sm */ 26cfd74d65d832137e20e193c960802afba73b5d38smpublic class LaunchProjectileComponent extends GameComponent { 27cfd74d65d832137e20e193c960802afba73b5d38sm private GameObjectFactory.GameObjectType mObjectTypeToSpawn; 28cfd74d65d832137e20e193c960802afba73b5d38sm private float mOffsetX; 29cfd74d65d832137e20e193c960802afba73b5d38sm private float mOffsetY; 30cfd74d65d832137e20e193c960802afba73b5d38sm private float mVelocityX; 31cfd74d65d832137e20e193c960802afba73b5d38sm private float mVelocityY; 32cfd74d65d832137e20e193c960802afba73b5d38sm private float mThetaError; 33cfd74d65d832137e20e193c960802afba73b5d38sm private GameObject.ActionType mRequiredAction; 34cfd74d65d832137e20e193c960802afba73b5d38sm private float mDelayBetweenShots; 35cfd74d65d832137e20e193c960802afba73b5d38sm private int mProjectilesInSet; 36cfd74d65d832137e20e193c960802afba73b5d38sm private float mDelayBetweenSets; 37cfd74d65d832137e20e193c960802afba73b5d38sm private int mSetsPerActivation; 38cfd74d65d832137e20e193c960802afba73b5d38sm private float mDelayBeforeFirstSet; 39cfd74d65d832137e20e193c960802afba73b5d38sm 40cfd74d65d832137e20e193c960802afba73b5d38sm private float mLastProjectileTime; 41cfd74d65d832137e20e193c960802afba73b5d38sm private float mSetStartedTime; 42cfd74d65d832137e20e193c960802afba73b5d38sm private int mLaunchedCount; 43cfd74d65d832137e20e193c960802afba73b5d38sm private int mSetCount; 44cfd74d65d832137e20e193c960802afba73b5d38sm 45cfd74d65d832137e20e193c960802afba73b5d38sm private boolean mTrackProjectiles; 46cfd74d65d832137e20e193c960802afba73b5d38sm private int mMaxTrackedProjectiles; 47cfd74d65d832137e20e193c960802afba73b5d38sm private int mTrackedProjectileCount; 48cfd74d65d832137e20e193c960802afba73b5d38sm 49cfd74d65d832137e20e193c960802afba73b5d38sm private Vector2 mWorkingVector; 50cfd74d65d832137e20e193c960802afba73b5d38sm 51cfd74d65d832137e20e193c960802afba73b5d38sm private SoundSystem.Sound mShootSound; 52cfd74d65d832137e20e193c960802afba73b5d38sm 53cfd74d65d832137e20e193c960802afba73b5d38sm 54cfd74d65d832137e20e193c960802afba73b5d38sm public LaunchProjectileComponent() { 55cfd74d65d832137e20e193c960802afba73b5d38sm super(); 56cfd74d65d832137e20e193c960802afba73b5d38sm setPhase(ComponentPhases.POST_COLLISION.ordinal()); 57cfd74d65d832137e20e193c960802afba73b5d38sm mWorkingVector = new Vector2(); 58cfd74d65d832137e20e193c960802afba73b5d38sm reset(); 59cfd74d65d832137e20e193c960802afba73b5d38sm } 60cfd74d65d832137e20e193c960802afba73b5d38sm 61cfd74d65d832137e20e193c960802afba73b5d38sm @Override 62cfd74d65d832137e20e193c960802afba73b5d38sm public void reset() { 63cfd74d65d832137e20e193c960802afba73b5d38sm mRequiredAction = ActionType.INVALID; 64cfd74d65d832137e20e193c960802afba73b5d38sm mObjectTypeToSpawn = GameObjectFactory.GameObjectType.INVALID; 65cfd74d65d832137e20e193c960802afba73b5d38sm mOffsetX = 0.0f; 66cfd74d65d832137e20e193c960802afba73b5d38sm mOffsetY = 0.0f; 67cfd74d65d832137e20e193c960802afba73b5d38sm mVelocityX = 0.0f; 68cfd74d65d832137e20e193c960802afba73b5d38sm mVelocityY = 0.0f; 69cfd74d65d832137e20e193c960802afba73b5d38sm mDelayBetweenShots = 0.0f; 70cfd74d65d832137e20e193c960802afba73b5d38sm mProjectilesInSet = 0; 71cfd74d65d832137e20e193c960802afba73b5d38sm mDelayBetweenSets = 0.0f; 72cfd74d65d832137e20e193c960802afba73b5d38sm mLastProjectileTime = 0.0f; 73cfd74d65d832137e20e193c960802afba73b5d38sm mSetStartedTime = -1.0f; 74cfd74d65d832137e20e193c960802afba73b5d38sm mLaunchedCount = 0; 75cfd74d65d832137e20e193c960802afba73b5d38sm mSetCount = 0; 76cfd74d65d832137e20e193c960802afba73b5d38sm mSetsPerActivation = -1; 77cfd74d65d832137e20e193c960802afba73b5d38sm mProjectilesInSet = 0; 78cfd74d65d832137e20e193c960802afba73b5d38sm mDelayBeforeFirstSet = 0.0f; 79cfd74d65d832137e20e193c960802afba73b5d38sm mTrackProjectiles = false; 80cfd74d65d832137e20e193c960802afba73b5d38sm mMaxTrackedProjectiles = 0; 81cfd74d65d832137e20e193c960802afba73b5d38sm mTrackedProjectileCount = 0; 82cfd74d65d832137e20e193c960802afba73b5d38sm mThetaError = 0.0f; 83cfd74d65d832137e20e193c960802afba73b5d38sm mShootSound = null; 84cfd74d65d832137e20e193c960802afba73b5d38sm } 85cfd74d65d832137e20e193c960802afba73b5d38sm 86cfd74d65d832137e20e193c960802afba73b5d38sm @Override 87cfd74d65d832137e20e193c960802afba73b5d38sm public void update(float timeDelta, BaseObject parent) { 88cfd74d65d832137e20e193c960802afba73b5d38sm GameObject parentObject = (GameObject) parent; 89cfd74d65d832137e20e193c960802afba73b5d38sm 90cfd74d65d832137e20e193c960802afba73b5d38sm final TimeSystem time = sSystemRegistry.timeSystem; 91cfd74d65d832137e20e193c960802afba73b5d38sm final float gameTime = time.getGameTime(); 92cfd74d65d832137e20e193c960802afba73b5d38sm 93cfd74d65d832137e20e193c960802afba73b5d38sm if (mTrackedProjectileCount < mMaxTrackedProjectiles || !mTrackProjectiles) { 94cfd74d65d832137e20e193c960802afba73b5d38sm if (parentObject.getCurrentAction() == mRequiredAction 95cfd74d65d832137e20e193c960802afba73b5d38sm || mRequiredAction == ActionType.INVALID) { 96cfd74d65d832137e20e193c960802afba73b5d38sm 97cfd74d65d832137e20e193c960802afba73b5d38sm if (mSetStartedTime == -1.0f) { 98cfd74d65d832137e20e193c960802afba73b5d38sm mLaunchedCount = 0; 99cfd74d65d832137e20e193c960802afba73b5d38sm mLastProjectileTime = 0.0f; 100cfd74d65d832137e20e193c960802afba73b5d38sm mSetStartedTime = gameTime; 101cfd74d65d832137e20e193c960802afba73b5d38sm } 102cfd74d65d832137e20e193c960802afba73b5d38sm 103cfd74d65d832137e20e193c960802afba73b5d38sm final float setDelay = mSetCount > 0 ? mDelayBetweenSets : mDelayBeforeFirstSet; 104cfd74d65d832137e20e193c960802afba73b5d38sm 105cfd74d65d832137e20e193c960802afba73b5d38sm if (gameTime - mSetStartedTime >= setDelay && 106cfd74d65d832137e20e193c960802afba73b5d38sm (mSetCount < mSetsPerActivation || mSetsPerActivation == -1)) { 107cfd74d65d832137e20e193c960802afba73b5d38sm // We can start shooting. 108cfd74d65d832137e20e193c960802afba73b5d38sm final float timeSinceLastShot = gameTime - mLastProjectileTime; 109cfd74d65d832137e20e193c960802afba73b5d38sm 110cfd74d65d832137e20e193c960802afba73b5d38sm if (timeSinceLastShot >= mDelayBetweenShots) { 111cfd74d65d832137e20e193c960802afba73b5d38sm 112cfd74d65d832137e20e193c960802afba73b5d38sm launch(parentObject); 113cfd74d65d832137e20e193c960802afba73b5d38sm mLastProjectileTime = gameTime; 114cfd74d65d832137e20e193c960802afba73b5d38sm 115cfd74d65d832137e20e193c960802afba73b5d38sm if (mLaunchedCount >= mProjectilesInSet && mProjectilesInSet > 0) { 116cfd74d65d832137e20e193c960802afba73b5d38sm mSetStartedTime = -1.0f; 117cfd74d65d832137e20e193c960802afba73b5d38sm mSetCount++; 118cfd74d65d832137e20e193c960802afba73b5d38sm } 119cfd74d65d832137e20e193c960802afba73b5d38sm } 120cfd74d65d832137e20e193c960802afba73b5d38sm } 121cfd74d65d832137e20e193c960802afba73b5d38sm } else { 122cfd74d65d832137e20e193c960802afba73b5d38sm // Force the timer to start counting when the right action is activated. 123cfd74d65d832137e20e193c960802afba73b5d38sm mSetStartedTime = -1.0f; 124cfd74d65d832137e20e193c960802afba73b5d38sm mSetCount = 0; 125cfd74d65d832137e20e193c960802afba73b5d38sm } 126cfd74d65d832137e20e193c960802afba73b5d38sm } 127cfd74d65d832137e20e193c960802afba73b5d38sm } 128cfd74d65d832137e20e193c960802afba73b5d38sm 129cfd74d65d832137e20e193c960802afba73b5d38sm private void launch(GameObject parentObject) { 130cfd74d65d832137e20e193c960802afba73b5d38sm mLaunchedCount++; 131cfd74d65d832137e20e193c960802afba73b5d38sm GameObjectFactory factory = sSystemRegistry.gameObjectFactory; 132cfd74d65d832137e20e193c960802afba73b5d38sm GameObjectManager manager = sSystemRegistry.gameObjectManager; 133cfd74d65d832137e20e193c960802afba73b5d38sm if (factory != null && manager != null) { 134cfd74d65d832137e20e193c960802afba73b5d38sm float offsetX = mOffsetX; 135cfd74d65d832137e20e193c960802afba73b5d38sm float offsetY = mOffsetY; 136cfd74d65d832137e20e193c960802afba73b5d38sm boolean flip = false; 137cfd74d65d832137e20e193c960802afba73b5d38sm if (parentObject.facingDirection.x < 0.0f) { 138cfd74d65d832137e20e193c960802afba73b5d38sm offsetX = parentObject.width - mOffsetX; 139cfd74d65d832137e20e193c960802afba73b5d38sm flip = true; 140cfd74d65d832137e20e193c960802afba73b5d38sm } 141cfd74d65d832137e20e193c960802afba73b5d38sm 142cfd74d65d832137e20e193c960802afba73b5d38sm if (parentObject.facingDirection.y < 0.0f) { 143cfd74d65d832137e20e193c960802afba73b5d38sm offsetY = parentObject.height - mOffsetY; 144cfd74d65d832137e20e193c960802afba73b5d38sm } 145cfd74d65d832137e20e193c960802afba73b5d38sm 146cfd74d65d832137e20e193c960802afba73b5d38sm final float x = parentObject.getPosition().x + offsetX; 147cfd74d65d832137e20e193c960802afba73b5d38sm final float y = parentObject.getPosition().y + offsetY; 148cfd74d65d832137e20e193c960802afba73b5d38sm GameObject object = factory.spawn(mObjectTypeToSpawn, x, y, flip); 1499d4cc2572d37983607df38b0f4216ed76ac51814sm if (object != null) { 1509d4cc2572d37983607df38b0f4216ed76ac51814sm mWorkingVector.set(1.0f, 1.0f); 1519d4cc2572d37983607df38b0f4216ed76ac51814sm if (mThetaError > 0.0f) { 1529d4cc2572d37983607df38b0f4216ed76ac51814sm final float angle = (float)(Math.random() * mThetaError * Math.PI * 2.0f); 1539d4cc2572d37983607df38b0f4216ed76ac51814sm mWorkingVector.x = (float)Math.sin(angle); 1549d4cc2572d37983607df38b0f4216ed76ac51814sm mWorkingVector.y = (float)Math.cos(angle); 1559d4cc2572d37983607df38b0f4216ed76ac51814sm if (Utils.close(mWorkingVector.length2(), 0.0f)) { 1569d4cc2572d37983607df38b0f4216ed76ac51814sm mWorkingVector.set(1.0f, 1.0f); 1579d4cc2572d37983607df38b0f4216ed76ac51814sm } 1589d4cc2572d37983607df38b0f4216ed76ac51814sm } 1599d4cc2572d37983607df38b0f4216ed76ac51814sm mWorkingVector.x *= flip ? -mVelocityX : mVelocityX; 1609d4cc2572d37983607df38b0f4216ed76ac51814sm mWorkingVector.y *= mVelocityY; 1619d4cc2572d37983607df38b0f4216ed76ac51814sm 1629d4cc2572d37983607df38b0f4216ed76ac51814sm object.getVelocity().set(mWorkingVector); 1639d4cc2572d37983607df38b0f4216ed76ac51814sm object.getTargetVelocity().set(mWorkingVector); 1649d4cc2572d37983607df38b0f4216ed76ac51814sm // Center the projectile on the spawn point. 1659d4cc2572d37983607df38b0f4216ed76ac51814sm object.getPosition().x -= object.width / 2.0f; 1669d4cc2572d37983607df38b0f4216ed76ac51814sm object.getPosition().y -= object.height / 2.0f; 1679d4cc2572d37983607df38b0f4216ed76ac51814sm 1689d4cc2572d37983607df38b0f4216ed76ac51814sm 1699d4cc2572d37983607df38b0f4216ed76ac51814sm if (mTrackProjectiles) { 1709d4cc2572d37983607df38b0f4216ed76ac51814sm object.commitUpdates(); 1719d4cc2572d37983607df38b0f4216ed76ac51814sm LifetimeComponent projectileLife = object.findByClass(LifetimeComponent.class); 1729d4cc2572d37983607df38b0f4216ed76ac51814sm if (projectileLife != null) { 1739d4cc2572d37983607df38b0f4216ed76ac51814sm projectileLife.setTrackingSpawner(this); 1749d4cc2572d37983607df38b0f4216ed76ac51814sm mTrackedProjectileCount++; 1759d4cc2572d37983607df38b0f4216ed76ac51814sm } 1769d4cc2572d37983607df38b0f4216ed76ac51814sm } 1779d4cc2572d37983607df38b0f4216ed76ac51814sm manager.add(object); 1789d4cc2572d37983607df38b0f4216ed76ac51814sm 1799d4cc2572d37983607df38b0f4216ed76ac51814sm if (mShootSound != null) { 1809d4cc2572d37983607df38b0f4216ed76ac51814sm SoundSystem sound = sSystemRegistry.soundSystem; 1819d4cc2572d37983607df38b0f4216ed76ac51814sm if (sound != null) { 1829d4cc2572d37983607df38b0f4216ed76ac51814sm sound.play(mShootSound, false, SoundSystem.PRIORITY_NORMAL); 1839d4cc2572d37983607df38b0f4216ed76ac51814sm } 1849d4cc2572d37983607df38b0f4216ed76ac51814sm } 185cfd74d65d832137e20e193c960802afba73b5d38sm } 186cfd74d65d832137e20e193c960802afba73b5d38sm } 187cfd74d65d832137e20e193c960802afba73b5d38sm 188cfd74d65d832137e20e193c960802afba73b5d38sm 189cfd74d65d832137e20e193c960802afba73b5d38sm } 190cfd74d65d832137e20e193c960802afba73b5d38sm 191cfd74d65d832137e20e193c960802afba73b5d38sm public final void setObjectTypeToSpawn(GameObjectFactory.GameObjectType objectTypeToSpawn) { 192cfd74d65d832137e20e193c960802afba73b5d38sm mObjectTypeToSpawn = objectTypeToSpawn; 193cfd74d65d832137e20e193c960802afba73b5d38sm } 194cfd74d65d832137e20e193c960802afba73b5d38sm 195cfd74d65d832137e20e193c960802afba73b5d38sm public final void setOffsetX(float offsetX) { 196cfd74d65d832137e20e193c960802afba73b5d38sm mOffsetX = offsetX; 197cfd74d65d832137e20e193c960802afba73b5d38sm } 198cfd74d65d832137e20e193c960802afba73b5d38sm 199cfd74d65d832137e20e193c960802afba73b5d38sm public final void setOffsetY(float offsetY) { 200cfd74d65d832137e20e193c960802afba73b5d38sm mOffsetY = offsetY; 201cfd74d65d832137e20e193c960802afba73b5d38sm } 202cfd74d65d832137e20e193c960802afba73b5d38sm 203cfd74d65d832137e20e193c960802afba73b5d38sm public final void setVelocityX(float velocityX) { 204cfd74d65d832137e20e193c960802afba73b5d38sm mVelocityX = velocityX; 205cfd74d65d832137e20e193c960802afba73b5d38sm } 206cfd74d65d832137e20e193c960802afba73b5d38sm 207cfd74d65d832137e20e193c960802afba73b5d38sm public final void setVelocityY(float velocityY) { 208cfd74d65d832137e20e193c960802afba73b5d38sm mVelocityY = velocityY; 209cfd74d65d832137e20e193c960802afba73b5d38sm } 210cfd74d65d832137e20e193c960802afba73b5d38sm 211cfd74d65d832137e20e193c960802afba73b5d38sm public final void setRequiredAction(GameObject.ActionType requiredAction) { 212cfd74d65d832137e20e193c960802afba73b5d38sm mRequiredAction = requiredAction; 213cfd74d65d832137e20e193c960802afba73b5d38sm } 214cfd74d65d832137e20e193c960802afba73b5d38sm 215cfd74d65d832137e20e193c960802afba73b5d38sm public final void setDelayBetweenShots(float launchDelay) { 216cfd74d65d832137e20e193c960802afba73b5d38sm mDelayBetweenShots = launchDelay; 217cfd74d65d832137e20e193c960802afba73b5d38sm } 218cfd74d65d832137e20e193c960802afba73b5d38sm 219cfd74d65d832137e20e193c960802afba73b5d38sm public final void setDelayBetweenSets(float delayBetweenSets) { 220cfd74d65d832137e20e193c960802afba73b5d38sm mDelayBetweenSets = delayBetweenSets; 221cfd74d65d832137e20e193c960802afba73b5d38sm } 222cfd74d65d832137e20e193c960802afba73b5d38sm 223cfd74d65d832137e20e193c960802afba73b5d38sm public final void setDelayBeforeFirstSet(float delayBeforeFirstSet) { 224cfd74d65d832137e20e193c960802afba73b5d38sm mDelayBeforeFirstSet = delayBeforeFirstSet; 225cfd74d65d832137e20e193c960802afba73b5d38sm } 226cfd74d65d832137e20e193c960802afba73b5d38sm 227cfd74d65d832137e20e193c960802afba73b5d38sm public final void setShotsPerSet(int shotCount) { 228cfd74d65d832137e20e193c960802afba73b5d38sm mProjectilesInSet = shotCount; 229cfd74d65d832137e20e193c960802afba73b5d38sm } 230cfd74d65d832137e20e193c960802afba73b5d38sm 231cfd74d65d832137e20e193c960802afba73b5d38sm public final void setSetsPerActivation(int setCount) { 232cfd74d65d832137e20e193c960802afba73b5d38sm mSetsPerActivation = setCount; 233cfd74d65d832137e20e193c960802afba73b5d38sm } 234cfd74d65d832137e20e193c960802afba73b5d38sm 235cfd74d65d832137e20e193c960802afba73b5d38sm public final void enableProjectileTracking(int max) { 236cfd74d65d832137e20e193c960802afba73b5d38sm mMaxTrackedProjectiles = max; 237cfd74d65d832137e20e193c960802afba73b5d38sm mTrackProjectiles = true; 238cfd74d65d832137e20e193c960802afba73b5d38sm } 239cfd74d65d832137e20e193c960802afba73b5d38sm 2402b1168acefb6a4104bb7f008df6ac51fcd1de7ecsm public final void disableProjectileTracking() { 2412b1168acefb6a4104bb7f008df6ac51fcd1de7ecsm mMaxTrackedProjectiles = 0; 2422b1168acefb6a4104bb7f008df6ac51fcd1de7ecsm mTrackProjectiles = false; 2432b1168acefb6a4104bb7f008df6ac51fcd1de7ecsm } 2442b1168acefb6a4104bb7f008df6ac51fcd1de7ecsm 245cfd74d65d832137e20e193c960802afba73b5d38sm public final void trackedProjectileDestroyed() { 246cfd74d65d832137e20e193c960802afba73b5d38sm assert mTrackProjectiles; 247cfd74d65d832137e20e193c960802afba73b5d38sm if (mTrackedProjectileCount == mMaxTrackedProjectiles) { 248cfd74d65d832137e20e193c960802afba73b5d38sm // Let's restart the set. 249cfd74d65d832137e20e193c960802afba73b5d38sm mSetStartedTime = -1.0f; 250cfd74d65d832137e20e193c960802afba73b5d38sm mSetCount = 0; 251cfd74d65d832137e20e193c960802afba73b5d38sm } 252cfd74d65d832137e20e193c960802afba73b5d38sm mTrackedProjectileCount--; 253cfd74d65d832137e20e193c960802afba73b5d38sm } 254cfd74d65d832137e20e193c960802afba73b5d38sm 255cfd74d65d832137e20e193c960802afba73b5d38sm public final void setThetaError(float error) { 256cfd74d65d832137e20e193c960802afba73b5d38sm mThetaError = error; 257cfd74d65d832137e20e193c960802afba73b5d38sm } 258cfd74d65d832137e20e193c960802afba73b5d38sm 259cfd74d65d832137e20e193c960802afba73b5d38sm public final void setShootSound(SoundSystem.Sound shoot) { 260cfd74d65d832137e20e193c960802afba73b5d38sm mShootSound = shoot; 261cfd74d65d832137e20e193c960802afba73b5d38sm } 262cfd74d65d832137e20e193c960802afba73b5d38sm 263cfd74d65d832137e20e193c960802afba73b5d38sm} 264