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 }