1 /* 2 * Entreri, an entity-component framework in Java 3 * 4 * Copyright (c) 2013, Michael Ludwig 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without modification, 8 * are permitted provided that the following conditions are met: 9 * 10 * Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 package com.lhkbob.entreri; 28 29 import java.util.Iterator; 30 31 /** 32 * <p/> 33 * ComponentIterator is an {@link Iterator}-like class used for quickly iterating over 34 * subsets of entities within an EntitySystem with direct access to the components you're 35 * interested in. You specify the component classes using {@link #addRequired(Class)} and 36 * {@link #addOptional(Class)}, which return flyweight component instances that are 37 * updated as the iterator is looped through. These determine the constraints on the 38 * entities reported by the iterator. ComponentIterator is reset-able, so the same 39 * instance and created components can be reused for multiple iterations. 40 * <p/> 41 * The ComponentIterator will skip all entities that do not have components of the 42 * required component types. This is very useful in Tasks because often there related 43 * component types that you want to fetch and process at the same time. Optional 44 * Component's will be set to the entity if present otherwise they'll be marked as dead. 45 * <p/> 46 * The basic workflow for using a ComponentIterator is shown below. In the example, the 47 * iterator is used to iterate over all entities that have both an A and a B component, 48 * while optionally loading a C component if available. 49 * <pre> 50 * // create iterator 51 * ComponentIterator it = new ComponentIterator(system); 52 * 53 * // create flyweight components for data access 54 * A cdA = it.addRequired(A.class); 55 * B cdB = it.addRequired(B.class); 56 * C cdC = it.addOptional(C.class); 57 * 58 * // iterate 59 * it.reset(); // not actually required for first iteration 60 * while(it.next()) { 61 * // cdA and cdB are both assigned to components of type A and B on the same 62 * // entity, so they can be processed without checking isAlive() 63 * ... 64 * // cdC may or may not be valid 65 * if (cdC.isAlive()) { 66 * // the current entity also has a component of type C 67 * } 68 * } 69 * </pre> 70 * 71 * @author Michael Ludwig 72 */ 73 public interface ComponentIterator { 74 /** 75 * Add the given Component type as a required component for this iterator. The 76 * returned flyweight instance must be used to access the data for the component at 77 * each iteration. Every call to {@link #next()} will update its identity to be the 78 * corresponding component of type T whose entity has all required components. 79 * 80 * @return A flyweight instance to access the current values for the component type 81 * 82 * @throws NullPointerException if type is null 83 */ 84 public <T extends Component> T addRequired(Class<T> type); 85 86 /** 87 * Add the given Component type as an optional component for this iterator. The 88 * returned flyweight instance must be used to access the data for the component at 89 * each iteration. Every call to {@link #next()} will update its identity to be the 90 * corresponding component of type T if the entity has a component of type T. 91 * <p/> 92 * If it does not then the component will be marked as dead until a future iteration 93 * has a T component 94 * 95 * @return A flyweight instance to access the current values for the component type 96 * 97 * @throws NullPointerException if type is null 98 */ 99 public <T extends Component> T addOptional(Class<T> type); 100 101 /** 102 * <p/> 103 * Advance the iterator to the next Entity that has components of all required types. 104 * Every flyweight component returned by previous calls to {@link #addRequired(Class)} 105 * will be updated to point to that entity. The optional flyweight components will be 106 * updated to the entity if a component exists. They may not be, in which case they 107 * will be flagged as invalid. 108 * <p/> 109 * It can be assumed that when an Entity is found that all required components are 110 * valid and reference that entity's components of the appropriate type. 111 * <p/> 112 * True is returned if an Entity was found. False is returned if there were no more 113 * entities matching the requirements in the system. Additionally, if there has been 114 * no call to {@link #addRequired(Class)} false is always returned. The iterator must 115 * be constrained by at least one required type. 116 * 117 * @return True if another entity was found and the required components (and any 118 * present optional components) have been updated to that entity 119 */ 120 public boolean next(); 121 122 /** 123 * Reset this ComponentIterator to the beginning of the system to perform another 124 * complete iteration. This does not change the identities of the created flyweight 125 * components until the next call to {@link #next()} is made, at which point they are 126 * updated to first valid matching components. 127 */ 128 public void reset(); 129 }