33 | //
34 | //End of AUTHORS file.
35 | //
36 | //All changes to this file are marked with comments starting with
37 | //my initials (MM).
38 |
39 | //MM: changed package name
40 | //package com.badlogic.gdx.math;
41 | package com.matthewmichelotti.collider;
42 |
43 | import java.util.Random;
44 |
45 | /** This class implements the xorshift128+ algorithm that is a very fast, top-quality 64-bit pseudo-random number generator. The
46 | * quality of this PRNG is much higher than {@link java.util.Random}'s, and its cycle length is 2128 − 1, which
47 | * is more than enough for any single-thread application. More details and algorithms can be found here.
49 | *
50 | * Instances of RandomXS128 are not thread-safe.
51 | *
52 | * @author Inferno
53 | * @author davebaol */
54 | //MM: changed class from public to package-private
55 | class RandomXS128 extends Random {
56 |
57 | /** Normalization constant for double. */
58 | private static final double NORM_DOUBLE = 1.0 / (1L << 53);
59 |
60 | /** Normalization constant for float. */
61 | private static final double NORM_FLOAT = 1.0 / (1L << 24);
62 |
63 | /** The first half of the internal state of this pseudo-random number generator. */
64 | private long seed0;
65 |
66 | /** The second half of the internal state of this pseudo-random number generator. */
67 | private long seed1;
68 |
69 | /** Creates a new random number generator. This constructor sets the seed of the random number generator to a value very likely
70 | * to be distinct from any other invocation of this constructor.
71 | *
72 | * This implementation creates a {@link java.util.Random} instance to generate the initial seed. */
73 | public RandomXS128 () {
74 | setSeed(new Random().nextLong());
75 | }
76 |
77 | /** Creates a new random number generator using a single {@code long} seed.
78 | * @param seed the initial seed */
79 | public RandomXS128 (long seed) {
80 | setSeed(seed);
81 | }
82 |
83 | /** Creates a new random number generator using two {@code long} seeds.
84 | * @param seed0 the first part of the initial seed
85 | * @param seed1 the second part of the initial seed */
86 | public RandomXS128 (long seed0, long seed1) {
87 | setState(seed0, seed1);
88 | }
89 |
90 | /** Returns the next pseudo-random, uniformly distributed {@code long} value from this random number generator's sequence.
91 | *
92 | * Subclasses should override this, as this is used by all other methods. */
93 | @Override
94 | public long nextLong () {
95 | long s1 = this.seed0;
96 | final long s0 = this.seed1;
97 | this.seed0 = s0;
98 | s1 ^= s1 << 23;
99 | return (this.seed1 = (s1 ^ s0 ^ (s1 >>> 17) ^ (s0 >>> 26))) + s0;
100 | }
101 |
102 | /** This protected method is final because, contrary to the superclass, it's not used anymore by the other methods. */
103 | @Override
104 | protected final int next (int bits) {
105 | return (int)(nextLong() & ((1L << bits) - 1));
106 | }
107 |
108 | /** Returns the next pseudo-random, uniformly distributed {@code int} value from this random number generator's sequence.
109 | *
110 | * This implementation uses {@link #nextLong()} internally. */
111 | @Override
112 | public int nextInt () {
113 | return (int)nextLong();
114 | }
115 |
116 | /** Returns a pseudo-random, uniformly distributed {@code int} value between 0 (inclusive) and the specified value (exclusive),
117 | * drawn from this random number generator's sequence.
118 | *
119 | * This implementation uses {@link #nextLong()} internally.
120 | * @param n the positive bound on the random number to be returned.
121 | * @return the next pseudo-random {@code int} value between {@code 0} (inclusive) and {@code n} (exclusive). */
122 | @Override
123 | public int nextInt (final int n) {
124 | return (int)nextLong(n);
125 | }
126 |
127 | /** Returns a pseudo-random, uniformly distributed {@code long} value between 0 (inclusive) and the specified value (exclusive),
128 | * drawn from this random number generator's sequence. The algorithm used to generate the value guarantees that the result is
129 | * uniform, provided that the sequence of 64-bit values produced by this generator is.
130 | *
131 | * This implementation uses {@link #nextLong()} internally.
132 | * @param n the positive bound on the random number to be returned.
133 | * @return the next pseudo-random {@code long} value between {@code 0} (inclusive) and {@code n} (exclusive). */
134 | public long nextLong (final long n) {
135 | if (n <= 0) throw new IllegalArgumentException("n must be positive");
136 | for (;;) {
137 | final long bits = nextLong() >>> 1;
138 | final long value = bits % n;
139 | if (bits - value + (n - 1) >= 0) return value;
140 | }
141 | }
142 |
143 | /** Returns a pseudo-random, uniformly distributed {@code double} value between 0.0 and 1.0from this random number generator's
144 | * sequence.
145 | *
146 | * This implementation uses {@link #nextLong()} internally. */
147 | @Override
148 | public double nextDouble () {
149 | return (nextLong() >>> 11) * NORM_DOUBLE;
150 | }
151 |
152 | /** Returns a pseudo-random, uniformly distributed {@code float} value between 0.0 and 1.0 from this random number generator's
153 | * sequence.
154 | *
155 | * This implementation uses {@link #nextLong()} internally. */
156 | @Override
157 | public float nextFloat () {
158 | return (float)((nextLong() >>> 40) * NORM_FLOAT);
159 | }
160 |
161 | /** Returns a pseudo-random, uniformly distributed {@code boolean } value from this random number generator's sequence.
162 | *
163 | * This implementation uses {@link #nextLong()} internally. */
164 | @Override
165 | public boolean nextBoolean () {
166 | return (nextLong() & 1) != 0;
167 | }
168 |
169 | /** Generates random bytes and places them into a user-supplied byte array. The number of random bytes produced is equal to the
170 | * length of the byte array.
171 | *
172 | * This implementation uses {@link #nextLong()} internally. */
173 | @Override
174 | public void nextBytes (final byte[] bytes) {
175 | int n; // = 0; //MM: commented this assignment
176 | int i = bytes.length;
177 | while (i != 0) {
178 | n = i < 8 ? i : 8; // min(i, 8);
179 | for (long bits = nextLong(); n-- != 0; bits >>= 8)
180 | bytes[--i] = (byte)bits;
181 | }
182 | }
183 |
184 | /** Sets the internal seed of this generator based on the given {@code long} value.
185 | *
186 | * The given seed is passed twice through an hash function. This way, if the user passes a small value we avoid the short
187 | * irregular transient associated with states having a very small number of bits set.
188 | * @param seed a nonzero seed for this generator (if zero, the generator will be seeded with {@link Long#MIN_VALUE}). */
189 | @Override
190 | public void setSeed (final long seed) {
191 | long seed0 = murmurHash3(seed == 0 ? Long.MIN_VALUE : seed);
192 | setState(seed0, murmurHash3(seed0));
193 | }
194 |
195 | /** Sets the internal state of this generator.
196 | * @param seed0 the first part of the internal state
197 | * @param seed1 the second part of the internal state */
198 | public void setState (final long seed0, final long seed1) {
199 | this.seed0 = seed0;
200 | this.seed1 = seed1;
201 | }
202 |
203 | private final static long murmurHash3 (long x) {
204 | x ^= x >>> 33;
205 | x *= 0xff51afd7ed558ccdL;
206 | x ^= x >>> 33;
207 | x *= 0xc4ceb9fe1a85ec53L;
208 | x ^= x >>> 33;
209 |
210 | return x;
211 | }
212 |
213 | }
214 |
--------------------------------------------------------------------------------
/core/src/com/matthewmichelotti/collider/HitBox.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013-2014 Matthew D. Michelotti
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.matthewmichelotti.collider;
18 |
19 | /**
20 | * Description of position, shape, and velocities of a hitbox
21 | * used for testing collision with other HitBoxes.
22 | * Methods for creating HitBoxes can be found in the {@link Collider} class.
23 | * Based on the velocities, the position and shape of a HitBox will
24 | * automatically reflect changes in time in the Collider.
25 | * The word "hitbox" is used in a general sense, as a HitBox is
26 | * not necessarily a rectangle.
27 | *
28 | * When a HitBox's state is modified, it will need to check with the Collider
29 | * for potential interactions.
30 | * Will wait for all consecutive modifier method calls on a HitBox
31 | * before performing this check.
32 | * Whenever you modify the state of a HitBox, you must also call
33 | * {@link #commit(double)}.
34 | *
35 | * For the sake of avoiding numerical instability, the dimensions
36 | * of a HitBox should never be zero nor extremely small.
37 | * Something on the order of 1/10 of a "pixel" should still be fine,
38 | * but, for example, 1e-11 "pixels" is too small.
39 | *
40 | * @author Matthew Michelotti
41 | */
42 | public abstract class HitBox {
43 | /**
44 | * Number of legal HitBox groups.
45 | * Current value is 256, but it most cases you won't need more than 3 groups.
46 | * Legal groups are 0-255 inclusive.
47 | */
48 | public final static int NUM_GROUPS = 256;
49 |
50 | double startTime, endTime;
51 | final Collider collider;
52 | Object overlapSet;
53 |
54 | private int group = -2;
55 | private int changeId = 0;
56 | private int testId = -1;
57 | private Object owner;
58 |
59 | HitBox(Collider collider) {
60 | this.collider = collider;
61 | }
62 |
63 | void init() {
64 | this.startTime = collider.getTime();
65 | this.endTime = this.startTime;
66 |
67 | this.group = -1;
68 | setGroup(0);
69 | }
70 |
71 | void markTransitionStart() {
72 | startTime = collider.getTime();
73 | if(endTime < startTime) {
74 | throw new RuntimeException("updating HitBox late");
75 | }
76 | changeId++;
77 | endTime = -1;
78 | }
79 |
80 | /**
81 | * Call when done using this HitBox.
82 | * No more events will be generated involving this HitBox.
83 | * This object will be placed uninitialized in a pool
84 | * for future use.
85 | */
86 | public void free() {
87 | //NOTE: overridden free method should place the HitBox in the appropriate pool
88 | owner = null;
89 | group = -2;
90 | }
91 |
92 | boolean isInitialized() {
93 | return group != -2;
94 | }
95 |
96 | final boolean testMark(int testId) {
97 | if(testId == this.testId) return false;
98 | this.testId = testId;
99 | return true;
100 | }
101 |
102 | final int getChangeId() {return changeId;}
103 |
104 | /**
105 | * Call this method if there is a change in the return values
106 | * of {@link InteractTester#canInteract(HitBox, HitBox)} involving
107 | * this HitBox.
108 | * This will prompt searching for potential collisions between
109 | * previously uninteractable HitBoxes.
110 | * Separate events will not be generated for HitBoxes that overlap and used
111 | * to interact with each other but no longer do because of this call.
112 | */
113 | public final void interactivityChange() {collider.altering(this, true);}
114 |
115 | /**
116 | * Set the group that this HitBox belongs to.
117 | * Default group is 0.
118 | * The value -1 denotes that this HitBox does not belong to any group
119 | * and thus is never tested for collisions.
120 | * This method will also invoke the functionality of
121 | * {@link #interactivityChange()}.
122 | *
123 | * Collision testing will only be performed on HitBoxes of the groups
124 | * specified by the {@link InteractTester#getInteractGroups(HitBox)}
125 | * method.
126 | * This reduces the number of HitBoxes to iterate over for collision checks.
127 | * It is a good idea to use only a small number of groups for a game, perhaps 1 to 3.
128 | * As an example, if you are implementing a
129 | * danmaku
130 | * game, you might use one group for bullets and one group for everything else,
131 | * and make it so bullets do not check for collisions within the bullet group.
132 | * @param group Group that this HitBox should belong to. Must be between
133 | * -1 and {@link #NUM_GROUPS}-1 inclusive. The value -1 denotes not belonging to any group.
134 | */
135 | public final void setGroup(int group) {
136 | if(group < -1 || group >= NUM_GROUPS) {
137 | throw new IllegalArgumentException("invalid group:" + group);
138 | }
139 | collider.altering(this, true);
140 | this.group = group;
141 | }
142 |
143 | /**
144 | * This should be called after you modify the HitBox by changing
145 | * its position, velocity, interactivity, etc. (exception: this does
146 | * not need to be called after calling {@link #setOwner(Object)}).
147 | * Call this method only once after you have made all of the other
148 | * changes to this HitBox. You must specify an endTime, which
149 | * is the expected time of the next change to the HitBox state.
150 | * You must call commit again when this endTime is reached, if not sooner.
151 | * Although you are allowed to change the HitBox state and call commit prior
152 | * to the specified endTime, doing so will result in more collisions
153 | * that need to be tested.
154 | * @param endTime Expected time of next change to HitBox state.
155 | * Positive infinity is allowed.
156 | */
157 | public final void commit(double endTime) {
158 | double time = collider.getTime();
159 | if(endTime < time) throw new IllegalArgumentException("endTime already passed");
160 | collider.altering(this);
161 | this.endTime = endTime;
162 | }
163 |
164 | /**
165 | * Set an object to be associated with this HitBox.
166 | * This is provided as an alternative to looking up
167 | * a related object in a HashMap with HitBoxes as keys.
168 | * @param obj Object to be associated with this HitBox.
169 | */
170 | public final void setOwner(Object obj) {this.owner = obj;}
171 |
172 | /**
173 | * Returns the group that this HitBox belongs to.
174 | * @return The group that this HitBox belongs to.
175 | * @see #setGroup(int)
176 | */
177 | public final int getGroup() {return group;}
178 |
179 | /**
180 | * Returns the Object associated with this HitBox.
181 | * @return The Object associated with this HitBox.
182 | */
183 | public final Object getOwner() {return owner;}
184 |
185 | /**
186 | * Returns the current time of the simulation.
187 | * Same as calling {@link Collider#getTime()}.
188 | * @return The current time of the simulation.
189 | */
190 | public final double getTime() {return collider.getTime();}
191 |
192 | /**
193 | * Returns a normal vector between the two HitBoxes.
194 | * Vector will be pointed away from this HitBox and towards the dest HitBox.
195 | * @param dest Other HitBox that normal vector will be pointed towards.
196 | * @return Normal vector between the two HitBoxes.
197 | * This object will be re-used each time getNormal is called
198 | * on any HitBox generated from the same Collider.
199 | */
200 | public final Normal getNormal(HitBox dest) {
201 | return collider.getNormal(this, dest);
202 | }
203 |
204 | /**
205 | * Returns the amount that the two HitBoxes overlap.
206 | * This is the same as the overlap in the return
207 | * value of {@link #getNormal(HitBox)}.
208 | * Due to rounding error, this value may be positive
209 | * even if a collision event was not generated
210 | * for the two HitBoxes, and vice versa.
211 | * @param other Other HitBox to compute overlap of.
212 | * @return The amount that the two HitBoxes overlap.
213 | */
214 | public final double getOverlap(HitBox other) {
215 | return collider.getNormal(this, other).overlap;
216 | }
217 |
218 |
219 | /**
220 | * Returns true if the two HitBoxes overlap.
221 | * This is the same as checking if {@link #getOverlap(HitBox)}
222 | * is positive.
223 | * Due to rounding error, this value may be true
224 | * even if a collision event was not generated
225 | * for the two HitBoxes, and vice versa.
226 | * @param other Other HitBox to test overlap with.
227 | * @return True if the two HitBoxes overlap.
228 | */
229 | public final boolean overlaps(HitBox other) {
230 | return collider.getNormal(this, other).overlap > 0.0;
231 | }
232 |
233 | abstract boolean isMoving();
234 |
235 | abstract double getBoundEdgeComp(int edge, double startTime, double endTime);
236 |
237 | abstract double getMaxBoundEdgeVel();
238 |
239 | final double getBoundEdgeComp(int edge) {
240 | return getBoundEdgeComp(edge, startTime, endTime);
241 | }
242 | }
243 |
--------------------------------------------------------------------------------
/demos-core/src/com/matthewmichelotti/collider/demos/GameEngine.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013-2014 Matthew D. Michelotti
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.matthewmichelotti.collider.demos;
18 |
19 | import java.util.ArrayList;
20 | import java.util.Collections;
21 | import java.util.HashSet;
22 | import java.util.PriorityQueue;
23 |
24 | import com.badlogic.gdx.Gdx;
25 | import com.badlogic.gdx.graphics.Color;
26 | import com.badlogic.gdx.graphics.GL20;
27 | import com.badlogic.gdx.graphics.OrthographicCamera;
28 | import com.badlogic.gdx.graphics.g2d.BitmapFont;
29 | import com.badlogic.gdx.graphics.g2d.SpriteBatch;
30 | import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
31 | import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
32 | import com.badlogic.gdx.utils.TimeUtils;
33 | import com.matthewmichelotti.collider.Collider;
34 | import com.matthewmichelotti.collider.ColliderEvent;
35 | import com.matthewmichelotti.collider.ColliderOpts;
36 | import com.matthewmichelotti.collider.HBCircle;
37 | import com.matthewmichelotti.collider.HBRect;
38 | import com.matthewmichelotti.collider.HitBox;
39 | import com.matthewmichelotti.collider.InteractTester;
40 | import com.matthewmichelotti.collider.demos.comps.CBounds;
41 | import com.matthewmichelotti.collider.util.ColliderListener;
42 | import com.matthewmichelotti.collider.util.ColliderProcess;
43 | import com.matthewmichelotti.collider.util.ContProcesses;
44 | import com.matthewmichelotti.collider.util.ContProcess;
45 |
46 | /**
47 | * Manages FunctionEvents, ColliderEvents,
48 | * creation of new HitBoxes, and rendering.
49 | * @author Matthew Michelotti
50 | */
51 | public class GameEngine {
52 | public final static int SCREEN_WIDTH = 1280; //960
53 | public final static int SCREEN_HEIGHT = 720;
54 |
55 | public final static int GROUP_NORMAL = 0;
56 | public final static int GROUP_BULLET = 1;
57 |
58 | private final static int[] ALL_GROUPS_ARR = new int[] {GROUP_NORMAL, GROUP_BULLET};
59 | private final static int[] NORMAL_GROUP_ARR = new int[] {GROUP_NORMAL};
60 |
61 | private ContProcesses processes;
62 | private Collider collider;
63 | private HashSet comps = new HashSet();
64 | private PriorityQueue events = new PriorityQueue();
65 | private MousePosListener mouseListener;
66 | private CBounds bounds;
67 |
68 | private ShapeRenderer shapeR = new ShapeRenderer();
69 | private SpriteBatch spriteB = new SpriteBatch();
70 | private BitmapFont font = new BitmapFont();
71 | private Color bgColor = Color.BLACK;
72 | private OrthographicCamera camera;
73 |
74 | private long renderWork = 0;
75 | private long otherWork = 0;
76 |
77 | public GameEngine() {
78 | clear();
79 | camera = new OrthographicCamera(SCREEN_WIDTH, SCREEN_HEIGHT);
80 | camera.translate(.5f*SCREEN_WIDTH, .5f*SCREEN_HEIGHT, 0);
81 | camera.update();
82 | }
83 |
84 | public void clear() {
85 | processes = new ContProcesses();
86 |
87 | ColliderOpts opts = new ColliderOpts();
88 | opts.cellWidth = 22.0;
89 | opts.separateBuffer = .1;
90 | opts.maxForesightTime = 2.0;
91 | opts.interactTester = new CompInteractTester();
92 | collider = new Collider(opts);
93 |
94 | comps.clear();
95 | events.clear();
96 | mouseListener = null;
97 | bounds = null;
98 |
99 | bgColor = Color.BLACK;
100 |
101 | processes.addProcess(new ColliderProcess(collider, new MyColliderListener()));
102 | processes.addProcess(new EventProcess());
103 | events.add(new LogEvent(0.0));
104 | }
105 |
106 | public HBRect makeRect() {return collider.makeRect();}
107 | public HBCircle makeCircle() {return collider.makeCircle();}
108 |
109 | public void addEvent(FunctionEvent event) {
110 | events.add(event);
111 | }
112 |
113 | public void addComp(Component comp) {
114 | boolean success = comps.add(comp);
115 | if(!success) throw new RuntimeException();
116 | if(comp instanceof MousePosListener) {
117 | if(mouseListener != null) throw new RuntimeException();
118 | mouseListener = (MousePosListener)comp;
119 | }
120 | if(comp instanceof CBounds) {
121 | if(bounds != null) throw new RuntimeException();
122 | bounds = (CBounds)comp;
123 | }
124 | }
125 |
126 | public void removeComp(Component comp) {
127 | boolean success = comps.remove(comp);
128 | if(!success) throw new RuntimeException();
129 | if(mouseListener == comp) mouseListener = null;
130 | if(bounds == comp) bounds = null;
131 | }
132 |
133 | public boolean isInBounds(HitBox hitBox) {
134 | return hitBox.getOverlap(bounds.hitBox()) >= .1;
135 | }
136 |
137 | public void stepToTime(double time) {
138 | if(time < getTime()) return;
139 | long startNanoTime = TimeUtils.nanoTime();
140 | if(time > getTime() && mouseListener != null) {
141 | double x = SCREEN_WIDTH*Gdx.input.getX()/(double)Gdx.graphics.getWidth();
142 | double y = SCREEN_HEIGHT*(1.0 - Gdx.input.getY()/(double)Gdx.graphics.getHeight());
143 | x = Math.max(0, Math.min(SCREEN_WIDTH, x));
144 | y = Math.max(0, Math.min(SCREEN_HEIGHT, y));
145 | mouseListener.updateMousePos(time, x, y);
146 | }
147 | processes.stepToTime(time);
148 | otherWork += (TimeUtils.nanoTime() - startNanoTime);
149 | }
150 |
151 | public double getTime() {
152 | return processes.getTime();
153 | }
154 |
155 | public void setBG(Color color) {
156 | this.bgColor = color;
157 | }
158 |
159 | public void render(boolean drawFPS) {
160 | long startNanoTime = TimeUtils.nanoTime();
161 |
162 | spriteB.setProjectionMatrix(camera.combined);
163 | shapeR.setProjectionMatrix(camera.combined);
164 |
165 | Gdx.gl.glClearColor(bgColor.r, bgColor.g, bgColor.b, bgColor.a);
166 | Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
167 |
168 | ArrayList orderedComps = new ArrayList(comps);
169 | ArrayList messageComps = new ArrayList();
170 | Collections.sort(orderedComps);
171 |
172 | shapeR.begin(ShapeType.Filled);
173 | for(Component c : orderedComps) {
174 | if(c.getMessage() != null) messageComps.add(c);
175 | Color color = c.getColor();
176 | if(color == null) continue;
177 | shapeR.setColor(color);
178 | if(c.isRect()) {
179 | HBRect rect = c.rect();
180 | double l = rect.getX() - .5*rect.getWidth();
181 | double b = rect.getY() - .5*rect.getHeight();
182 | shapeR.rect((float)l, (float)b, (float)rect.getWidth(), (float)rect.getHeight());
183 | }
184 | else {
185 | HBCircle circle = c.circ();
186 | shapeR.circle((float)circle.getX(), (float)circle.getY(), .5f*(float)circle.getDiam());
187 | }
188 | }
189 | shapeR.end();
190 |
191 | spriteB.begin();
192 |
193 | font.setColor(Color.WHITE);
194 | for(Component c : messageComps) {
195 | String message = c.getMessage();
196 | BitmapFont.TextBounds tb = font.getBounds(message);
197 | float x = (float)c.hitBox().getX() - .5f*tb.width;
198 | float y = (float)c.hitBox().getY() + .5f*tb.height;
199 | font.draw(spriteB, message, x, y);
200 | }
201 |
202 | if(drawFPS) {
203 | font.draw(spriteB, "FPS: "+ Gdx.graphics.getFramesPerSecond(), 0, SCREEN_HEIGHT);
204 | }
205 |
206 | spriteB.end();
207 |
208 | renderWork += (TimeUtils.nanoTime() - startNanoTime);
209 | }
210 |
211 | public void dispose() {
212 | shapeR.dispose();
213 | spriteB.dispose();
214 | font.dispose();
215 | }
216 |
217 | private class LogEvent extends FunctionEvent {
218 | private LogEvent(double time) {super(time);}
219 |
220 | @Override public void resolve() {
221 | collider.log();
222 | System.out.println("Free Memory: " + Runtime.getRuntime().freeMemory());
223 | System.out.println("Total Memory: " + Runtime.getRuntime().totalMemory());
224 | System.out.println("Rendering Work: " + renderWork*1e-9);
225 | System.out.println("Other Work: " + otherWork*1e-9);
226 | System.out.println("FPS: " + Gdx.graphics.getFramesPerSecond());
227 | renderWork = 0;
228 | otherWork = 0;
229 | setTime(getTime() + 3.0);
230 | addEvent(this);
231 | }
232 | }
233 |
234 | private static class MyColliderListener implements ColliderListener {
235 | @Override public void collision(ColliderEvent evt) {
236 | Component compA = (Component)evt.getFirst().getOwner();
237 | Component compB = (Component)evt.getSecond().getOwner();
238 | compA.onCollide(compB);
239 | if(!compA.isDeleted() && !compB.isDeleted()) compB.onCollide(compA);
240 | }
241 | @Override public void separation(ColliderEvent evt) {
242 | Component compA = (Component)evt.getFirst().getOwner();
243 | Component compB = (Component)evt.getSecond().getOwner();
244 | compA.onSeparate(compB);
245 | if(!compA.isDeleted() && !compB.isDeleted()) compB.onSeparate(compA);
246 | }
247 | }
248 |
249 | private class EventProcess implements ContProcess {
250 | @Override public double peekNextEventTime() {
251 | FunctionEvent event = events.peek();
252 | if(event == null) return Double.POSITIVE_INFINITY;
253 | return event.getTime();
254 | }
255 | @Override public void stepToTime(double time) {}
256 | @Override public void resolveEvent() {
257 | FunctionEvent event = events.poll();
258 | if(event.getTime() == processes.getTime()) event.resolve();
259 | }
260 | }
261 |
262 | private static class CompInteractTester implements InteractTester {
263 | @Override public boolean canInteract(HitBox a, HitBox b) {
264 | Component compA = (Component)a.getOwner();
265 | Component compB = (Component)b.getOwner();
266 | return compA.canInteract(compB) || compB.canInteract(compA);
267 | }
268 |
269 | @Override public int[] getInteractGroups(HitBox hitBox) {
270 | if(((Component)hitBox.getOwner()).interactsWithBullets()) return ALL_GROUPS_ARR;
271 | return NORMAL_GROUP_ARR;
272 | }
273 | }
274 | }
275 |
--------------------------------------------------------------------------------
/core/src/com/matthewmichelotti/collider/CollisionTester.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013-2014 Matthew D. Michelotti
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.matthewmichelotti.collider;
18 |
19 | final class CollisionTester {
20 | private double separateBuffer;
21 | private HBRect dummyRect = new HBRect(null);
22 | private HBCircle dummyPoint = new HBCircle(null);
23 | private HBRect dummyRect2 = new HBRect(null);
24 | private HBCircle dummyCircle = new HBCircle(null);
25 | private Normal normal = new Normal();
26 |
27 | CollisionTester(ColliderOpts opts) {
28 | this.separateBuffer = opts.separateBuffer;
29 | if(this.separateBuffer <= 0.0) throw new IllegalArgumentException();
30 | }
31 |
32 | double collideTime(HitBox a, HitBox b, double startTime) {
33 | double endTime = Arith.min(a.endTime, b.endTime);
34 | if(endTime <= startTime) return Double.POSITIVE_INFINITY;
35 | if(!boundBoxTest(a, b, startTime, endTime)) return Double.POSITIVE_INFINITY;
36 | return getTime(a, b, startTime, endTime, true);
37 | }
38 |
39 | double separateTime(HitBox a, HitBox b, double startTime) {
40 | double endTime = Arith.min(a.endTime, b.endTime);
41 | if(endTime <= startTime) return Double.POSITIVE_INFINITY;
42 | boolean aIsRect = (a.getClass() == HBRect.class);
43 | boolean bIsRect = (b.getClass() == HBRect.class);
44 | if(aIsRect && bIsRect) {
45 | HBRect rect = (HBRect)a;
46 | double hw = rect.startHW;
47 | double hh = rect.startHH;
48 | rect.startHW += separateBuffer;
49 | rect.startHH += separateBuffer;
50 | double result = getTime(a, b, startTime, endTime, false);
51 | rect.startHW = hw;
52 | rect.startHH = hh;
53 | return result;
54 | }
55 | else {
56 | HBCircle circ = (HBCircle)(aIsRect ? b : a);
57 | double rad = circ.startRad;
58 | circ.startRad += separateBuffer;
59 | double result = getTime(a, b, startTime, endTime, false);
60 | circ.startRad = rad;
61 | return result;
62 | }
63 | }
64 |
65 | Normal normal(HitBox src, HitBox dst, double time) {
66 | if(src.getClass() == HBRect.class) {
67 | if(dst.getClass() == HBRect.class) return rectRectNormal((HBRect)src, (HBRect)dst, time);
68 | else return rectCircNormal((HBRect)src, (HBCircle)dst, time);
69 | }
70 | else {
71 | if(dst.getClass() == HBRect.class) {
72 | Normal normal = rectCircNormal((HBRect)dst, (HBCircle)src, time);
73 | normal.x = -normal.x;
74 | normal.y = -normal.y;
75 | return normal;
76 | }
77 | else return circCircNormal((HBCircle)src, (HBCircle)dst, time);
78 | }
79 | }
80 |
81 | private double getTime(HitBox a, HitBox b, double startTime, double endTime, boolean forCollide) {
82 | boolean aIsRect = (a.getClass() == HBRect.class);
83 | boolean bIsRect = (b.getClass() == HBRect.class);
84 | double result;
85 | if(aIsRect) {
86 | if(bIsRect) result = rectRectTime((HBRect)a, (HBRect)b, startTime, endTime, forCollide);
87 | else result = rectCircTime((HBRect)a, (HBCircle)b, startTime, endTime, forCollide);
88 | }
89 | else {
90 | if(bIsRect) result = rectCircTime((HBRect)b, (HBCircle)a, startTime, endTime, forCollide);
91 | else result = circCircTime((HBCircle)a, (HBCircle)b, startTime, forCollide);
92 | }
93 | if(result >= endTime) result = Double.POSITIVE_INFINITY;
94 | return result;
95 | }
96 |
97 | private double rectCircTime(HBRect a, HBCircle b, double startTime, double endTime,
98 | boolean forCollide)
99 | {
100 | if(forCollide) return rectCircCollideTime(a, b, startTime, endTime);
101 | else return rectCircSeparateTime(a, b, startTime, endTime);
102 | }
103 |
104 | private static boolean boundBoxTest(HitBox a, HitBox b, double startTime, double endTime) {
105 | for(int dir = 0; dir < 4; dir++) {
106 | double overlap = a.getBoundEdgeComp(dir, startTime, endTime)
107 | + b.getBoundEdgeComp(Dir.opp(dir), startTime, endTime);
108 | if(overlap <= 0.0) return false;
109 | }
110 | return true;
111 | }
112 |
113 | private static double rectRectTime(HBRect a, HBRect b, double startTime, double endTime,
114 | boolean forCollide)
115 | {
116 | double overlapStart = 0.0;
117 | double overlapEnd = 1.05*(endTime - startTime);
118 |
119 | for(int dir = 0; dir < 4; dir++) {
120 | double overlap = a.getEdgeComp(dir, startTime) + b.getEdgeComp(Dir.opp(dir), startTime);
121 | double overlapVel = a.getVelEdgeComp(dir) + b.getVelEdgeComp(Dir.opp(dir));
122 | if(overlap < 0.0) {
123 | if(!forCollide) return startTime;
124 | if(overlapVel <= 0.0) return Double.POSITIVE_INFINITY;
125 | else overlapStart = Arith.max(overlapStart, -overlap/overlapVel);
126 | }
127 | else if(overlapVel < 0.0) {
128 | overlapEnd = Arith.min(overlapEnd, -overlap/overlapVel);
129 | }
130 | if(overlapStart >= overlapEnd) return forCollide ? Double.POSITIVE_INFINITY : startTime;
131 | }
132 |
133 | return startTime + (forCollide ? overlapStart : overlapEnd);
134 | }
135 |
136 | private static double circCircTime(HBCircle a, HBCircle b, double startTime, boolean forCollide)
137 | {
138 | double sign = forCollide ? 1.0 : -1.0;
139 |
140 | double netRad = a.getRad(startTime) + b.getRad(startTime);
141 | double distX = a.getX(startTime) - b.getX(startTime);
142 | double distY = a.getY(startTime) - b.getY(startTime);
143 |
144 | double coeffC = sign*(netRad*netRad - distX*distX - distY*distY);
145 | if(coeffC > 0.0) return startTime;
146 |
147 | double netRadVel = a.velRad + b.velRad;
148 | double distXVel = a.velX - b.velX;
149 | double distYVel = a.velY - b.velY;
150 |
151 | double coeffA = sign*(netRadVel*netRadVel - distXVel*distXVel - distYVel*distYVel);
152 | double coeffB = sign*2.0*(netRad*netRadVel - distX*distXVel - distY*distYVel);
153 |
154 | double result = Arith.quadRootAscending(coeffA, coeffB, coeffC);
155 | if(result >= 0.0) return startTime + result;
156 | else return Double.POSITIVE_INFINITY; //NOTE: handles NaN case
157 | }
158 |
159 | private double rectCircCollideTime(HBRect a, HBCircle b, double startTime, double endTime)
160 | {
161 | // if(!forCollide) {
162 | // pair.init(a, b);
163 | // double overlap = pair.getOverlap();
164 | // pair.clear();
165 | // if(overlap <= 0.0) return startTime;
166 | // }
167 | dummyRect.dummyMimicCircle(b);
168 | double time = rectRectTime(a, dummyRect, startTime, endTime, true);
169 | if(time >= endTime) return Double.POSITIVE_INFINITY;
170 | // if(time >= endTime) {
171 | // if(forCollide) return Double.POSITIVE_INFINITY;
172 | // else time = endTime;
173 | // }
174 |
175 | for(int dir = 0; dir < 2; dir++) {
176 | double hiEdge = a.getEdgeComp(dir, time);
177 | double loEdge = -a.getEdgeComp(Dir.opp(dir), time);
178 | double bCoord = b.getPosComp(dir, time);
179 | if(bCoord > hiEdge) {
180 | dummyPoint.dummySetStartCoord(dir, hiEdge);
181 | dummyPoint.dummySetVelCoord(dir, a.getVelEdgeComp(dir));
182 | }
183 | else if(bCoord < loEdge) {
184 | dummyPoint.dummySetStartCoord(dir, loEdge);
185 | dummyPoint.dummySetVelCoord(dir, -a.getVelEdgeComp(Dir.opp(dir)));
186 | }
187 | else return time;
188 | }
189 | dummyPoint.startTime = time;
190 | return circCircTime(dummyPoint, b, startTime, true);
191 | }
192 |
193 | private double rectCircSeparateTime(HBRect a, HBCircle b, double startTime, double endTime) {
194 | Normal normal = normal(a, b, startTime);
195 | if(normal.overlap <= 0.0) return startTime;
196 | mirror(a, dummyRect2, endTime);
197 | mirror(b, dummyCircle, endTime);
198 | dummyRect2.startTime = 0.0;
199 | dummyCircle.startTime = 0.0;
200 | double result = rectCircCollideTime(dummyRect2, dummyCircle, 0.0, endTime - startTime);
201 | return Arith.max(startTime, endTime - result);
202 | }
203 |
204 | private static void mirror(HBRect original, HBRect mirror, double endTime) {
205 | mirrorPos(original, mirror, endTime);
206 | mirror.startHW = original.getHW(endTime);
207 | mirror.startHH = original.getHH(endTime);
208 | mirror.velHW = -original.velHW;
209 | mirror.velHH = -original.velHH;
210 | }
211 |
212 | private static void mirror(HBCircle original, HBCircle mirror, double endTime) {
213 | mirrorPos(original, mirror, endTime);
214 | mirror.startRad = original.getRad(endTime);
215 | mirror.velRad = -original.velRad;
216 | }
217 |
218 | private static void mirrorPos(HBPositioned original, HBPositioned mirror, double endTime) {
219 | mirror.startX = original.getX(endTime);
220 | mirror.startY = original.getY(endTime);
221 | mirror.velX = -original.velX;
222 | mirror.velY = -original.velY;
223 | }
224 |
225 | private Normal rectRectNormal(HBRect src, HBRect dst, double time) {
226 | int minDir = 0;
227 | double overlap = Double.POSITIVE_INFINITY;
228 | for(int dir = 0; dir < 4; dir++) {
229 | double testOverlap = src.getEdgeComp(dir, time)
230 | + dst.getEdgeComp(Dir.opp(dir), time);
231 | if(testOverlap < overlap) {
232 | overlap = testOverlap;
233 | minDir = dir;
234 | }
235 | }
236 | normal.x = Dir.x(minDir);
237 | normal.y = Dir.y(minDir);
238 | normal.overlap = overlap;
239 | return normal;
240 | }
241 |
242 | private Normal circCircNormal(HBCircle src, HBCircle dst, double time) {
243 | double nx = dst.getX(time) - src.getX(time);
244 | double ny = dst.getY(time) - src.getY(time);
245 | double dist = Math.sqrt(nx*nx + ny*ny);
246 | if(dist == 0.0) {
247 | nx = 1.0;
248 | ny = 0.0;
249 | }
250 | else {//NOTE: if dist != 0.0, dist is at least Math.sqrt(Double.MIN_VALUE)
251 | double invNMag = 1.0/dist;
252 | nx *= invNMag;
253 | ny *= invNMag;
254 | }
255 | normal.x = nx;
256 | normal.y = ny;
257 | normal.overlap = src.getRad(time) + dst.getRad(time) - dist;
258 | return normal;
259 | }
260 |
261 | private Normal rectCircNormal(HBRect src, HBCircle dst, double time) {
262 | for(int dir = 0; dir < 2; dir++) {
263 | double dstCoord = dst.getPosComp(dir, time);
264 | double srcHi = src.getEdgeComp(dir, time);
265 | double srcLo = -src.getEdgeComp(Dir.opp(dir), time);
266 | if(dstCoord > srcHi) dummyPoint.dummySetStartCoord(dir, srcHi);
267 | else if(dstCoord < srcLo) dummyPoint.dummySetStartCoord(dir, srcLo);
268 | else {
269 | dummyRect.dummyMimicCircle(dst);
270 | return rectRectNormal(src, dummyRect, time);
271 | }
272 | }
273 | dummyPoint.velX = 0.0;
274 | dummyPoint.velY = 0.0;
275 | return circCircNormal(dummyPoint, dst, time);
276 | }
277 | }
278 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------