View Javadoc

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 }