Added example project doc
This commit is contained in:
commit
f3d2740a25
17
demo1/.editorconfig
Normal file
17
demo1/.editorconfig
Normal file
@ -0,0 +1,17 @@
|
||||
# Editor configuration, see http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
max_line_length = 80
|
||||
|
||||
[*.sh]
|
||||
end_of_line = lf
|
||||
|
||||
[*.java]
|
||||
indent_size = 4
|
||||
max_line_length = 120
|
2
demo1/.gitattributes
vendored
Normal file
2
demo1/.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# When shell scripts end in CRLF, bash gives a cryptic error message
|
||||
*.sh text eol=lf
|
28
demo1/.gitignore
vendored
Normal file
28
demo1/.gitignore
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
#
|
||||
# Standard Maven .gitignore
|
||||
#
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
|
||||
#
|
||||
# IntelliJ
|
||||
#
|
||||
*.iml
|
||||
.idea/*
|
||||
!.idea/runConfigurations/
|
||||
|
||||
#
|
||||
# Visual Studio Code
|
||||
#
|
||||
.settings/
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.vscode/
|
4
demo1/.travis.yml
Normal file
4
demo1/.travis.yml
Normal file
@ -0,0 +1,4 @@
|
||||
language: java
|
||||
jdk: openjdk8
|
||||
after_success:
|
||||
- mvn coveralls:report
|
200
demo1/pom.xml
Normal file
200
demo1/pom.xml
Normal file
@ -0,0 +1,200 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>nz.ac.massey.javaecs.examples</groupId>
|
||||
<artifactId>demo1</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<junit.version>5.6.0</junit.version>
|
||||
<maven-enforcer-plugin.version>3.0.0-M3</maven-enforcer-plugin.version>
|
||||
<maven-checkstyle-plugin.version>3.1.0</maven-checkstyle-plugin.version>
|
||||
<checkstyle.version>8.29</checkstyle.version>
|
||||
<checkstyle-rules.version>4.0.1</checkstyle-rules.version>
|
||||
<maven-surefire-plugin.version>3.0.0-M4</maven-surefire-plugin.version>
|
||||
<jacoco-maven-plugin.version>0.8.4</jacoco-maven-plugin.version>
|
||||
<maven-javadoc-plugin.version>3.0.0</maven-javadoc-plugin.version>
|
||||
<coveralls-maven-plugin.version>4.3.0</coveralls-maven-plugin.version>
|
||||
<!-- JaCoCo thresholds. Increase gradually as you add tests. -->
|
||||
<jacoco.unit-tests.limit.instruction-ratio>0%</jacoco.unit-tests.limit.instruction-ratio>
|
||||
<jacoco.unit-tests.limit.branch-ratio>0%</jacoco.unit-tests.limit.branch-ratio>
|
||||
<jacoco.unit-tests.limit.class-complexity>20</jacoco.unit-tests.limit.class-complexity>
|
||||
<jacoco.unit-tests.limit.method-complexity>5</jacoco.unit-tests.limit.method-complexity>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>nz.ac.massey.javaecs</groupId>
|
||||
<artifactId>javaecs</artifactId>
|
||||
<version>0.9.2-PRERELEASE</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>${maven-enforcer-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<requireMavenVersion>
|
||||
<version>3.6.3</version>
|
||||
</requireMavenVersion>
|
||||
</rules>
|
||||
<fail>true</fail>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>${maven-checkstyle-plugin.version}</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.puppycrawl.tools</groupId>
|
||||
<artifactId>checkstyle</artifactId>
|
||||
<version>${checkstyle.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.ngeor</groupId>
|
||||
<artifactId>checkstyle-rules</artifactId>
|
||||
<version>${checkstyle-rules.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<configuration>
|
||||
<configLocation>com/github/ngeor/checkstyle.xml</configLocation>
|
||||
<includeTestSourceDirectory>true</includeTestSourceDirectory>
|
||||
<skip>${skipTests}</skip>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>checkstyle</id>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${maven-surefire-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>${jacoco-maven-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>pre-unit-test</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>post-unit-test</id>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>check-unit-test</id>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<dataFile>${project.build.directory}/jacoco.exec</dataFile>
|
||||
<rules>
|
||||
<rule>
|
||||
<element>BUNDLE</element>
|
||||
<limits>
|
||||
<limit>
|
||||
<counter>INSTRUCTION</counter>
|
||||
<value>COVEREDRATIO</value>
|
||||
<minimum>${jacoco.unit-tests.limit.instruction-ratio}</minimum>
|
||||
</limit>
|
||||
<limit>
|
||||
<counter>BRANCH</counter>
|
||||
<value>COVEREDRATIO</value>
|
||||
<minimum>${jacoco.unit-tests.limit.branch-ratio}</minimum>
|
||||
</limit>
|
||||
</limits>
|
||||
</rule>
|
||||
<rule>
|
||||
<element>CLASS</element>
|
||||
<limits>
|
||||
<limit>
|
||||
<counter>COMPLEXITY</counter>
|
||||
<value>TOTALCOUNT</value>
|
||||
<maximum>${jacoco.unit-tests.limit.class-complexity}</maximum>
|
||||
</limit>
|
||||
</limits>
|
||||
</rule>
|
||||
<rule>
|
||||
<element>METHOD</element>
|
||||
<limits>
|
||||
<limit>
|
||||
<counter>COMPLEXITY</counter>
|
||||
<value>TOTALCOUNT</value>
|
||||
<maximum>${jacoco.unit-tests.limit.method-complexity}</maximum>
|
||||
</limit>
|
||||
</limits>
|
||||
</rule>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>${maven-javadoc-plugin.version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
<profiles>
|
||||
<!-- Publish coverage report to Coveralls, only when running in Travis. -->
|
||||
<profile>
|
||||
<id>travis</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>env.TRAVIS</name>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.eluder.coveralls</groupId>
|
||||
<artifactId>coveralls-maven-plugin</artifactId>
|
||||
<version>${coveralls-maven-plugin.version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
129
demo1/src/main/java/nz/ac/massey/javaecs/examples/App.java
Normal file
129
demo1/src/main/java/nz/ac/massey/javaecs/examples/App.java
Normal file
@ -0,0 +1,129 @@
|
||||
package nz.ac.massey.javaecs.examples;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import nz.ac.massey.javaecs.*;
|
||||
import nz.ac.massey.javaecs.examples.Components.*;
|
||||
import nz.ac.massey.javaecs.examples.Systems.*;
|
||||
|
||||
/**
|
||||
* Physics simulation app
|
||||
*/
|
||||
public final class App {
|
||||
private App() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple physics simulation.
|
||||
* @param args The arguments of the program.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
Engine gameEngine = new Engine(16384);
|
||||
|
||||
gameEngine.registerComponent(Gravity.class);
|
||||
gameEngine.registerComponent(RidgidBody.class);
|
||||
gameEngine.registerComponent(Vec2D.class);
|
||||
gameEngine.registerComponent(Collider.class);
|
||||
gameEngine.registerComponent(LogUpdate.class);
|
||||
gameEngine.registerComponent(Render.class);
|
||||
gameEngine.registerComponent(BoxRender.class);
|
||||
|
||||
PhysicsSystem physicsSystem = new PhysicsSystem(gameEngine);
|
||||
gameEngine.registerSystem(PhysicsSystem.class, physicsSystem);
|
||||
|
||||
|
||||
CollisionSystem collisionSystem = new CollisionSystem(gameEngine);
|
||||
gameEngine.registerSystem(CollisionSystem.class, collisionSystem);
|
||||
|
||||
LogUpdateSystem logUpdateSystem = new LogUpdateSystem(gameEngine);
|
||||
gameEngine.registerSystem(LogUpdateSystem.class, logUpdateSystem);
|
||||
|
||||
RenderSystem renderSystem = new RenderSystem(gameEngine, 10.);
|
||||
gameEngine.registerSystem(RenderSystem.class, renderSystem);
|
||||
|
||||
// Define a play area 100 * 100, make sure to use worldspace not screenspace (top left is 0, 100, not 0,0)
|
||||
// Bottom boundary
|
||||
Entity newEnt = gameEngine.createEntity();
|
||||
gameEngine.addComponent(newEnt, Vec2D.class, new Vec2D(-50., -50.,0));
|
||||
gameEngine.addComponent(newEnt, RidgidBody.class, new RidgidBody(0., 0., 0., 0., 0.f, 0., -1.));
|
||||
gameEngine.addComponent(newEnt, Collider.class, new Collider(200., 50.)); // 200 along, 50 up
|
||||
gameEngine.addComponent(newEnt, Render.class, new Render(BoxRender.class));
|
||||
gameEngine.addComponent(newEnt, BoxRender.class, new BoxRender(200, 50, 64, 64, 64));
|
||||
// Left boundary
|
||||
newEnt = gameEngine.createEntity();
|
||||
gameEngine.addComponent(newEnt, Vec2D.class, new Vec2D(-50., -50.,0));
|
||||
gameEngine.addComponent(newEnt, RidgidBody.class, new RidgidBody(0., 0., 0., 0., 0.f, 0., -1.));
|
||||
gameEngine.addComponent(newEnt, Collider.class, new Collider(50., 200.));
|
||||
gameEngine.addComponent(newEnt, Render.class, new Render(BoxRender.class));
|
||||
gameEngine.addComponent(newEnt, BoxRender.class, new BoxRender(50, 200, 64, 64, 64));
|
||||
// Top boundary
|
||||
newEnt = gameEngine.createEntity();
|
||||
gameEngine.addComponent(newEnt, Vec2D.class, new Vec2D(-50., 100.,0));
|
||||
gameEngine.addComponent(newEnt, RidgidBody.class, new RidgidBody(0., 0., 0., 0., 0.f, 0., -1.));
|
||||
gameEngine.addComponent(newEnt, Collider.class, new Collider(200., 50.));
|
||||
gameEngine.addComponent(newEnt, Render.class, new Render(BoxRender.class));
|
||||
gameEngine.addComponent(newEnt, BoxRender.class, new BoxRender(200, 50, 64, 64, 64));
|
||||
// Right boundary
|
||||
newEnt = gameEngine.createEntity();
|
||||
gameEngine.addComponent(newEnt, Vec2D.class, new Vec2D(100., -50.,0));
|
||||
gameEngine.addComponent(newEnt, RidgidBody.class, new RidgidBody(0., 0., 0., 0., 0.f, 0., -1.));
|
||||
gameEngine.addComponent(newEnt, Collider.class, new Collider(50., 200.));
|
||||
gameEngine.addComponent(newEnt, Render.class, new Render(BoxRender.class));
|
||||
gameEngine.addComponent(newEnt, BoxRender.class, new BoxRender(50, 200, 64, 64, 64));
|
||||
// One object
|
||||
newEnt = gameEngine.createEntity();
|
||||
gameEngine.addComponent(newEnt, Vec2D.class, new Vec2D(62., 90.,0));
|
||||
gameEngine.addComponent(newEnt, RidgidBody.class, new RidgidBody(1., 0., 0., 0., 0.f, 0., 1.));
|
||||
gameEngine.addComponent(newEnt, Collider.class, new Collider(10., 10.));
|
||||
gameEngine.addComponent(newEnt, Gravity.class, new Gravity(0, -9.80665, 45., 45.)); // Terminal velocity is 45 m/s
|
||||
gameEngine.addComponent(newEnt, Render.class, new Render(BoxRender.class));
|
||||
gameEngine.addComponent(newEnt, BoxRender.class, new BoxRender(10, 10, 255, 64, 64));
|
||||
// Other objects
|
||||
Random rand = new Random();
|
||||
for (int i = 0; i < 100; i++) {
|
||||
newEnt = gameEngine.createEntity();
|
||||
gameEngine.addComponent(newEnt, Vec2D.class, new Vec2D(10 + rand.nextDouble()* 80, 10+ rand.nextDouble()* 80,0));
|
||||
gameEngine.addComponent(newEnt, RidgidBody.class, new RidgidBody(-2.5 + rand.nextDouble()* 5., 0., 0., 0., 0.f, 0., rand.nextDouble() * 20.));
|
||||
double size = 3 + rand.nextDouble() * 7;
|
||||
gameEngine.addComponent(newEnt, Collider.class, new Collider(size, size));
|
||||
gameEngine.addComponent(newEnt, Gravity.class, new Gravity(0, -9.80665, 45., 45.)); // Terminal velocity is 45 m/s
|
||||
gameEngine.addComponent(newEnt, LogUpdate.class, null); // Add to object to print pos of
|
||||
gameEngine.addComponent(newEnt, Render.class, new Render(BoxRender.class));
|
||||
gameEngine.addComponent(newEnt, BoxRender.class, new BoxRender(size, size, 30 + rand.nextInt(225), 30 + rand.nextInt(225), 30 + rand.nextInt(225)));
|
||||
}
|
||||
|
||||
//gameEngine.addComponent(newEnt, LogUpdate.class, null);
|
||||
|
||||
|
||||
physicsSystem.init();
|
||||
collisionSystem.init();
|
||||
logUpdateSystem.init();
|
||||
renderSystem.init();
|
||||
|
||||
double dt = 0.;
|
||||
double frameRate = 1.0 / 144; // 1 second divided by target number of frames
|
||||
double idleTime = 0.0; // the amount of time spent sleeping
|
||||
|
||||
boolean exit = false;
|
||||
long loopStart = System.currentTimeMillis();
|
||||
long startTime = System.nanoTime();
|
||||
while (!exit){
|
||||
|
||||
collisionSystem.update();
|
||||
physicsSystem.update(dt);
|
||||
//logUpdateSystem.update();
|
||||
// The render system should be uncoupled from the physics and collision
|
||||
renderSystem.update();
|
||||
|
||||
dt = (System.nanoTime() - startTime) / 1e9; // convert nanoseconds to seconds
|
||||
startTime = System.nanoTime();
|
||||
if (dt < frameRate){
|
||||
idleTime = frameRate-dt;
|
||||
Thread.sleep((int)((frameRate-dt)*1000));
|
||||
dt = (System.nanoTime() - startTime) / 1e9;
|
||||
startTime = System.nanoTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package nz.ac.massey.javaecs.examples.Components;
|
||||
|
||||
public class BoxRender {
|
||||
|
||||
public double r = 255;
|
||||
public double g = 255;
|
||||
public double b = 255;
|
||||
|
||||
public double xSize = 0.0;
|
||||
public double ySize = 0.0;
|
||||
|
||||
public BoxRender(double xSize, double ySize, int red, int green, int blue){
|
||||
this.xSize = xSize;
|
||||
this.ySize = ySize;
|
||||
r = red/255.;
|
||||
g = green/255.;
|
||||
b = blue/255.;
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package nz.ac.massey.javaecs.examples.Components;
|
||||
|
||||
public class Collider {
|
||||
public Collider(double x, double y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
// bottom-right, top-right is specified by position
|
||||
public double x = 0.0;
|
||||
public double y = 0.0;
|
||||
public boolean collided = false;
|
||||
|
||||
public double travelDirection = 0.0;
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package nz.ac.massey.javaecs.examples.Components;
|
||||
|
||||
public class Gravity {
|
||||
public Gravity(){
|
||||
}
|
||||
|
||||
public Gravity(double x, double y){
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
public Gravity(double x, double y, double terminalX, double terminalY){
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.terminalX = terminalX;
|
||||
this.terminalY = terminalY;
|
||||
}
|
||||
public double x = 0.0;
|
||||
public double y = -9.80665; // Force of gravity (from https://www.bipm.org/en/publications/si-brochure - 9th edition - p159 - Bureau International des Poids et Mesures - CC BY 4.0)
|
||||
// Acceleration due to gravity won't be considered if the speed exceeds this. i.e. Negative values are ignored (unlimited)
|
||||
public double terminalX = -1.0;
|
||||
public double terminalY = -1.0;
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package nz.ac.massey.javaecs.examples.Components;
|
||||
|
||||
public class LogUpdate {
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package nz.ac.massey.javaecs.examples.Components;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public class Render {
|
||||
public Type renderType;
|
||||
|
||||
public Render(Type t){
|
||||
renderType = t;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package nz.ac.massey.javaecs.examples.Components;
|
||||
|
||||
public class RidgidBody {
|
||||
public RidgidBody(){}
|
||||
public RidgidBody(double xVel, double yVel, double xAcc, double yAcc, float compressability, double bounciness, double mass){
|
||||
this.xVel = xVel;
|
||||
this.yVel = yVel;
|
||||
this.xAcc = xAcc;
|
||||
this.yAcc = yAcc;
|
||||
this.compressability = compressability;
|
||||
this.bounciness = bounciness;
|
||||
this.mass = mass;
|
||||
}
|
||||
|
||||
// Velocities
|
||||
public double xVel = 0.0;
|
||||
public double yVel = 0.0;
|
||||
// accelerations
|
||||
public double xAcc = 0.0;
|
||||
public double yAcc = 0.0;
|
||||
// physical properties
|
||||
public float compressability = 0.01f; // How much the object can squish the other
|
||||
public double bounciness = 0.75; // How bouncy the object is
|
||||
|
||||
public double mass = 1.0;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package nz.ac.massey.javaecs.examples.Components;
|
||||
|
||||
public class Vec2D {
|
||||
public Vec2D(double x, double y, int z){
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public double x = 0.0;
|
||||
public double y = 0.0;
|
||||
public int z = 0;
|
||||
}
|
@ -0,0 +1,252 @@
|
||||
package nz.ac.massey.javaecs.examples.Systems;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import nz.ac.massey.javaecs.ECSSystem;
|
||||
import nz.ac.massey.javaecs.Engine;
|
||||
import nz.ac.massey.javaecs.Entity;
|
||||
import nz.ac.massey.javaecs.examples.Components.Collider;
|
||||
import nz.ac.massey.javaecs.examples.Components.Gravity;
|
||||
import nz.ac.massey.javaecs.examples.Components.RidgidBody;
|
||||
import nz.ac.massey.javaecs.examples.Components.Vec2D;
|
||||
|
||||
public class CollisionSystem extends ECSSystem {
|
||||
Engine gameEngine;
|
||||
|
||||
public CollisionSystem(Engine gameEngine) {
|
||||
this.gameEngine = gameEngine;
|
||||
// Set registrations
|
||||
registrationSet = new BitSet();
|
||||
registrationSet.set(gameEngine.getComponentIndex(Vec2D.class));
|
||||
registrationSet.set(gameEngine.getComponentIndex(Collider.class));
|
||||
registrationSet.set(gameEngine.getComponentIndex(RidgidBody.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
public void updateNew() {
|
||||
Set<Entity> processed = new HashSet<>();
|
||||
// Gets all items we have collided with
|
||||
for (Entity entity : entities) {
|
||||
RidgidBody ridgidBody = (RidgidBody) gameEngine.getComponentData(entity, RidgidBody.class);
|
||||
// Only considering elements with mass just now
|
||||
if (ridgidBody.mass > 0){
|
||||
Vec2D pos = (Vec2D) gameEngine.getComponentData(entity, Vec2D.class);
|
||||
Collider collider = (Collider) gameEngine.getComponentData(entity, Collider.class);
|
||||
|
||||
// The pos of each bounding line of the entity
|
||||
// i.e.
|
||||
//
|
||||
// -------------
|
||||
// |###########|
|
||||
// |###########|
|
||||
// |###########|
|
||||
// |###########|
|
||||
// -------------
|
||||
//
|
||||
double eleft = pos.x;
|
||||
double ebottom = pos.y;
|
||||
double eright = pos.x + collider.x;
|
||||
double etop = pos.y + collider.y;
|
||||
|
||||
double evectorAngle = calcAngle(ridgidBody.xVel, ridgidBody.yVel);
|
||||
|
||||
|
||||
if (ridgidBody.mass > 0){
|
||||
// Dont't recalc for entities that aren't static
|
||||
processed.add(entity);
|
||||
}
|
||||
|
||||
for (Entity entity2 : entities) {
|
||||
if (!processed.contains(entity2)) {
|
||||
// skip entities that have already been processed
|
||||
Vec2D oPos = (Vec2D) gameEngine.getComponentData(entity2, Vec2D.class);
|
||||
RidgidBody oRidgidBody = (RidgidBody) gameEngine.getComponentData(entity2, RidgidBody.class);
|
||||
Collider oCollider = (Collider) gameEngine.getComponentData(entity2, Collider.class);
|
||||
|
||||
double oleft = oPos.x;
|
||||
double obottom = oPos.y;
|
||||
double oright = oPos.x + oCollider.x;
|
||||
double otop = oPos.y + oCollider.y;
|
||||
|
||||
// Check if a collision occured
|
||||
// Few conditions required, that is,
|
||||
// - oS2 must be greater than eS0, else they aren't close
|
||||
// - eS2 must be greater than oS0, for the same reason
|
||||
// - either
|
||||
if (!(eleft > oright || oleft > eright || etop < obottom || otop < ebottom)){
|
||||
// Collided
|
||||
// Grab the angle the other is moving, to figure the quadrant to move to
|
||||
double ovectorAngle = calcAngle(oRidgidBody.xVel, oRidgidBody.yVel);
|
||||
// Grab the vector sums
|
||||
double xVelSum = ridgidBody.xVel + oRidgidBody.xVel;
|
||||
double yVelSum = ridgidBody.yVel + oRidgidBody.yVel;
|
||||
// Collision occurred
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
// Parallelising this loop ()
|
||||
Set<Entity> processed = new HashSet<>();
|
||||
// Gets all items we have collided with
|
||||
for (Entity entity : entities) {
|
||||
Vec2D pos = (Vec2D) gameEngine.getComponentData(entity, Vec2D.class);
|
||||
RidgidBody ridgidBody = (RidgidBody) gameEngine.getComponentData(entity, RidgidBody.class);
|
||||
Collider collider = (Collider) gameEngine.getComponentData(entity, Collider.class);
|
||||
if (ridgidBody.mass > 0){
|
||||
// Only ignore non-static colliders
|
||||
processed.add(entity);
|
||||
}
|
||||
for (Entity entity2 : entities) {
|
||||
if (!processed.contains(entity2)) {
|
||||
// skip entities that have already been processed
|
||||
Vec2D otherPos = (Vec2D) gameEngine.getComponentData(entity2, Vec2D.class);
|
||||
RidgidBody otherRidgidBody = (RidgidBody) gameEngine.getComponentData(entity2, RidgidBody.class);
|
||||
Collider otherCollider = (Collider) gameEngine.getComponentData(entity2, Collider.class);
|
||||
|
||||
|
||||
if (ridgidBody.mass >= 0 || otherRidgidBody.mass >= 0) {
|
||||
// Evaluate a collision in the top-left
|
||||
boolean tlCollide = pos.x > otherPos.x && pos.x < otherPos.x + otherCollider.x
|
||||
&& pos.y > otherPos.y && pos.y < otherPos.y + otherCollider.y;
|
||||
// Evaluate a collision in the bottom-left
|
||||
boolean blCollide = pos.x > otherPos.x && pos.x < otherPos.x + otherCollider.x
|
||||
&& pos.y + collider.y > otherPos.y && pos.y + collider.y < otherPos.y + otherCollider.y;
|
||||
// Evaluate a collision in the bottom-right
|
||||
boolean brCollide = pos.x + collider.x > otherPos.x
|
||||
&& pos.x + collider.x < otherPos.x + otherCollider.x && pos.y + collider.y > otherPos.y
|
||||
&& pos.y + collider.y < otherPos.y + otherCollider.y;
|
||||
// Evaluate a collision in the top-right
|
||||
boolean trCollide = pos.x + collider.x > otherPos.x
|
||||
&& pos.x + collider.x < otherPos.x + otherCollider.x && pos.y > otherPos.y
|
||||
&& pos.y < otherPos.y + otherCollider.y;
|
||||
if (tlCollide || blCollide || brCollide || trCollide) {
|
||||
// Determine collision nature
|
||||
if (tlCollide) {
|
||||
int k = 0;
|
||||
}
|
||||
if (trCollide) {
|
||||
int k = 0;
|
||||
}
|
||||
if (blCollide) {
|
||||
int k = 0;
|
||||
}
|
||||
if (brCollide) {
|
||||
int k = 0;
|
||||
}
|
||||
// Get the vels
|
||||
double totalXVel = Math.abs(ridgidBody.xVel) + Math.abs(otherRidgidBody.xVel);
|
||||
double totalYVel = Math.abs(ridgidBody.yVel) + Math.abs(otherRidgidBody.yVel);
|
||||
double totalMass = ridgidBody.mass + otherRidgidBody.mass;
|
||||
int xMult = 0;
|
||||
int yMult = 0;
|
||||
boolean fullEdge = false;
|
||||
// left-hand collision
|
||||
if (tlCollide && blCollide) {
|
||||
fullEdge = true;
|
||||
xMult = 2;
|
||||
}
|
||||
// Bottom collision
|
||||
if (blCollide && brCollide) {
|
||||
fullEdge = true;
|
||||
yMult = -2;
|
||||
}
|
||||
// right-hand collision
|
||||
if (brCollide && trCollide) {
|
||||
fullEdge = true;
|
||||
xMult = -2;
|
||||
}
|
||||
// top collision
|
||||
if (trCollide && tlCollide) {
|
||||
fullEdge = true;
|
||||
yMult = 2;
|
||||
}
|
||||
if (fullEdge) {
|
||||
// Finally, actuate the calculation
|
||||
if (ridgidBody.mass < 0) {
|
||||
// entity 1 is immovable
|
||||
otherRidgidBody.xVel += totalXVel * (-1 * xMult);
|
||||
otherRidgidBody.yVel += totalYVel * (-1 * yMult);
|
||||
|
||||
Object grav = gameEngine.getComponentData(entity, Gravity.class);
|
||||
if (grav != null) {
|
||||
Gravity gravity = (Gravity) grav;
|
||||
otherRidgidBody.xAcc += gravity.x * -1.;
|
||||
otherRidgidBody.yAcc += gravity.y * -1.;
|
||||
}
|
||||
|
||||
} else if (otherRidgidBody.mass < 0) {
|
||||
// entity 2 is immovable; full acceleration applied to the current entity
|
||||
ridgidBody.xVel += totalXVel * xMult;
|
||||
ridgidBody.yVel += totalYVel * yMult;
|
||||
Object grav = gameEngine.getComponentData(entity, Gravity.class);
|
||||
if (grav != null) {
|
||||
// negate gravity while collided
|
||||
Gravity gravity = (Gravity) grav;
|
||||
ridgidBody.xAcc += gravity.x * -1.;
|
||||
ridgidBody.yAcc += gravity.y * -1.;
|
||||
}
|
||||
} else {
|
||||
// collision is elastic; add the forces x & y and the masses, and share between
|
||||
// objects
|
||||
/*ridgidBody.xVel += (ridgidBody.mass / totalMass) * totalXVel * xMult;
|
||||
otherRidgidBody.xVel += (otherRidgidBody.mass / totalMass) * totalXVel
|
||||
* (-1 * xMult);
|
||||
|
||||
ridgidBody.yVel += (ridgidBody.mass / totalMass) * totalYVel * yMult;
|
||||
otherRidgidBody.yVel += (otherRidgidBody.mass / totalMass) * totalYVel
|
||||
* (-1 * yMult);*/
|
||||
}
|
||||
}
|
||||
else{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Zero degrees is straight up,
|
||||
* 90 east
|
||||
* -90 (270) = west
|
||||
* 180 south
|
||||
* @param xVel
|
||||
* @param yVel
|
||||
* @return
|
||||
*/
|
||||
public static double calcAngle(double xVel, double yVel){
|
||||
if (xVel == 0){ // Div zero; = +- 90
|
||||
return yVel < 0 ? 270 : 90;
|
||||
}
|
||||
else if (xVel < 0 && yVel < 0){ // bottom-left quad (180 - 270)
|
||||
return 180. + Math.tanh(yVel/xVel);
|
||||
}
|
||||
else if (xVel < 0){ // Top left quad (270 - 360)
|
||||
return 360 - Math.tanh(yVel/xVel);
|
||||
}
|
||||
else if (yVel < 0){
|
||||
return 180 - Math.tanh(yVel/xVel);
|
||||
}
|
||||
else{
|
||||
return Math.tanh(yVel/xVel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package nz.ac.massey.javaecs.examples.Systems;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
import nz.ac.massey.javaecs.ECSSystem;
|
||||
import nz.ac.massey.javaecs.Engine;
|
||||
import nz.ac.massey.javaecs.Entity;
|
||||
import nz.ac.massey.javaecs.examples.Components.LogUpdate;
|
||||
import nz.ac.massey.javaecs.examples.Components.Vec2D;
|
||||
|
||||
public class LogUpdateSystem extends ECSSystem{
|
||||
Engine gameEngine;
|
||||
|
||||
public LogUpdateSystem(Engine gameEngine){
|
||||
this.gameEngine = gameEngine;
|
||||
// Set registrations
|
||||
registrationSet = new BitSet();
|
||||
registrationSet.set(gameEngine.getComponentIndex(LogUpdate.class));
|
||||
}
|
||||
@Override
|
||||
public void init() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
for (Entity entity : entities) {
|
||||
Vec2D pos = (Vec2D)gameEngine.getComponentData(entity, Vec2D.class);
|
||||
System.out.println(String.format("X: %.6g, Y: %.6g", pos.x, pos.y));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package nz.ac.massey.javaecs.examples.Systems;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
import nz.ac.massey.javaecs.ECSSystem;
|
||||
import nz.ac.massey.javaecs.Engine;
|
||||
import nz.ac.massey.javaecs.Entity;
|
||||
import nz.ac.massey.javaecs.examples.Components.Vec2D;
|
||||
import nz.ac.massey.javaecs.examples.Components.RidgidBody;
|
||||
import nz.ac.massey.javaecs.examples.Components.Collider;
|
||||
import nz.ac.massey.javaecs.examples.Components.Gravity;
|
||||
|
||||
public class PhysicsSystem extends ECSSystem {
|
||||
Engine gameEngine;
|
||||
|
||||
public PhysicsSystem(Engine gameEngine){
|
||||
this.gameEngine = gameEngine;
|
||||
// Set registrations
|
||||
registrationSet = new BitSet();
|
||||
registrationSet.set(gameEngine.getComponentIndex(Vec2D.class));
|
||||
registrationSet.set(gameEngine.getComponentIndex(RidgidBody.class));
|
||||
registrationSet.set(gameEngine.getComponentIndex(Gravity.class));
|
||||
registrationSet.set(gameEngine.getComponentIndex(Collider.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public void update(double dt){
|
||||
for (Entity entity : entities) {
|
||||
Vec2D pos = (Vec2D)gameEngine.getComponentData(entity, Vec2D.class);
|
||||
RidgidBody ridgidBody = (RidgidBody)gameEngine.getComponentData(entity, RidgidBody.class);
|
||||
Gravity gravity = (Gravity)gameEngine.getComponentData(entity, Gravity.class);
|
||||
Collider collider = (Collider)gameEngine.getComponentData(entity, Collider.class);
|
||||
// Firstly, add the result of the accelerative forces to the ridgidbody
|
||||
ridgidBody.xVel += ridgidBody.xAcc * dt;
|
||||
ridgidBody.yVel += ridgidBody.yAcc * dt;
|
||||
// Set acceleration to zero (it has been processed/integrated and is now applied to the velocity);
|
||||
// use a constant-force component to apply acceleration each frame
|
||||
ridgidBody.xAcc = 0.;
|
||||
ridgidBody.yAcc = 0.;
|
||||
|
||||
if (!collider.collided){
|
||||
// Special case of gravity
|
||||
if (gravity.terminalX < 0 || Math.abs(ridgidBody.xVel) < gravity.terminalX){
|
||||
ridgidBody.xAcc += gravity.x;
|
||||
}
|
||||
if (gravity.terminalY < 0 || Math.abs(ridgidBody.yVel) < gravity.terminalY){
|
||||
ridgidBody.yAcc += gravity.y;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Finally, move the vec2d by the new velocity
|
||||
pos.x += ridgidBody.xVel * dt;
|
||||
pos.y += ridgidBody.yVel * dt;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
package nz.ac.massey.javaecs.examples.Systems;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.paint.Paint;
|
||||
import javafx.scene.shape.Rectangle;
|
||||
import javafx.stage.Stage;
|
||||
import nz.ac.massey.javaecs.ECSSystem;
|
||||
import nz.ac.massey.javaecs.Engine;
|
||||
import nz.ac.massey.javaecs.Entity;
|
||||
import nz.ac.massey.javaecs.examples.Components.BoxRender;
|
||||
import nz.ac.massey.javaecs.examples.Components.Render;
|
||||
import nz.ac.massey.javaecs.examples.Components.Vec2D;
|
||||
|
||||
public class RenderSystem extends ECSSystem{
|
||||
JFXView jFXView;
|
||||
Engine gameEngine;
|
||||
Thread renderThread;
|
||||
double renderScale;
|
||||
int screenX = 1024;
|
||||
int screenY = 1024;
|
||||
|
||||
public RenderSystem(Engine gameEngine, double renderScale){
|
||||
this.gameEngine = gameEngine;
|
||||
// Set registrations
|
||||
registrationSet = new BitSet();
|
||||
registrationSet.set(gameEngine.getComponentIndex(Render.class));
|
||||
this.renderScale = renderScale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
// Spawn a new thread
|
||||
renderThread = new Thread(new RenderStarter());
|
||||
renderThread.start(); // this thread is asynchronous, it isn't expected to rejoin
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
/* while (JFXView.root == null){
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} */
|
||||
Group renderScene = new Group();
|
||||
for (Entity entity : entities) {
|
||||
//Vec2D pos = (Vec2D)gameEngine.getComponentData(entity, Vec2D.class);
|
||||
if (((Render)gameEngine.getComponentData(entity, Render.class)).renderType == BoxRender.class){
|
||||
BoxRender box = (BoxRender)gameEngine.getComponentData(entity, BoxRender.class);
|
||||
Vec2D vec2d = (Vec2D)gameEngine.getComponentData(entity, Vec2D.class);
|
||||
|
||||
Rectangle rect = new Rectangle(box.xSize* renderScale, box.ySize * renderScale);
|
||||
rect.setFill(new Color(box.r, box.g, box.b, 0.9));
|
||||
rect.setX(12 + (vec2d.x * renderScale));
|
||||
rect.setY(1012 - (vec2d.y * renderScale) - rect.getHeight());
|
||||
renderScene.getChildren().add(rect);
|
||||
}
|
||||
}
|
||||
Platform.runLater(new Runnable(){
|
||||
@Override
|
||||
public void run() {
|
||||
JFXView.root.getChildren().clear();
|
||||
JFXView.root.getChildren().add(renderScene);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Add a renderer
|
||||
|
||||
public class RenderStarter implements Runnable{
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
JFXView.run();
|
||||
}
|
||||
void updateScene(Group newGroup){
|
||||
JFXView.root.getChildren().clear();
|
||||
JFXView.root.getChildren().add(newGroup);
|
||||
}
|
||||
}
|
||||
|
||||
public static class JFXView extends Application {
|
||||
private static Group root;
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws Exception {
|
||||
// based on the colorful circles sample at https://docs.oracle.com/javase/8/javafx/get-started-tutorial/animation.htm
|
||||
root = new Group();
|
||||
Scene scene = new Scene(root, 1024, 1024, Color.BLACK);
|
||||
primaryStage.setScene(scene);
|
||||
|
||||
primaryStage.show();
|
||||
}
|
||||
|
||||
public static void run(){
|
||||
launch(new String[0]);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package nz.ac.massey.javaecs.examples;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* Unit test for simple App.
|
||||
*/
|
||||
class AppTest {
|
||||
/**
|
||||
* Rigorous Test.
|
||||
*/
|
||||
@Test
|
||||
void testApp() {
|
||||
assertEquals(1, 1);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user