Added ParticleEngineCellularImplementation + tests; still a lot of things to improve...
[desert.git] / src / org / sourceforge / desert / ParticleEngineCustomImplementation.java
blobe6524ef94565416fb95507ce97eb74c4fb191d7b
1 /*
2 * Copyright (c) 2010 The Desert team
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use,
8 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following
11 * conditions:
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
26 package org.sourceforge.desert;
28 import static org.sourceforge.desert.Utilities.*;
30 /**
32 * @author codistmonk (creation 2010-04-13)
34 public class ParticleEngineCustomImplementation extends AbstractParticleEngineCustomImplementation {
36 private int lastParticleCount;
38 private Particle[][] grid;
40 @Override
41 public final void update(final float deltaTime) {
42 this.updateGrid();
44 for (final Particle particle : this) {
45 if (particle.getType().isMobile()) {
46 this.updateSpeed((ParticleDefaultImplementation) particle, deltaTime);
50 for (final Particle particle : this) {
51 if (particle.getType().isMobile()) {
52 this.updatePosition((ParticleDefaultImplementation) particle, deltaTime);
57 @Override
58 protected final void boardSizeChanged() {
59 if (this.getBoardSize() != null && this.getBoardSize().width > 0 && this.getBoardSize().height > 0) {
60 this.grid = new ParticleDefaultImplementation[this.getBoardSize().width][this.getBoardSize().height];
62 for (final Particle particle : this) {
63 if (0 <= particle.getX() && particle.getX() < this.grid.length && 0 <= particle.getY() && particle.getY() < this.grid[0].length) {
64 this.grid[(int) particle.getX()][(int) particle.getY()] = particle;
68 else {
69 this.grid = null;
73 @Override
74 protected final void particleAdded(final ParticleDefaultImplementation particle) {
75 if (this.grid != null && 0 <= particle.getX() && particle.getX() < this.grid.length && 0 <= particle.getY() && particle.getY() < this.grid[0].length) {
76 this.grid[(int) particle.getX()][(int) particle.getY()] = particle;
80 private final void updateGrid() {
81 if (this.grid != null && this.lastParticleCount != this.getParticleCount()) {
82 for (int x = 0; x < this.grid.length; ++x) {
83 for (int y = 0; y < this.grid[0].length; ++y) {
84 this.grid[x][y] = null;
88 for (final Particle particle : this) {
89 final int x = (int) particle.getX();
90 final int y = (int) particle.getY();
92 if (0 <= x && x < this.grid.length && 0 <= y && y < this.grid[0].length) {
93 this.grid[x][y] = particle;
97 this.lastParticleCount = this.getParticleCount();
103 * @param particle A mobile particle
104 * <br>Should not be null
105 * <br>Input-output parameter
106 * @param deltaTime
107 * <br>Range: <code>[0F .. Float.POSITIVE_INFINITY[</code>
109 private final void updateSpeed(final ParticleDefaultImplementation particle, final float deltaTime) {
110 // Gravity effect
111 particle.setSpeedY(particle.getSpeedY() + this.getGravity() * deltaTime);
113 // Collisions with surrounding cells
114 for (int i = -1; i <= 1; ++i) {
115 for (int j = -1; j <= 1; ++j) {
116 if (i != 0 || j != 0) {
117 this.collision(particle, (int) (particle.getX() + i), (int) (particle.getY() + j));
122 constrainSpeed(particle);
127 * @param particle
128 * <br>Should not be null
129 * <br>Input-output parameter
130 * @param x
131 * <br>Range: Any integer
132 * @param y
133 * <br>Range: Any integer
135 private final void collision(final ParticleDefaultImplementation particle, final int x, final int y) {
136 if (this.grid != null && 0 <= x && x < this.grid.length && 0 <= y && y < this.grid[0].length && this.grid[x][y] != null) {
137 final Particle other = this.grid[x][y];
138 float uX = other.getX() - particle.getX();
139 float uY = other.getY() - particle.getY();
140 final float u = length(uX, uY);
142 if (0F < u && u <= particle.getType().getRadius() + other.getType().getRadius()) {
143 uX /= u;
144 uY /= u;
146 final float otherCollisionSpeed = other.getSpeedX() * uX + other.getSpeedY() * uY;
147 final float collisionSpeed = particle.getSpeedX() * uX + particle.getSpeedY() * uY;
149 if (collisionSpeed > 0 && otherCollisionSpeed <= 0) {
150 // TODO use particles masses
151 particle.setSpeedX(particle.getSpeedX() - 2F * collisionSpeed * uX);
152 particle.setSpeedY(particle.getSpeedY() - 2F * collisionSpeed * uY);
160 * @param particle A mobile particle
161 * <br>Should not be null
162 * <br>Input-output parameter
163 * @param deltaTime
164 * <br>Range: <code>[0F .. Float.POSITIVE_INFINITY[</code>
166 private final void updatePosition(final ParticleDefaultImplementation particle, final float deltaTime) {
167 float deltaX = particle.getSpeedX() * deltaTime;
168 float deltaY = particle.getSpeedY() * deltaTime;
169 final int pixelCount = 1 + ((int) length(deltaX, deltaY));
170 deltaX /= pixelCount;
171 deltaY /= pixelCount;
173 for (int i = 0; i < pixelCount; ++i) {
174 int x = (int) particle.getX();
175 int y = (int) particle.getY();
177 if (this.grid != null && 0 <= x && x < this.grid.length && 0 <= y && y < this.grid[0].length && this.grid[x][y] == particle) {
178 this.grid[x][y] = null;
181 particle.setX(particle.getX() + deltaX);
182 particle.setY(particle.getY() + deltaY);
184 if (this.grid != null) {
185 x = (int) particle.getX();
186 y = (int) particle.getY();
188 if (0 <= x && x < this.grid.length && 0 <= y && y < this.grid[0].length && this.grid[x][y] == null) {
189 this.grid[x][y] = particle;
191 else {
192 particle.setX(particle.getX() - 2F * deltaX);
193 particle.setY(particle.getY() - 2F * deltaY);
194 break;
199 this.constrainPosition(particle);