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.impl;
28  
29  import com.lhkbob.entreri.Component;
30  import com.lhkbob.entreri.ComponentIterator;
31  
32  import java.util.Arrays;
33  
34  /**
35   * Implementation of ComponentIterator used by EntitySystemImpl.
36   *
37   * @author Michael Ludwig
38   */
39  public class ComponentIteratorImpl implements ComponentIterator {
40      private final EntitySystemImpl system;
41  
42      private int index;
43  
44      private AbstractComponent<?>[] required; // all required except primary
45      private AbstractComponent<?>[] optional;
46  
47      private AbstractComponent<?> primary;
48  
49      /**
50       * Create a new ComponentIterator that will iterate over components within the given
51       * EntitySystem. It is initialized with no required or optional components, but at
52       * least one required component must be added before it can be iterated over.
53       *
54       * @param system The EntitySystem of the iterator
55       *
56       * @throws NullPointerException if system is null
57       */
58      public ComponentIteratorImpl(EntitySystemImpl system) {
59          if (system == null) {
60              throw new NullPointerException("System cannot be null");
61          }
62          this.system = system;
63          required = new AbstractComponent<?>[0];
64          optional = new AbstractComponent<?>[0];
65          primary = null;
66          index = 0;
67      }
68  
69      @Override
70      @SuppressWarnings("unchecked")
71      public <T extends Component> T addRequired(Class<T> type) {
72          if (type == null) {
73              throw new NullPointerException("Component type cannot be null");
74          }
75          AbstractComponent<T> data = system.getRepository(type).createDataInstance();
76  
77          // check to see if the data should be the new primary
78          if (primary == null) {
79              // no other required components, so just set it
80              primary = data;
81          } else {
82              // check if the new data is shorter, but we will definitely
83              // putting one data into the required array
84              required = Arrays.copyOf(required, required.length + 1);
85  
86              if (data.owner.getMaxComponentIndex() <
87                  primary.owner.getMaxComponentIndex()) {
88                  // new primary
89                  required[required.length - 1] = primary;
90                  primary = data;
91              } else {
92                  // not short enough so store it in the array
93                  required[required.length - 1] = data;
94              }
95          }
96  
97          return (T) data;
98      }
99  
100     @Override
101     @SuppressWarnings("unchecked")
102     public <T extends Component> T addOptional(Class<T> type) {
103         if (type == null) {
104             throw new NullPointerException("Component type cannot be null");
105         }
106 
107         AbstractComponent<T> data = system.getRepository(type).createDataInstance();
108 
109         // add the data to the optional array
110         optional = Arrays.copyOf(optional, optional.length + 1);
111         optional[optional.length - 1] = data;
112 
113         return (T) data;
114     }
115 
116     @Override
117     public boolean next() {
118         if (primary == null) {
119             return false;
120         }
121 
122         boolean found;
123         int entity;
124         int component;
125         int count = primary.owner.getMaxComponentIndex();
126         while (index < count - 1) {
127             index++; // always increment one
128 
129             found = true;
130             entity = primary.owner.getEntityIndex(index);
131             if (entity != 0) {
132                 // we have a possible entity candidate
133                 primary.setIndex(index);
134                 for (int i = 0; i < required.length; i++) {
135                     component = required[i].owner.getComponentIndex(entity);
136                     if (component == 0) {
137                         found = false;
138                         break;
139                     } else {
140                         required[i].setIndex(component);
141                     }
142                 }
143 
144                 if (found) {
145                     // we have satisfied all required components,
146                     // so now set all optional requirements as well
147                     for (int i = 0; i < optional.length; i++) {
148                         component = optional[i].owner.getComponentIndex(entity);
149                         optional[i].setIndex(component);
150                     }
151 
152                     return true;
153                 }
154             }
155         }
156 
157         return false;
158     }
159 
160     @Override
161     public void reset() {
162         index = 0;
163     }
164 }