Compare commits

..

No commits in common. "294c0fc52f804eb3eac945f53a659fdcc6225e9a" and "4d764285537d29c9fe99c6b26186267dec4103f4" have entirely different histories.

8 changed files with 246 additions and 149 deletions

View File

@ -1,8 +1,10 @@
package nz.ac.massey.javaecs.examples; package nz.ac.massey.javaecs.examples;
import java.sql.Time;
import java.util.Random; import java.util.Random;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import nz.ac.massey.javaecs.*; import nz.ac.massey.javaecs.*;
import nz.ac.massey.javaecs.examples.Components.*; import nz.ac.massey.javaecs.examples.Components.*;
import nz.ac.massey.javaecs.examples.Systems.*; import nz.ac.massey.javaecs.examples.Systems.*;
@ -20,14 +22,8 @@ public final class App {
* @throws InterruptedException * @throws InterruptedException
*/ */
public static void main(String[] args) throws InterruptedException { public static void main(String[] args) throws InterruptedException {
/************************************
** Initialise engine **
*************************************/
Engine gameEngine = new Engine(16384); Engine gameEngine = new Engine(16384);
/************************************
** Register game components **
*************************************/
gameEngine.registerComponent(Gravity.class); gameEngine.registerComponent(Gravity.class);
gameEngine.registerComponent(RidgidBody.class); gameEngine.registerComponent(RidgidBody.class);
gameEngine.registerComponent(Vec2D.class); gameEngine.registerComponent(Vec2D.class);
@ -39,9 +35,6 @@ public final class App {
gameEngine.registerComponent(Reporter.class); gameEngine.registerComponent(Reporter.class);
gameEngine.registerComponent(TextRender.class); gameEngine.registerComponent(TextRender.class);
/************************************
** Register and initialise systems **
*************************************/
PhysicsSystem physicsSystem = new PhysicsSystem(gameEngine); PhysicsSystem physicsSystem = new PhysicsSystem(gameEngine);
gameEngine.registerSystem(PhysicsSystem.class, physicsSystem); gameEngine.registerSystem(PhysicsSystem.class, physicsSystem);
@ -61,11 +54,6 @@ public final class App {
ReportSystem reportSystem = new ReportSystem(gameEngine); ReportSystem reportSystem = new ReportSystem(gameEngine);
gameEngine.registerSystem(ReportSystem.class, reportSystem); gameEngine.registerSystem(ReportSystem.class, reportSystem);
/************************************
** Create known entities **
*************************************/
// Define a play area 100 * 100, make sure to use worldspace not screenspace (top left is 0, 100, not 0,0) // Define a play area 100 * 100, make sure to use worldspace not screenspace (top left is 0, 100, not 0,0)
// Bottom boundary // Bottom boundary
Entity newEnt = gameEngine.createEntity(); Entity newEnt = gameEngine.createEntity();
@ -98,35 +86,35 @@ public final class App {
// One object // One object
newEnt = gameEngine.createEntity(); newEnt = gameEngine.createEntity();
gameEngine.addComponent(newEnt, Vec2D.class, new Vec2D(62., 90.,0)); gameEngine.addComponent(newEnt, Vec2D.class, new Vec2D(62., 90.,0));
gameEngine.addComponent(newEnt, RidgidBody.class, new RidgidBody(1., 0., 0., 0., 0.f, 0.66, 120.)); 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, 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, 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, Render.class, new Render(BoxRender.class));
gameEngine.addComponent(newEnt, BoxRender.class, new BoxRender(10, 10, 255, 64, 64)); gameEngine.addComponent(newEnt, BoxRender.class, new BoxRender(10, 10, 255, 64, 64));
// The textobject that prints the current number of entities
newEnt = gameEngine.createEntity(); newEnt = gameEngine.createEntity();
gameEngine.addComponent(newEnt, TextRender.class, new TextRender("", 24, Color.WHITE)); gameEngine.addComponent(newEnt, TextRender.class, new TextRender("", 24, Color.WHITE));
gameEngine.addComponent(newEnt, Render.class, new Render(TextRender.class)); gameEngine.addComponent(newEnt, Render.class, new Render(TextRender.class));
gameEngine.addComponent(newEnt, Reporter.class, new Reporter()); gameEngine.addComponent(newEnt, Reporter.class, new Reporter());
gameEngine.addComponent(newEnt, Vec2D.class, new Vec2D(5,5,0)); gameEngine.addComponent(newEnt, Vec2D.class, new Vec2D(5,5,0));
// Other objects
/* // Uncomment this block to enable the stress-test (runs 500 square entities, with physics etc.)
Random rand = new Random(); Random rand = new Random();
for (int i = 0; i < 500; i++) { for (int i = 0; i < 20; i++) {
newEnt = gameEngine.createEntity(); newEnt = gameEngine.createEntity();
double size = 1 + rand.nextDouble();
gameEngine.addComponent(newEnt, Vec2D.class, new Vec2D(10 + rand.nextDouble()* 80, 10+ rand.nextDouble()* 80,0)); 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.3, 2. * size)); 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, 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, 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, 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, BoxRender.class, new BoxRender(size, size, 30 + rand.nextInt(225), 30 + rand.nextInt(225), 30 + rand.nextInt(225)));
gameEngine.addComponent(newEnt, TimedExistence.class, new TimedExistence(25 + rand.nextDouble() * 90)); gameEngine.addComponent(newEnt, TimedExistence.class, new TimedExistence(5 + rand.nextDouble() * 90));
} */ }
//gameEngine.addComponent(newEnt, LogUpdate.class, null);
/************************************
** Run init() on the systems **
*************************************/
physicsSystem.init(); physicsSystem.init();
collisionSystem.init(); collisionSystem.init();
logUpdateSystem.init(); logUpdateSystem.init();
@ -134,33 +122,32 @@ public final class App {
existenceSystem.init(); existenceSystem.init();
reportSystem.init(); reportSystem.init();
/************************************
** Prepare and enter the game loop **
*************************************/
double dt = 0.001; double dt = 0.001;
double frameRate = 1.0 / 144; // 1 second divided by target number of frames 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; boolean exit = false;
long loopStart = System.currentTimeMillis();
long startTime = System.nanoTime(); long startTime = System.nanoTime();
while (!exit){ while (!exit){
// Run system updates
collisionSystem.update(); collisionSystem.update();
physicsSystem.update(dt); physicsSystem.update(dt);
existenceSystem.update(dt); existenceSystem.update(dt);
reportSystem.update(); reportSystem.update();
//logUpdateSystem.update();
// The render system should be uncoupled from the physics and collision
renderSystem.update(); renderSystem.update();
dt = (System.nanoTime() - startTime) / 1e9; // convert nanoseconds to seconds dt = (System.nanoTime() - startTime) / 1e9; // convert nanoseconds to seconds
startTime = System.nanoTime(); startTime = System.nanoTime();
if (dt < frameRate){ if (dt < frameRate){
idleTime = frameRate-dt;
Thread.sleep((int)((frameRate-dt)*1000)); Thread.sleep((int)((frameRate-dt)*1000));
dt = (System.nanoTime() - startTime) / 1e9; dt = (System.nanoTime() - startTime) / 1e9;
startTime = System.nanoTime(); startTime = System.nanoTime();
} }
// Setting dt here to a fixed time-step will lock the rate of the physics. The above code ensures that it is dt = 0.001;
// executed no more than once 1/framerate seconds.
// dt = 0.001;
} }
} }
} }

View File

@ -9,4 +9,7 @@ public class Collider {
// bottom-right, top-right is specified by position // bottom-right, top-right is specified by position
public double x = 0.0; public double x = 0.0;
public double y = 0.0; public double y = 0.0;
public boolean collided = false;
public double travelDirection = 0.0;
} }

