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 java.util.Comparator; 20cfd74d65d832137e20e193c960802afba73b5d38sm 21cfd74d65d832137e20e193c960802afba73b5d38smimport com.replica.replicaisland.CollisionParameters.HitType; 22cfd74d65d832137e20e193c960802afba73b5d38sm 23cfd74d65d832137e20e193c960802afba73b5d38sm/** 24cfd74d65d832137e20e193c960802afba73b5d38sm * A system for calculating collisions between moving game objects. This system accepts collision 25cfd74d65d832137e20e193c960802afba73b5d38sm * volumes from game objects each frame and performs a series of tests to see which of them 26cfd74d65d832137e20e193c960802afba73b5d38sm * overlap. Collisions are only considered between offending "attack" volumes and receiving 27cfd74d65d832137e20e193c960802afba73b5d38sm * "vulnerability" volumes. This implementation works by using a sweep-and-prune algorithm: 28cfd74d65d832137e20e193c960802afba73b5d38sm * objects to be considered are sorted in the x axis and then compared in one dimension for 29cfd74d65d832137e20e193c960802afba73b5d38sm * overlaps. A bounding volume that encompasses all attack and vulnerability volumes is used for 30cfd74d65d832137e20e193c960802afba73b5d38sm * this test, and when an intersection is found the actual offending and receiving volumes are 31cfd74d65d832137e20e193c960802afba73b5d38sm * compared. If an intersection is detected both objects receive notification via a 32cfd74d65d832137e20e193c960802afba73b5d38sm * HitReactionComponent, if one has been specified. 33cfd74d65d832137e20e193c960802afba73b5d38sm */ 34cfd74d65d832137e20e193c960802afba73b5d38smpublic class GameObjectCollisionSystem extends BaseObject { 359d4cc2572d37983607df38b0f4216ed76ac51814sm private static final int MAX_COLLIDING_OBJECTS = 256; 369d4cc2572d37983607df38b0f4216ed76ac51814sm private static final int COLLISION_RECORD_POOL_SIZE = 256; 37cfd74d65d832137e20e193c960802afba73b5d38sm private static final CollisionVolumeComparator sCollisionVolumeComparator 38cfd74d65d832137e20e193c960802afba73b5d38sm = new CollisionVolumeComparator(); 39cfd74d65d832137e20e193c960802afba73b5d38sm private static CollisionVolume.FlipInfo sFlip = new CollisionVolume.FlipInfo(); 40cfd74d65d832137e20e193c960802afba73b5d38sm private static CollisionVolume.FlipInfo sOtherFlip = new CollisionVolume.FlipInfo(); 41cfd74d65d832137e20e193c960802afba73b5d38sm 42cfd74d65d832137e20e193c960802afba73b5d38sm FixedSizeArray<CollisionVolumeRecord> mObjects; 43cfd74d65d832137e20e193c960802afba73b5d38sm CollisionVolumeRecordPool mRecordPool; 44cfd74d65d832137e20e193c960802afba73b5d38sm private boolean mDrawDebugBoundingVolume = false; 45cfd74d65d832137e20e193c960802afba73b5d38sm private boolean mDrawDebugCollisionVolumes = false; 46cfd74d65d832137e20e193c960802afba73b5d38sm 47cfd74d65d832137e20e193c960802afba73b5d38sm 48cfd74d65d832137e20e193c960802afba73b5d38sm public GameObjectCollisionSystem() { 49cfd74d65d832137e20e193c960802afba73b5d38sm super(); 50cfd74d65d832137e20e193c960802afba73b5d38sm mObjects = new FixedSizeArray<CollisionVolumeRecord>(MAX_COLLIDING_OBJECTS); 51cfd74d65d832137e20e193c960802afba73b5d38sm mObjects.setComparator(sCollisionVolumeComparator); 52cfd74d65d832137e20e193c960802afba73b5d38sm //mObjects.setSorter(new ShellSorter<CollisionVolumeRecord>()); 53cfd74d65d832137e20e193c960802afba73b5d38sm mRecordPool = new CollisionVolumeRecordPool(COLLISION_RECORD_POOL_SIZE); 54cfd74d65d832137e20e193c960802afba73b5d38sm } 55cfd74d65d832137e20e193c960802afba73b5d38sm 56cfd74d65d832137e20e193c960802afba73b5d38sm @Override 57cfd74d65d832137e20e193c960802afba73b5d38sm public void reset() { 58cfd74d65d832137e20e193c960802afba73b5d38sm final int count = mObjects.getCount(); 59cfd74d65d832137e20e193c960802afba73b5d38sm 60cfd74d65d832137e20e193c960802afba73b5d38sm for (int x = 0; x < count; x++) { 61cfd74d65d832137e20e193c960802afba73b5d38sm mRecordPool.release(mObjects.get(x)); 62cfd74d65d832137e20e193c960802afba73b5d38sm } 63cfd74d65d832137e20e193c960802afba73b5d38sm mObjects.clear(); 64cfd74d65d832137e20e193c960802afba73b5d38sm 65cfd74d65d832137e20e193c960802afba73b5d38sm mDrawDebugBoundingVolume = false; 66cfd74d65d832137e20e193c960802afba73b5d38sm mDrawDebugCollisionVolumes = false; 67cfd74d65d832137e20e193c960802afba73b5d38sm } 68cfd74d65d832137e20e193c960802afba73b5d38sm 69cfd74d65d832137e20e193c960802afba73b5d38sm /** 70cfd74d65d832137e20e193c960802afba73b5d38sm * Adds a game object, and its related volumes, to the dynamic collision world for one frame. 71cfd74d65d832137e20e193c960802afba73b5d38sm * Once registered for collisions the object may damage other objects via attack volumes or 72cfd74d65d832137e20e193c960802afba73b5d38sm * receive damage from other volumes via vulnerability volumes. 73cfd74d65d832137e20e193c960802afba73b5d38sm * @param object The object to consider for collision. 74cfd74d65d832137e20e193c960802afba73b5d38sm * @param reactionComponent A HitReactionComponent to notify when an intersection is calculated. 75cfd74d65d832137e20e193c960802afba73b5d38sm * If null, the intersection will still occur and no notification will be sent. 76cfd74d65d832137e20e193c960802afba73b5d38sm * @param boundingVolume A volume that describes the game object in space. It should encompass 77cfd74d65d832137e20e193c960802afba73b5d38sm * all of the attack and vulnerability volumes. 78cfd74d65d832137e20e193c960802afba73b5d38sm * @param attackVolumes A list of volumes that can hit other game objects. May be null. 79cfd74d65d832137e20e193c960802afba73b5d38sm * @param vulnerabilityVolumes A list of volumes that can receive hits from other game objects. 80cfd74d65d832137e20e193c960802afba73b5d38sm * May be null. 81cfd74d65d832137e20e193c960802afba73b5d38sm */ 82cfd74d65d832137e20e193c960802afba73b5d38sm public void registerForCollisions(GameObject object, 83cfd74d65d832137e20e193c960802afba73b5d38sm HitReactionComponent reactionComponent, 84cfd74d65d832137e20e193c960802afba73b5d38sm CollisionVolume boundingVolume, 85cfd74d65d832137e20e193c960802afba73b5d38sm FixedSizeArray<CollisionVolume> attackVolumes, 86cfd74d65d832137e20e193c960802afba73b5d38sm FixedSizeArray<CollisionVolume> vulnerabilityVolumes) { 87cfd74d65d832137e20e193c960802afba73b5d38sm CollisionVolumeRecord record = mRecordPool.allocate(); 88cfd74d65d832137e20e193c960802afba73b5d38sm if (record != null && object != null && boundingVolume != null 89cfd74d65d832137e20e193c960802afba73b5d38sm && (attackVolumes != null || vulnerabilityVolumes != null)) { 90cfd74d65d832137e20e193c960802afba73b5d38sm record.object = object; 91cfd74d65d832137e20e193c960802afba73b5d38sm record.boundingVolume = boundingVolume; 92cfd74d65d832137e20e193c960802afba73b5d38sm record.attackVolumes = attackVolumes; 93cfd74d65d832137e20e193c960802afba73b5d38sm record.vulnerabilityVolumes = vulnerabilityVolumes; 94cfd74d65d832137e20e193c960802afba73b5d38sm record.reactionComponent = reactionComponent; 95cfd74d65d832137e20e193c960802afba73b5d38sm mObjects.add(record); 96cfd74d65d832137e20e193c960802afba73b5d38sm } 97cfd74d65d832137e20e193c960802afba73b5d38sm } 98cfd74d65d832137e20e193c960802afba73b5d38sm 99cfd74d65d832137e20e193c960802afba73b5d38sm @Override 100cfd74d65d832137e20e193c960802afba73b5d38sm public void update(float timeDelta, BaseObject parent) { 101cfd74d65d832137e20e193c960802afba73b5d38sm // Sort the objects by their x position. 102cfd74d65d832137e20e193c960802afba73b5d38sm mObjects.sort(true); 103cfd74d65d832137e20e193c960802afba73b5d38sm 104cfd74d65d832137e20e193c960802afba73b5d38sm final int count = mObjects.getCount(); 105cfd74d65d832137e20e193c960802afba73b5d38sm for (int x = 0; x < count; x++) { 106cfd74d65d832137e20e193c960802afba73b5d38sm final CollisionVolumeRecord record = mObjects.get(x); 107cfd74d65d832137e20e193c960802afba73b5d38sm final Vector2 position = record.object.getPosition(); 108cfd74d65d832137e20e193c960802afba73b5d38sm sFlip.flipX = (record.object.facingDirection.x < 0.0f); 109cfd74d65d832137e20e193c960802afba73b5d38sm sFlip.flipY = (record.object.facingDirection.y < 0.0f); 110cfd74d65d832137e20e193c960802afba73b5d38sm sFlip.parentWidth = record.object.width; 111cfd74d65d832137e20e193c960802afba73b5d38sm sFlip.parentHeight = record.object.height; 112cfd74d65d832137e20e193c960802afba73b5d38sm 113cfd74d65d832137e20e193c960802afba73b5d38sm if (sSystemRegistry.debugSystem != null) { 114cfd74d65d832137e20e193c960802afba73b5d38sm drawDebugVolumes(record); 115cfd74d65d832137e20e193c960802afba73b5d38sm } 116cfd74d65d832137e20e193c960802afba73b5d38sm 117cfd74d65d832137e20e193c960802afba73b5d38sm final float maxX = record.boundingVolume.getMaxXPosition(sFlip) + position.x; 118cfd74d65d832137e20e193c960802afba73b5d38sm for (int y = x + 1; y < count; y++) { 119cfd74d65d832137e20e193c960802afba73b5d38sm final CollisionVolumeRecord other = mObjects.get(y); 120cfd74d65d832137e20e193c960802afba73b5d38sm final Vector2 otherPosition = other.object.getPosition(); 121cfd74d65d832137e20e193c960802afba73b5d38sm sOtherFlip.flipX = (other.object.facingDirection.x < 0.0f); 122cfd74d65d832137e20e193c960802afba73b5d38sm sOtherFlip.flipY = (other.object.facingDirection.y < 0.0f); 123cfd74d65d832137e20e193c960802afba73b5d38sm sOtherFlip.parentWidth = other.object.width; 124cfd74d65d832137e20e193c960802afba73b5d38sm sOtherFlip.parentHeight = other.object.height; 125cfd74d65d832137e20e193c960802afba73b5d38sm 126cfd74d65d832137e20e193c960802afba73b5d38sm if (otherPosition.x + other.boundingVolume.getMinXPosition(sOtherFlip) > maxX) { 127cfd74d65d832137e20e193c960802afba73b5d38sm // These objects can't possibly be colliding. And since the list is sorted, 128cfd74d65d832137e20e193c960802afba73b5d38sm // there are no potentially colliding objects after this object 129cfd74d65d832137e20e193c960802afba73b5d38sm // either, so we're done! 130cfd74d65d832137e20e193c960802afba73b5d38sm break; 131cfd74d65d832137e20e193c960802afba73b5d38sm } else { 132cfd74d65d832137e20e193c960802afba73b5d38sm final boolean testRequired = (record.attackVolumes != null && other.vulnerabilityVolumes != null) || 133cfd74d65d832137e20e193c960802afba73b5d38sm (record.vulnerabilityVolumes != null && other.attackVolumes != null); 134cfd74d65d832137e20e193c960802afba73b5d38sm if (testRequired && record.boundingVolume.intersects(position, sFlip, 135cfd74d65d832137e20e193c960802afba73b5d38sm other.boundingVolume, otherPosition, sOtherFlip)) { 136cfd74d65d832137e20e193c960802afba73b5d38sm // These two objects are potentially colliding. 137cfd74d65d832137e20e193c960802afba73b5d38sm // Now we must test all attack vs vulnerability boxes. 138cfd74d65d832137e20e193c960802afba73b5d38sm final int hit = testAttackAgainstVulnerability( 139cfd74d65d832137e20e193c960802afba73b5d38sm record.attackVolumes, 140cfd74d65d832137e20e193c960802afba73b5d38sm other.vulnerabilityVolumes, 141cfd74d65d832137e20e193c960802afba73b5d38sm position, 142cfd74d65d832137e20e193c960802afba73b5d38sm otherPosition, 143cfd74d65d832137e20e193c960802afba73b5d38sm sFlip, 144cfd74d65d832137e20e193c960802afba73b5d38sm sOtherFlip); 145cfd74d65d832137e20e193c960802afba73b5d38sm if (hit != HitType.INVALID) { 146cfd74d65d832137e20e193c960802afba73b5d38sm boolean hitAccepted = false; 147cfd74d65d832137e20e193c960802afba73b5d38sm if (other.reactionComponent != null) { 148cfd74d65d832137e20e193c960802afba73b5d38sm hitAccepted = other.reactionComponent.receivedHit( 149cfd74d65d832137e20e193c960802afba73b5d38sm other.object, record.object, hit); 150cfd74d65d832137e20e193c960802afba73b5d38sm } 151cfd74d65d832137e20e193c960802afba73b5d38sm if (record.reactionComponent != null) { 152cfd74d65d832137e20e193c960802afba73b5d38sm record.reactionComponent.hitVictim( 153cfd74d65d832137e20e193c960802afba73b5d38sm record.object, other.object, hit, hitAccepted); 154cfd74d65d832137e20e193c960802afba73b5d38sm } 155cfd74d65d832137e20e193c960802afba73b5d38sm 156cfd74d65d832137e20e193c960802afba73b5d38sm } 157cfd74d65d832137e20e193c960802afba73b5d38sm 158cfd74d65d832137e20e193c960802afba73b5d38sm final int hit2 = testAttackAgainstVulnerability( 159cfd74d65d832137e20e193c960802afba73b5d38sm other.attackVolumes, 160cfd74d65d832137e20e193c960802afba73b5d38sm record.vulnerabilityVolumes, 161cfd74d65d832137e20e193c960802afba73b5d38sm otherPosition, 162cfd74d65d832137e20e193c960802afba73b5d38sm position, 163cfd74d65d832137e20e193c960802afba73b5d38sm sOtherFlip, 164cfd74d65d832137e20e193c960802afba73b5d38sm sFlip); 165cfd74d65d832137e20e193c960802afba73b5d38sm if (hit2 != HitType.INVALID) { 166cfd74d65d832137e20e193c960802afba73b5d38sm boolean hitAccepted = false; 167cfd74d65d832137e20e193c960802afba73b5d38sm if (record.reactionComponent != null) { 168cfd74d65d832137e20e193c960802afba73b5d38sm hitAccepted = record.reactionComponent.receivedHit( 169cfd74d65d832137e20e193c960802afba73b5d38sm record.object, other.object, hit2); 170cfd74d65d832137e20e193c960802afba73b5d38sm } 171cfd74d65d832137e20e193c960802afba73b5d38sm if (other.reactionComponent != null) { 172cfd74d65d832137e20e193c960802afba73b5d38sm other.reactionComponent.hitVictim( 173cfd74d65d832137e20e193c960802afba73b5d38sm other.object, record.object, hit2, hitAccepted); 174cfd74d65d832137e20e193c960802afba73b5d38sm } 175cfd74d65d832137e20e193c960802afba73b5d38sm 176cfd74d65d832137e20e193c960802afba73b5d38sm } 177cfd74d65d832137e20e193c960802afba73b5d38sm } 178cfd74d65d832137e20e193c960802afba73b5d38sm } 179cfd74d65d832137e20e193c960802afba73b5d38sm } 180cfd74d65d832137e20e193c960802afba73b5d38sm // This is a little tricky. Since we always sweep forward in the list it's safe 181cfd74d65d832137e20e193c960802afba73b5d38sm // to invalidate the current record after we've tested it. This way we don't have to 182cfd74d65d832137e20e193c960802afba73b5d38sm // iterate over the object list twice. 183cfd74d65d832137e20e193c960802afba73b5d38sm mRecordPool.release(record); 184cfd74d65d832137e20e193c960802afba73b5d38sm } 185cfd74d65d832137e20e193c960802afba73b5d38sm 186cfd74d65d832137e20e193c960802afba73b5d38sm mObjects.clear(); 187cfd74d65d832137e20e193c960802afba73b5d38sm } 188cfd74d65d832137e20e193c960802afba73b5d38sm 189cfd74d65d832137e20e193c960802afba73b5d38sm /** Compares the passed list of attack volumes against the passed list of vulnerability volumes 190cfd74d65d832137e20e193c960802afba73b5d38sm * and returns a hit type if an intersection is found. 191cfd74d65d832137e20e193c960802afba73b5d38sm * @param attackVolumes Offensive collision volumes. 192cfd74d65d832137e20e193c960802afba73b5d38sm * @param vulnerabilityVolumes Receiving collision volumes. 193cfd74d65d832137e20e193c960802afba73b5d38sm * @param attackPosition The world position of the attacking object. 194cfd74d65d832137e20e193c960802afba73b5d38sm * @param vulnerabilityPosition The world position of the receiving object. 195cfd74d65d832137e20e193c960802afba73b5d38sm * @return The hit type of the first attacking volume that intersects a vulnerability volume, 196cfd74d65d832137e20e193c960802afba73b5d38sm * or HitType.INVALID if no intersections are found. 197cfd74d65d832137e20e193c960802afba73b5d38sm */ 198cfd74d65d832137e20e193c960802afba73b5d38sm private int testAttackAgainstVulnerability( 199cfd74d65d832137e20e193c960802afba73b5d38sm FixedSizeArray<CollisionVolume> attackVolumes, 200cfd74d65d832137e20e193c960802afba73b5d38sm FixedSizeArray<CollisionVolume> vulnerabilityVolumes, 201cfd74d65d832137e20e193c960802afba73b5d38sm Vector2 attackPosition, 202cfd74d65d832137e20e193c960802afba73b5d38sm Vector2 vulnerabilityPosition, 203cfd74d65d832137e20e193c960802afba73b5d38sm CollisionVolume.FlipInfo attackFlip, 204cfd74d65d832137e20e193c960802afba73b5d38sm CollisionVolume.FlipInfo vulnerabilityFlip) { 205cfd74d65d832137e20e193c960802afba73b5d38sm int intersectionType = HitType.INVALID; 206cfd74d65d832137e20e193c960802afba73b5d38sm if (attackVolumes != null && vulnerabilityVolumes != null) { 207cfd74d65d832137e20e193c960802afba73b5d38sm final int attackCount = attackVolumes.getCount(); 208cfd74d65d832137e20e193c960802afba73b5d38sm for (int x = 0; x < attackCount && intersectionType == HitType.INVALID; x++) { 209cfd74d65d832137e20e193c960802afba73b5d38sm final CollisionVolume attackVolume = attackVolumes.get(x); 210cfd74d65d832137e20e193c960802afba73b5d38sm final int hitType = attackVolume.getHitType(); 211cfd74d65d832137e20e193c960802afba73b5d38sm if (hitType != HitType.INVALID) { 212cfd74d65d832137e20e193c960802afba73b5d38sm final int vulnerabilityCount = vulnerabilityVolumes.getCount(); 213cfd74d65d832137e20e193c960802afba73b5d38sm for (int y = 0; y < vulnerabilityCount; y++) { 214cfd74d65d832137e20e193c960802afba73b5d38sm final CollisionVolume vulnerabilityVolume = vulnerabilityVolumes.get(y); 215cfd74d65d832137e20e193c960802afba73b5d38sm final int vulnerableType = vulnerabilityVolume.getHitType(); 216cfd74d65d832137e20e193c960802afba73b5d38sm if (vulnerableType == HitType.INVALID || vulnerableType == hitType) { 217cfd74d65d832137e20e193c960802afba73b5d38sm if (attackVolume.intersects(attackPosition, attackFlip, 218cfd74d65d832137e20e193c960802afba73b5d38sm vulnerabilityVolume, vulnerabilityPosition, 219cfd74d65d832137e20e193c960802afba73b5d38sm vulnerabilityFlip)) { 220cfd74d65d832137e20e193c960802afba73b5d38sm intersectionType = hitType; 221cfd74d65d832137e20e193c960802afba73b5d38sm break; 222cfd74d65d832137e20e193c960802afba73b5d38sm } 223cfd74d65d832137e20e193c960802afba73b5d38sm } 224cfd74d65d832137e20e193c960802afba73b5d38sm } 225cfd74d65d832137e20e193c960802afba73b5d38sm } 226cfd74d65d832137e20e193c960802afba73b5d38sm } 227cfd74d65d832137e20e193c960802afba73b5d38sm } 228cfd74d65d832137e20e193c960802afba73b5d38sm 229cfd74d65d832137e20e193c960802afba73b5d38sm return intersectionType; 230cfd74d65d832137e20e193c960802afba73b5d38sm } 231cfd74d65d832137e20e193c960802afba73b5d38sm 232cfd74d65d832137e20e193c960802afba73b5d38sm private final void drawDebugVolumes(CollisionVolumeRecord record) { 233cfd74d65d832137e20e193c960802afba73b5d38sm final Vector2 position = record.object.getPosition(); 234cfd74d65d832137e20e193c960802afba73b5d38sm if (mDrawDebugBoundingVolume) { 235cfd74d65d832137e20e193c960802afba73b5d38sm final CollisionVolume boundingVolume = record.boundingVolume; 236cfd74d65d832137e20e193c960802afba73b5d38sm sSystemRegistry.debugSystem.drawShape( 237cfd74d65d832137e20e193c960802afba73b5d38sm position.x + boundingVolume.getMinXPosition(sFlip), position.y + boundingVolume.getMinYPosition(sFlip), 238cfd74d65d832137e20e193c960802afba73b5d38sm boundingVolume.getMaxX() - boundingVolume.getMinX(), 239cfd74d65d832137e20e193c960802afba73b5d38sm boundingVolume.getMaxY() - boundingVolume.getMinY(), 240cfd74d65d832137e20e193c960802afba73b5d38sm DebugSystem.SHAPE_CIRCLE, 241cfd74d65d832137e20e193c960802afba73b5d38sm DebugSystem.COLOR_OUTLINE); 242cfd74d65d832137e20e193c960802afba73b5d38sm } 243cfd74d65d832137e20e193c960802afba73b5d38sm if (mDrawDebugCollisionVolumes) { 244cfd74d65d832137e20e193c960802afba73b5d38sm if (record.attackVolumes != null) { 245cfd74d65d832137e20e193c960802afba73b5d38sm final int attackVolumeCount = record.attackVolumes.getCount(); 246cfd74d65d832137e20e193c960802afba73b5d38sm for (int y = 0; y < attackVolumeCount; y++) { 247cfd74d65d832137e20e193c960802afba73b5d38sm CollisionVolume volume = record.attackVolumes.get(y); 248cfd74d65d832137e20e193c960802afba73b5d38sm sSystemRegistry.debugSystem.drawShape( 249cfd74d65d832137e20e193c960802afba73b5d38sm position.x + volume.getMinXPosition(sFlip), position.y + volume.getMinYPosition(sFlip), 250cfd74d65d832137e20e193c960802afba73b5d38sm volume.getMaxX() - volume.getMinX(), 251cfd74d65d832137e20e193c960802afba73b5d38sm volume.getMaxY() - volume.getMinY(), 252cfd74d65d832137e20e193c960802afba73b5d38sm volume.getClass() == AABoxCollisionVolume.class ? DebugSystem.SHAPE_BOX : DebugSystem.SHAPE_CIRCLE, 253cfd74d65d832137e20e193c960802afba73b5d38sm DebugSystem.COLOR_RED); 254cfd74d65d832137e20e193c960802afba73b5d38sm } 255cfd74d65d832137e20e193c960802afba73b5d38sm } 256cfd74d65d832137e20e193c960802afba73b5d38sm 257cfd74d65d832137e20e193c960802afba73b5d38sm if (record.vulnerabilityVolumes != null) { 258cfd74d65d832137e20e193c960802afba73b5d38sm final int vulnVolumeCount = record.vulnerabilityVolumes.getCount(); 259cfd74d65d832137e20e193c960802afba73b5d38sm for (int y = 0; y < vulnVolumeCount; y++) { 260cfd74d65d832137e20e193c960802afba73b5d38sm CollisionVolume volume = record.vulnerabilityVolumes.get(y); 261cfd74d65d832137e20e193c960802afba73b5d38sm sSystemRegistry.debugSystem.drawShape( 262cfd74d65d832137e20e193c960802afba73b5d38sm position.x + volume.getMinXPosition(sFlip), position.y + volume.getMinYPosition(sFlip), 263cfd74d65d832137e20e193c960802afba73b5d38sm volume.getMaxX() - volume.getMinX(), 264cfd74d65d832137e20e193c960802afba73b5d38sm volume.getMaxY() - volume.getMinY(), 265cfd74d65d832137e20e193c960802afba73b5d38sm volume.getClass() == AABoxCollisionVolume.class ? DebugSystem.SHAPE_BOX : DebugSystem.SHAPE_CIRCLE, 266cfd74d65d832137e20e193c960802afba73b5d38sm DebugSystem.COLOR_BLUE); 267cfd74d65d832137e20e193c960802afba73b5d38sm } 268cfd74d65d832137e20e193c960802afba73b5d38sm } 269cfd74d65d832137e20e193c960802afba73b5d38sm } 270cfd74d65d832137e20e193c960802afba73b5d38sm } 271cfd74d65d832137e20e193c960802afba73b5d38sm 272cfd74d65d832137e20e193c960802afba73b5d38sm public void setDebugPrefs(boolean drawBoundingVolumes, boolean drawCollisionVolumes) { 273cfd74d65d832137e20e193c960802afba73b5d38sm mDrawDebugBoundingVolume = drawBoundingVolumes; 274cfd74d65d832137e20e193c960802afba73b5d38sm mDrawDebugCollisionVolumes = drawCollisionVolumes; 275cfd74d65d832137e20e193c960802afba73b5d38sm } 276cfd74d65d832137e20e193c960802afba73b5d38sm 277cfd74d65d832137e20e193c960802afba73b5d38sm /** A record of a single game object and its associated collision info. */ 278cfd74d65d832137e20e193c960802afba73b5d38sm private class CollisionVolumeRecord extends AllocationGuard { 279cfd74d65d832137e20e193c960802afba73b5d38sm public GameObject object; 280cfd74d65d832137e20e193c960802afba73b5d38sm public HitReactionComponent reactionComponent; 281cfd74d65d832137e20e193c960802afba73b5d38sm public CollisionVolume boundingVolume; 282cfd74d65d832137e20e193c960802afba73b5d38sm public FixedSizeArray<CollisionVolume> attackVolumes; 283cfd74d65d832137e20e193c960802afba73b5d38sm public FixedSizeArray<CollisionVolume> vulnerabilityVolumes; 284cfd74d65d832137e20e193c960802afba73b5d38sm 285cfd74d65d832137e20e193c960802afba73b5d38sm public void reset() { 286cfd74d65d832137e20e193c960802afba73b5d38sm object = null; 287cfd74d65d832137e20e193c960802afba73b5d38sm attackVolumes = null; 288cfd74d65d832137e20e193c960802afba73b5d38sm vulnerabilityVolumes = null; 289cfd74d65d832137e20e193c960802afba73b5d38sm boundingVolume = null; 290cfd74d65d832137e20e193c960802afba73b5d38sm reactionComponent = null; 291cfd74d65d832137e20e193c960802afba73b5d38sm } 292cfd74d65d832137e20e193c960802afba73b5d38sm } 293cfd74d65d832137e20e193c960802afba73b5d38sm 294cfd74d65d832137e20e193c960802afba73b5d38sm /** A pool of collision volume records. */ 295cfd74d65d832137e20e193c960802afba73b5d38sm private class CollisionVolumeRecordPool extends TObjectPool<CollisionVolumeRecord> { 296cfd74d65d832137e20e193c960802afba73b5d38sm 297cfd74d65d832137e20e193c960802afba73b5d38sm public CollisionVolumeRecordPool(int count) { 298cfd74d65d832137e20e193c960802afba73b5d38sm super(count); 299cfd74d65d832137e20e193c960802afba73b5d38sm } 300cfd74d65d832137e20e193c960802afba73b5d38sm 301cfd74d65d832137e20e193c960802afba73b5d38sm @Override 302cfd74d65d832137e20e193c960802afba73b5d38sm protected void fill() { 303cfd74d65d832137e20e193c960802afba73b5d38sm for (int x = 0; x < getSize(); x++) { 304cfd74d65d832137e20e193c960802afba73b5d38sm getAvailable().add(new CollisionVolumeRecord()); 305cfd74d65d832137e20e193c960802afba73b5d38sm } 306cfd74d65d832137e20e193c960802afba73b5d38sm } 307cfd74d65d832137e20e193c960802afba73b5d38sm 308cfd74d65d832137e20e193c960802afba73b5d38sm @Override 309cfd74d65d832137e20e193c960802afba73b5d38sm public void release(Object entry) { 310cfd74d65d832137e20e193c960802afba73b5d38sm ((CollisionVolumeRecord)entry).reset(); 311cfd74d65d832137e20e193c960802afba73b5d38sm super.release(entry); 312cfd74d65d832137e20e193c960802afba73b5d38sm } 313cfd74d65d832137e20e193c960802afba73b5d38sm 314cfd74d65d832137e20e193c960802afba73b5d38sm } 315cfd74d65d832137e20e193c960802afba73b5d38sm 316cfd74d65d832137e20e193c960802afba73b5d38sm /** 317cfd74d65d832137e20e193c960802afba73b5d38sm * Comparator for game objects that considers the world position of the object's bounding 318cfd74d65d832137e20e193c960802afba73b5d38sm * volume and sorts objects from left to right on the x axis. */ 319cfd74d65d832137e20e193c960802afba73b5d38sm public final static class CollisionVolumeComparator implements Comparator<CollisionVolumeRecord> { 320cfd74d65d832137e20e193c960802afba73b5d38sm private static CollisionVolume.FlipInfo sCompareFlip = new CollisionVolume.FlipInfo(); 321cfd74d65d832137e20e193c960802afba73b5d38sm public int compare(CollisionVolumeRecord object1, CollisionVolumeRecord object2) { 322cfd74d65d832137e20e193c960802afba73b5d38sm int result = 0; 323cfd74d65d832137e20e193c960802afba73b5d38sm if (object1 == null && object2 != null) { 324cfd74d65d832137e20e193c960802afba73b5d38sm result = 1; 325cfd74d65d832137e20e193c960802afba73b5d38sm } else if (object1 != null && object2 == null) { 326cfd74d65d832137e20e193c960802afba73b5d38sm result = -1; 327cfd74d65d832137e20e193c960802afba73b5d38sm } else if (object1 != null && object2 != null) { 328cfd74d65d832137e20e193c960802afba73b5d38sm sCompareFlip.flipX = (object1.object.facingDirection.x < 0.0f); 329cfd74d65d832137e20e193c960802afba73b5d38sm sCompareFlip.flipY = (object1.object.facingDirection.y < 0.0f); 330cfd74d65d832137e20e193c960802afba73b5d38sm sCompareFlip.parentWidth = object1.object.width; 331cfd74d65d832137e20e193c960802afba73b5d38sm sCompareFlip.parentHeight = object1.object.height; 332cfd74d65d832137e20e193c960802afba73b5d38sm 333cfd74d65d832137e20e193c960802afba73b5d38sm final float minX1 = object1.object.getPosition().x 334cfd74d65d832137e20e193c960802afba73b5d38sm + object1.boundingVolume.getMinXPosition(sCompareFlip); 335cfd74d65d832137e20e193c960802afba73b5d38sm 336cfd74d65d832137e20e193c960802afba73b5d38sm sCompareFlip.flipX = (object2.object.facingDirection.x < 0.0f); 337cfd74d65d832137e20e193c960802afba73b5d38sm sCompareFlip.flipY = (object2.object.facingDirection.y < 0.0f); 338cfd74d65d832137e20e193c960802afba73b5d38sm sCompareFlip.parentWidth = object2.object.width; 339cfd74d65d832137e20e193c960802afba73b5d38sm sCompareFlip.parentHeight = object2.object.height; 340cfd74d65d832137e20e193c960802afba73b5d38sm 341cfd74d65d832137e20e193c960802afba73b5d38sm final float minX2 = object2.object.getPosition().x 342cfd74d65d832137e20e193c960802afba73b5d38sm + object2.boundingVolume.getMinXPosition(sCompareFlip); 343cfd74d65d832137e20e193c960802afba73b5d38sm 344cfd74d65d832137e20e193c960802afba73b5d38sm final float delta = minX1 - minX2; 345cfd74d65d832137e20e193c960802afba73b5d38sm if (delta < 0.0f) { 346cfd74d65d832137e20e193c960802afba73b5d38sm result = -1; 347cfd74d65d832137e20e193c960802afba73b5d38sm } else if (delta > 0.0f) { 348cfd74d65d832137e20e193c960802afba73b5d38sm result = 1; 349cfd74d65d832137e20e193c960802afba73b5d38sm } 350cfd74d65d832137e20e193c960802afba73b5d38sm } 351cfd74d65d832137e20e193c960802afba73b5d38sm return result; 352cfd74d65d832137e20e193c960802afba73b5d38sm } 353cfd74d65d832137e20e193c960802afba73b5d38sm } 354cfd74d65d832137e20e193c960802afba73b5d38sm 355cfd74d65d832137e20e193c960802afba73b5d38sm 356cfd74d65d832137e20e193c960802afba73b5d38sm 357cfd74d65d832137e20e193c960802afba73b5d38sm} 358