View File

@ -2,4 +2,4 @@ package nz.ac.massey.javaecs.examples.Components;
public class Reporter { public class Reporter {
} }

View File

@ -1,8 +1,11 @@
package nz.ac.massey.javaecs.examples.Systems; package nz.ac.massey.javaecs.examples.Systems;
import java.util.ArrayList;
import java.util.BitSet; import java.util.BitSet;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream;
import nz.ac.massey.javaecs.ECSSystem; import nz.ac.massey.javaecs.ECSSystem;
import nz.ac.massey.javaecs.Engine; import nz.ac.massey.javaecs.Engine;
@ -26,98 +29,170 @@ public class CollisionSystem extends ECSSystem {
@Override @Override
public void init() { 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
}
}
}
}
}
} }
// This is a quick & naive physics implementation. Not all collision states are accurately calculated
// I also expect it is highly inefficient, though I was able to run it with 500 subscribed entities
// with no major performance issues
// Replace this with a proper system as required
@Override @Override
public void update() { public void update() {
// Parallelising this loop ()
Set<Entity> processed = new HashSet<>(); Set<Entity> processed = new HashSet<>();
// Gets all items we have collided with // Gets all items we have collided with
for (Entity entity : entities) { for (Entity entity : entities) {
Vec2D pos = (Vec2D) gameEngine.getComponentData(entity, Vec2D.class); Vec2D pos = (Vec2D) gameEngine.getComponentData(entity, Vec2D.class);
RidgidBody ridgidBody = (RidgidBody) gameEngine.getComponentData(entity, RidgidBody.class); RidgidBody ridgidBody = (RidgidBody) gameEngine.getComponentData(entity, RidgidBody.class);
Collider collider = (Collider) gameEngine.getComponentData(entity, Collider.class); Collider collider = (Collider) gameEngine.getComponentData(entity, Collider.class);
if (ridgidBody.mass >= 0) { if (ridgidBody.mass > 0){
// Only ignore non-static colliders // Only ignore non-static colliders
//processed.add(entity); processed.add(entity);
for (Entity entity2 : entities) { }
if (!processed.contains(entity2)) { for (Entity entity2 : entities) {
// skip entities that have already been processed if (!processed.contains(entity2)) {
Vec2D otherPos = (Vec2D) gameEngine.getComponentData(entity2, Vec2D.class); // skip entities that have already been processed
RidgidBody otherRidgidBody = (RidgidBody) gameEngine.getComponentData(entity2, Vec2D otherPos = (Vec2D) gameEngine.getComponentData(entity2, Vec2D.class);
RidgidBody.class); RidgidBody otherRidgidBody = (RidgidBody) gameEngine.getComponentData(entity2, RidgidBody.class);
Collider otherCollider = (Collider) gameEngine.getComponentData(entity2, Collider.class); Collider otherCollider = (Collider) gameEngine.getComponentData(entity2, Collider.class);
if (ridgidBody.mass >= 0 || otherRidgidBody.mass >= 0) { if (ridgidBody.mass >= 0 || otherRidgidBody.mass >= 0) {
// Evaluate a collision in the top-left // Evaluate a collision in the top-left
boolean tlCollide = pos.x > otherPos.x && pos.x < otherPos.x + otherCollider.x boolean tlCollide = pos.x > otherPos.x && pos.x < otherPos.x + otherCollider.x
&& pos.y > otherPos.y && pos.y < otherPos.y + otherCollider.y; && pos.y > otherPos.y && pos.y < otherPos.y + otherCollider.y;
// Evaluate a collision in the bottom-left // Evaluate a collision in the bottom-left
boolean blCollide = pos.x > otherPos.x && pos.x < otherPos.x + otherCollider.x boolean blCollide = pos.x > otherPos.x && pos.x < otherPos.x + otherCollider.x
&& pos.y + collider.y > otherPos.y && pos.y + collider.y > otherPos.y && pos.y + collider.y < otherPos.y + otherCollider.y;
&& pos.y + collider.y < otherPos.y + otherCollider.y; // Evaluate a collision in the bottom-right
// Evaluate a collision in the bottom-right boolean brCollide = pos.x + collider.x > otherPos.x
boolean brCollide = pos.x + collider.x > otherPos.x && pos.x + collider.x < otherPos.x + otherCollider.x && pos.y + collider.y > otherPos.y
&& pos.x + collider.x < otherPos.x + otherCollider.x && pos.y + collider.y < otherPos.y + otherCollider.y;
&& pos.y + collider.y > otherPos.y // Evaluate a collision in the top-right
&& pos.y + collider.y < otherPos.y + otherCollider.y; boolean trCollide = pos.x + collider.x > otherPos.x
// Evaluate a collision in the top-right && pos.x + collider.x < otherPos.x + otherCollider.x && pos.y > otherPos.y
boolean trCollide = pos.x + collider.x > otherPos.x && pos.y < otherPos.y + otherCollider.y;
&& pos.x + collider.x < otherPos.x + otherCollider.x && pos.y > otherPos.y if (tlCollide || blCollide || brCollide || trCollide) {
&& pos.y < otherPos.y + otherCollider.y; // Determine collision nature
if (tlCollide || blCollide || brCollide || trCollide) { if (tlCollide) {
// Get the vels int k = 0;
double totalXVel = Math.abs(ridgidBody.xVel) + Math.abs(otherRidgidBody.xVel); }
double totalYVel = Math.abs(ridgidBody.yVel) + Math.abs(otherRidgidBody.yVel); if (trCollide) {
double xMult = 0; int k = 0;
double yMult = 0; }
double multTot = (1 + ridgidBody.bounciness); if (blCollide) {
double totalMass = ridgidBody.mass + otherRidgidBody.mass; int k = 0;
boolean fullEdge = false; }
// left-hand collision if (brCollide) {
if (tlCollide && blCollide) { int k = 0;
fullEdge = true; }
pos.x = otherPos.x + otherCollider.x; // Get the vels
xMult = multTot; double totalXVel = Math.abs(ridgidBody.xVel) + Math.abs(otherRidgidBody.xVel);
} double totalYVel = Math.abs(ridgidBody.yVel) + Math.abs(otherRidgidBody.yVel);
// right-hand collision double totalMass = ridgidBody.mass + otherRidgidBody.mass;
else if (brCollide && trCollide) { int xMult = 0;
fullEdge = true; int yMult = 0;
pos.x = otherPos.x - collider.x; boolean fullEdge = false;
xMult = -multTot; // left-hand collision
} if (tlCollide && blCollide) {
// Bottom collision fullEdge = true;
if (blCollide && brCollide) { xMult = 2;
fullEdge = true; }
//pos.y = otherPos.y + otherCollider.y; // Bottom collision
pos.y = otherPos.y - collider.y; if (blCollide && brCollide) {
yMult = -multTot; fullEdge = true;
} yMult = -2;
// top collision }
else if (trCollide && tlCollide) { // right-hand collision
fullEdge = true; if (brCollide && trCollide) {
//pos.y = otherPos.y - collider.y; fullEdge = true;
pos.y = otherPos.y + otherCollider.y; xMult = -2;
yMult = multTot; }
} // top collision
if (fullEdge) { if (trCollide && tlCollide) {
// Finally, actuate the calculation 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 // entity 2 is immovable; full acceleration applied to the current entity
ridgidBody.xVel += totalXVel * xMult;
if (otherRidgidBody.mass > 0){ ridgidBody.yVel += totalYVel * yMult;
ridgidBody.xVel += totalXVel * xMult * ((totalMass - ridgidBody.mass) / totalMass);
ridgidBody.yVel += totalYVel * yMult * ((totalMass - ridgidBody.mass) / totalMass);
otherRidgidBody.xVel -= totalXVel * xMult * ((totalMass - otherRidgidBody.mass) / totalMass);
otherRidgidBody.yVel -= totalYVel * yMult * ((totalMass - otherRidgidBody.mass) / totalMass);
}
else{
ridgidBody.xVel += totalXVel * xMult;
ridgidBody.yVel += totalYVel * yMult;
}
Object grav = gameEngine.getComponentData(entity, Gravity.class); Object grav = gameEngine.getComponentData(entity, Gravity.class);
if (grav != null) { if (grav != null) {
// negate gravity while collided // negate gravity while collided
@ -125,36 +200,53 @@ public class CollisionSystem extends ECSSystem {
ridgidBody.xAcc += gravity.x * -1.; ridgidBody.xAcc += gravity.x * -1.;
ridgidBody.yAcc += gravity.y * -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 * Zero degrees is straight up,
* * 90 east
* -90 (270) = west
* 180 south
* @param xVel * @param xVel
* @param yVel * @param yVel
* @return * @return
*/ */
public static double calcAngle(double xVel, double yVel) { public static double calcAngle(double xVel, double yVel){
if (xVel == 0) { // Div zero; = +- 90 if (xVel == 0){ // Div zero; = +- 90
return yVel < 0 ? 270 : 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);
} }
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);
}
} }
} }

View File

@ -11,6 +11,7 @@ import nz.ac.massey.javaecs.Entity;
import nz.ac.massey.javaecs.examples.Components.BoxRender; import nz.ac.massey.javaecs.examples.Components.BoxRender;
import nz.ac.massey.javaecs.examples.Components.Collider; import nz.ac.massey.javaecs.examples.Components.Collider;
import nz.ac.massey.javaecs.examples.Components.Gravity; import nz.ac.massey.javaecs.examples.Components.Gravity;
import nz.ac.massey.javaecs.examples.Components.LogUpdate;
import nz.ac.massey.javaecs.examples.Components.Render; import nz.ac.massey.javaecs.examples.Components.Render;
import nz.ac.massey.javaecs.examples.Components.RidgidBody; import nz.ac.massey.javaecs.examples.Components.RidgidBody;
import nz.ac.massey.javaecs.examples.Components.TimedExistence; import nz.ac.massey.javaecs.examples.Components.TimedExistence;
@ -31,10 +32,13 @@ public class ExistenceSystem extends ECSSystem{
@Override @Override
public void init() { public void init() {
rand = new Random(); rand = new Random();
} }
@Override @Override
public void update() { public void update() {
// TODO Auto-generated method stub
} }
public void update(double dt){ public void update(double dt){
@ -43,10 +47,10 @@ public class ExistenceSystem extends ECSSystem{
BoxRender shape = (BoxRender)gameEngine.getComponentData(entity, BoxRender.class); BoxRender shape = (BoxRender)gameEngine.getComponentData(entity, BoxRender.class);
TimedExistence timedExistence = (TimedExistence)gameEngine.getComponentData(entity, TimedExistence.class); TimedExistence timedExistence = (TimedExistence)gameEngine.getComponentData(entity, TimedExistence.class);
// Get the rate the fade should occur at our current frame rate. // Get the rate the fade should occur at our current frame rate.
double fadeRate = timedExistence.lifeTime / dt; double fadeRate = timedExistence.lifeTime / dt; // I.e. might say 200 frames left
// Fade the opacity // Fade the opacity
shape.a -= shape.a / fadeRate; shape.a -= shape.a / fadeRate;
// Keep the alpha between 0-1 // Clauses to keep things safe
if (shape.a < 0) shape.a = 0.; if (shape.a < 0) shape.a = 0.;
else if (shape.a > 1) shape.a = 1.; else if (shape.a > 1) shape.a = 1.;
// Reduce the time the shape may continue living for // Reduce the time the shape may continue living for
@ -56,18 +60,15 @@ public class ExistenceSystem extends ECSSystem{
deletions.add(entity); deletions.add(entity);
} }
} }
// As we were using the iterator to traverse entities, we could not delete them as we read them.
while (deletions.size() > 0){ while (deletions.size() > 0){
gameEngine.destroyEntity(deletions.remove()); gameEngine.destroyEntity(deletions.remove());
} }
// Finally, randomly add an entity as required // Finally, randomly add an entity as required
int newRate = gameEngine.getNumEntities(); if (rand.nextInt(16384) < 8){
newRate = newRate < 13 ? 7 - newRate / 2 : 1;
if (rand.nextInt(2048) <= 1*newRate){
Entity newEnt = gameEngine.createEntity(); Entity newEnt = gameEngine.createEntity();
double size = 1 + rand.nextDouble() * 10;
gameEngine.addComponent(newEnt, Vec2D.class, new Vec2D(10 + rand.nextDouble()* 80, 10+ rand.nextDouble()* 80,0)); 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.75, 2. * size)); 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, 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, 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, Render.class, new Render(BoxRender.class));

View File

@ -40,6 +40,7 @@ public class PhysicsSystem extends ECSSystem {
Vec2D pos = (Vec2D)gameEngine.getComponentData(entity, Vec2D.class); Vec2D pos = (Vec2D)gameEngine.getComponentData(entity, Vec2D.class);
RidgidBody ridgidBody = (RidgidBody)gameEngine.getComponentData(entity, RidgidBody.class); RidgidBody ridgidBody = (RidgidBody)gameEngine.getComponentData(entity, RidgidBody.class);
Gravity gravity = (Gravity)gameEngine.getComponentData(entity, Gravity.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 // Firstly, add the result of the accelerative forces to the ridgidbody
ridgidBody.xVel += ridgidBody.xAcc * dt; ridgidBody.xVel += ridgidBody.xAcc * dt;
ridgidBody.yVel += ridgidBody.yAcc * dt; ridgidBody.yVel += ridgidBody.yAcc * dt;
@ -48,12 +49,14 @@ public class PhysicsSystem extends ECSSystem {
ridgidBody.xAcc = 0.; ridgidBody.xAcc = 0.;
ridgidBody.yAcc = 0.; ridgidBody.yAcc = 0.;
// Special case of gravity if (!collider.collided){
if (gravity.terminalX < 0 || Math.abs(ridgidBody.xVel) < gravity.terminalX){ // Special case of gravity
ridgidBody.xAcc += gravity.x; 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; if (gravity.terminalY < 0 || Math.abs(ridgidBody.yVel) < gravity.terminalY){
ridgidBody.yAcc += gravity.y;
}
} }

View File

@ -4,9 +4,11 @@ import java.util.BitSet;
import javafx.application.Application; import javafx.application.Application;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.scene.Group; import javafx.scene.Group;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Rectangle; import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font; import javafx.scene.text.Font;
import javafx.scene.text.Text; import javafx.scene.text.Text;
@ -38,15 +40,23 @@ public class RenderSystem extends ECSSystem{
@Override @Override
public void init() { public void init() {
// Spawn a new asynchronous thread (won't rejoin the main program flow) // Spawn a new thread
renderThread = new Thread(new RenderStarter()); renderThread = new Thread(new RenderStarter());
renderThread.start(); renderThread.start(); // this thread is asynchronous, it isn't expected to rejoin
} }
@Override @Override
public void update() { public void update() {
/* while (JFXView.root == null){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} */
Group renderScene = new Group(); Group renderScene = new Group();
for (Entity entity : entities) { for (Entity entity : entities) {
//Vec2D pos = (Vec2D)gameEngine.getComponentData(entity, Vec2D.class);
if (((Render)gameEngine.getComponentData(entity, Render.class)).renderType == BoxRender.class){ if (((Render)gameEngine.getComponentData(entity, Render.class)).renderType == BoxRender.class){
BoxRender box = (BoxRender)gameEngine.getComponentData(entity, BoxRender.class); BoxRender box = (BoxRender)gameEngine.getComponentData(entity, BoxRender.class);
Vec2D vec2d = (Vec2D)gameEngine.getComponentData(entity, Vec2D.class); Vec2D vec2d = (Vec2D)gameEngine.getComponentData(entity, Vec2D.class);
@ -67,9 +77,6 @@ public class RenderSystem extends ECSSystem{
renderScene.getChildren().add(t); renderScene.getChildren().add(t);
} }
} }
// Must be run by the UI thread, not the main thread.
// This dispatches the operation run() to the UI.
Platform.runLater(new Runnable(){ Platform.runLater(new Runnable(){
@Override @Override
public void run() { public void run() {
@ -80,6 +87,7 @@ public class RenderSystem extends ECSSystem{
} }
// Add a renderer // Add a renderer
public class RenderStarter implements Runnable{ public class RenderStarter implements Runnable{
@Override @Override
@ -101,6 +109,7 @@ public class RenderSystem extends ECSSystem{
root = new Group(); root = new Group();
Scene scene = new Scene(root, 1024, 1024, Color.BLACK); Scene scene = new Scene(root, 1024, 1024, Color.BLACK);
primaryStage.setScene(scene); primaryStage.setScene(scene);
primaryStage.show(); primaryStage.show();
} }

View File

@ -20,6 +20,8 @@ public class ReportSystem extends ECSSystem{
} }
@Override @Override
public void init() { public void init() {
// TODO Auto-generated method stub
} }
@Override @Override