mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2025-10-30 08:11:25 +00:00
performance improvement
This commit is contained in:
parent
b6eafc57b7
commit
9aafd8b541
14 changed files with 164 additions and 88 deletions
|
|
@ -26,6 +26,8 @@ class MeshBatchInfo {
|
||||||
var meshbatch:MeshBatch;
|
var meshbatch:MeshBatch;
|
||||||
var transparencymeshbatch:MeshBatch;
|
var transparencymeshbatch:MeshBatch;
|
||||||
var mesh:Mesh;
|
var mesh:Mesh;
|
||||||
|
var dtsShader:DtsTexture;
|
||||||
|
var glowPassDtsShader:DtsTexture;
|
||||||
|
|
||||||
public function new() {}
|
public function new() {}
|
||||||
}
|
}
|
||||||
|
|
@ -81,7 +83,7 @@ class InstanceManager {
|
||||||
var opaqueinstances = visibleinstances.filter(x -> x.gameObject.currentOpacity == 1);
|
var opaqueinstances = visibleinstances.filter(x -> x.gameObject.currentOpacity == 1);
|
||||||
minfo.meshbatch.begin(opaqueinstances.length);
|
minfo.meshbatch.begin(opaqueinstances.length);
|
||||||
for (instance in opaqueinstances) { // Draw the opaque shit first
|
for (instance in opaqueinstances) { // Draw the opaque shit first
|
||||||
var dtsShader = minfo.meshbatch.material.mainPass.getShader(DtsTexture);
|
var dtsShader = minfo.dtsShader; // minfo.meshbatch.material.mainPass.getShader(DtsTexture);
|
||||||
var subOpacity = 1.0;
|
var subOpacity = 1.0;
|
||||||
if (dtsShader != null) {
|
if (dtsShader != null) {
|
||||||
if (instance.gameObject.animateSubObjectOpacities) {
|
if (instance.gameObject.animateSubObjectOpacities) {
|
||||||
|
|
@ -112,7 +114,7 @@ class InstanceManager {
|
||||||
// handle the glow pass too
|
// handle the glow pass too
|
||||||
var glowPass = minfo.meshbatch.material.getPass("glow");
|
var glowPass = minfo.meshbatch.material.getPass("glow");
|
||||||
if (glowPass != null) {
|
if (glowPass != null) {
|
||||||
dtsShader = glowPass.getShader(DtsTexture);
|
dtsShader = minfo.glowPassDtsShader;
|
||||||
if (dtsShader != null)
|
if (dtsShader != null)
|
||||||
dtsShader.currentOpacity = instance.gameObject.currentOpacity * subOpacity;
|
dtsShader.currentOpacity = instance.gameObject.currentOpacity * subOpacity;
|
||||||
}
|
}
|
||||||
|
|
@ -124,7 +126,7 @@ class InstanceManager {
|
||||||
var transparentinstances = visibleinstances.filter(x -> x.gameObject.currentOpacity != 1 && x.gameObject.currentOpacity != 0); // Filter out all zero opacity things too
|
var transparentinstances = visibleinstances.filter(x -> x.gameObject.currentOpacity != 1 && x.gameObject.currentOpacity != 0); // Filter out all zero opacity things too
|
||||||
minfo.transparencymeshbatch.begin(transparentinstances.length);
|
minfo.transparencymeshbatch.begin(transparentinstances.length);
|
||||||
for (instance in transparentinstances) { // Non opaque shit
|
for (instance in transparentinstances) { // Non opaque shit
|
||||||
var dtsShader = minfo.transparencymeshbatch.material.mainPass.getShader(DtsTexture);
|
var dtsShader = minfo.dtsShader;
|
||||||
if (dtsShader != null) {
|
if (dtsShader != null) {
|
||||||
dtsShader.currentOpacity = instance.gameObject.currentOpacity;
|
dtsShader.currentOpacity = instance.gameObject.currentOpacity;
|
||||||
}
|
}
|
||||||
|
|
@ -218,6 +220,8 @@ class InstanceManager {
|
||||||
for (shader in addshaders)
|
for (shader in addshaders)
|
||||||
gpass.addShader(shader);
|
gpass.addShader(shader);
|
||||||
|
|
||||||
|
minfo.glowPassDtsShader = gpass.getShader(DtsTexture);
|
||||||
|
|
||||||
minfo.meshbatch.material.addPass(gpass);
|
minfo.meshbatch.material.addPass(gpass);
|
||||||
}
|
}
|
||||||
var refractPass = mat.getPass("refract");
|
var refractPass = mat.getPass("refract");
|
||||||
|
|
@ -279,6 +283,7 @@ class InstanceManager {
|
||||||
|
|
||||||
minfo.meshbatch.material.addPass(gpass);
|
minfo.meshbatch.material.addPass(gpass);
|
||||||
}
|
}
|
||||||
|
minfo.dtsShader = minfo.meshbatch.material.mainPass.getShader(DtsTexture);
|
||||||
// var dtsshader = mat.mainPass.getShader(DtsTexture);
|
// var dtsshader = mat.mainPass.getShader(DtsTexture);
|
||||||
// if (dtsshader != null) {
|
// if (dtsshader != null) {
|
||||||
// minfo.meshbatch.material.mainPass.removeShader(minfo.meshbatch.material.textureShader);
|
// minfo.meshbatch.material.mainPass.removeShader(minfo.meshbatch.material.textureShader);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package src;
|
package src;
|
||||||
|
|
||||||
|
import collision.CollisionPool;
|
||||||
import net.NetPacket.MarbleNetFlags;
|
import net.NetPacket.MarbleNetFlags;
|
||||||
import net.BitStream.OutputBitStream;
|
import net.BitStream.OutputBitStream;
|
||||||
import net.ClientConnection;
|
import net.ClientConnection;
|
||||||
|
|
@ -532,9 +533,10 @@ class Marble extends GameObject {
|
||||||
matWorker.run();
|
matWorker.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
function findContacts(collisiomWorld:CollisionWorld, timeState:TimeState) {
|
function findContacts(collisionWorld:CollisionWorld, timeState:TimeState) {
|
||||||
this.contacts = queuedContacts;
|
this.contacts = queuedContacts;
|
||||||
var c = collisiomWorld.sphereIntersection(this.collider, timeState);
|
CollisionPool.clear();
|
||||||
|
var c = collisionWorld.sphereIntersection(this.collider, timeState);
|
||||||
this.contactEntities = c.foundEntities;
|
this.contactEntities = c.foundEntities;
|
||||||
contacts = contacts.concat(c.contacts);
|
contacts = contacts.concat(c.contacts);
|
||||||
}
|
}
|
||||||
|
|
@ -1763,7 +1765,7 @@ class Marble extends GameObject {
|
||||||
if (this.controllable && this.mode != Finish && !MarbleGame.instance.paused && !this.level.isWatching && !this.level.isReplayingMovement) {
|
if (this.controllable && this.mode != Finish && !MarbleGame.instance.paused && !this.level.isWatching && !this.level.isReplayingMovement) {
|
||||||
if (Net.isClient) {
|
if (Net.isClient) {
|
||||||
var axis = getMarbleAxis()[1];
|
var axis = getMarbleAxis()[1];
|
||||||
move = Net.clientConnection.moveManager.recordMove(cast this, axis, timeState);
|
move = Net.clientConnection.recordMove(cast this, axis, timeState);
|
||||||
} else if (Net.isHost) {
|
} else if (Net.isHost) {
|
||||||
var axis = getMarbleAxis()[1];
|
var axis = getMarbleAxis()[1];
|
||||||
var innerMove = recordMove();
|
var innerMove = recordMove();
|
||||||
|
|
@ -1772,7 +1774,7 @@ class Marble extends GameObject {
|
||||||
}
|
}
|
||||||
var moveId = 65535;
|
var moveId = 65535;
|
||||||
if (!this.controllable && this.connection != null && Net.isHost) {
|
if (!this.controllable && this.connection != null && Net.isHost) {
|
||||||
var nextMove = this.connection.moveManager.getNextMove();
|
var nextMove = this.connection.getNextMove();
|
||||||
// trace('Moves left: ${@:privateAccess this.connection.moveManager.queuedMoves.length}');
|
// trace('Moves left: ${@:privateAccess this.connection.moveManager.queuedMoves.length}');
|
||||||
if (nextMove == null) {
|
if (nextMove == null) {
|
||||||
var axis = getMarbleAxis()[1];
|
var axis = getMarbleAxis()[1];
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package src;
|
package src;
|
||||||
|
|
||||||
|
import collision.CollisionPool;
|
||||||
import net.GemPredictionStore;
|
import net.GemPredictionStore;
|
||||||
import modes.HuntMode;
|
import modes.HuntMode;
|
||||||
import net.NetPacket.MarbleNetFlags;
|
import net.NetPacket.MarbleNetFlags;
|
||||||
|
|
@ -236,7 +237,7 @@ class MarbleWorld extends Scheduler {
|
||||||
|
|
||||||
var oobSchedule:Float;
|
var oobSchedule:Float;
|
||||||
|
|
||||||
var _cubemapNeedsUpdate:Bool = false;
|
var _instancesNeedsUpdate:Bool = false;
|
||||||
|
|
||||||
var lock:Bool = false;
|
var lock:Bool = false;
|
||||||
|
|
||||||
|
|
@ -1076,7 +1077,7 @@ class MarbleWorld extends Scheduler {
|
||||||
if (!lastMoves.ourMoveApplied) {
|
if (!lastMoves.ourMoveApplied) {
|
||||||
var ourMove = lastMoves.myMarbleUpdate;
|
var ourMove = lastMoves.myMarbleUpdate;
|
||||||
if (ourMove != null) {
|
if (ourMove != null) {
|
||||||
var ourMoveStruct = Net.clientConnection.moveManager.acknowledgeMove(ourMove.move.id, timeState);
|
var ourMoveStruct = Net.clientConnection.acknowledgeMove(ourMove.move.id, timeState);
|
||||||
lastMoves.ourMoveApplied = true;
|
lastMoves.ourMoveApplied = true;
|
||||||
for (client => arr in lastMoves.otherMarbleUpdates) {
|
for (client => arr in lastMoves.otherMarbleUpdates) {
|
||||||
var lastMove = null;
|
var lastMove = null;
|
||||||
|
|
@ -1157,11 +1158,11 @@ class MarbleWorld extends Scheduler {
|
||||||
var ourLastMove = lastMoves.myMarbleUpdate;
|
var ourLastMove = lastMoves.myMarbleUpdate;
|
||||||
if (ourLastMove == null || marbleNeedsPrediction == 0)
|
if (ourLastMove == null || marbleNeedsPrediction == 0)
|
||||||
return -1;
|
return -1;
|
||||||
var ackLag = @:privateAccess Net.clientConnection.moveManager.queuedMoves.length;
|
var ackLag = @:privateAccess Net.clientConnection.getQueuedMovesLength();
|
||||||
|
|
||||||
var ourLastMoveTime = ourLastMove.serverTicks;
|
var ourLastMoveTime = ourLastMove.serverTicks;
|
||||||
|
|
||||||
var ourQueuedMoves = @:privateAccess Net.clientConnection.moveManager.queuedMoves.copy();
|
var ourQueuedMoves = @:privateAccess Net.clientConnection.getQueuedMoves().copy();
|
||||||
|
|
||||||
var qm = ourQueuedMoves[0];
|
var qm = ourQueuedMoves[0];
|
||||||
var advanceTimeState = qm != null ? qm.timeState.clone() : timeState.clone();
|
var advanceTimeState = qm != null ? qm.timeState.clone() : timeState.clone();
|
||||||
|
|
@ -1506,14 +1507,12 @@ class MarbleWorld extends Scheduler {
|
||||||
marble.update(timeState, collisionWorld, this.pathedInteriors);
|
marble.update(timeState, collisionWorld, this.pathedInteriors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_cubemapNeedsUpdate = true;
|
_instancesNeedsUpdate = true;
|
||||||
Renderer.dirtyBuffers = true;
|
Renderer.dirtyBuffers = true;
|
||||||
if (this.rewinding) {
|
if (this.rewinding) {
|
||||||
// Update camera separately
|
// Update camera separately
|
||||||
marble.camera.update(timeState.currentAttemptTime, realDt);
|
marble.camera.update(timeState.currentAttemptTime, realDt);
|
||||||
}
|
}
|
||||||
ProfilerUI.measure("updateInstances");
|
|
||||||
this.instanceManager.render();
|
|
||||||
ProfilerUI.measure("updateParticles");
|
ProfilerUI.measure("updateParticles");
|
||||||
if (this.rewinding) {
|
if (this.rewinding) {
|
||||||
this.particleManager.update(1000 * timeState.timeSinceLoad, -realDt * rewindManager.timeScale);
|
this.particleManager.update(1000 * timeState.timeSinceLoad, -realDt * rewindManager.timeScale);
|
||||||
|
|
@ -1555,13 +1554,16 @@ class MarbleWorld extends Scheduler {
|
||||||
asyncLoadResources();
|
asyncLoadResources();
|
||||||
if (this.playGui != null && _ready)
|
if (this.playGui != null && _ready)
|
||||||
this.playGui.render(e);
|
this.playGui.render(e);
|
||||||
if (this.marble != null && this.marble.cubemapRenderer != null && _ready) {
|
if (_instancesNeedsUpdate) {
|
||||||
ProfilerUI.measure("renderCubemap");
|
ProfilerUI.measure("updateInstances");
|
||||||
if (_cubemapNeedsUpdate) {
|
this.instanceManager.render();
|
||||||
|
if (this.marble != null && this.marble.cubemapRenderer != null && _ready) {
|
||||||
|
ProfilerUI.measure("renderCubemap");
|
||||||
|
|
||||||
this.marble.cubemapRenderer.position.load(this.marble.getAbsPos().getPosition());
|
this.marble.cubemapRenderer.position.load(this.marble.getAbsPos().getPosition());
|
||||||
this.marble.cubemapRenderer.render(e);
|
this.marble.cubemapRenderer.render(e);
|
||||||
_cubemapNeedsUpdate = false;
|
|
||||||
}
|
}
|
||||||
|
_instancesNeedsUpdate = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2298,6 +2300,8 @@ class MarbleWorld extends Scheduler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CollisionPool.freeMemory();
|
||||||
|
|
||||||
radar.dispose();
|
radar.dispose();
|
||||||
|
|
||||||
if (this.playGui != null)
|
if (this.playGui != null)
|
||||||
|
|
|
||||||
|
|
@ -64,10 +64,12 @@ class CollisionEntity implements IOctreeObject implements IBVHObject {
|
||||||
// Generates the bvh
|
// Generates the bvh
|
||||||
public function finalize() {
|
public function finalize() {
|
||||||
this.generateBoundingBox();
|
this.generateBoundingBox();
|
||||||
|
#if hl
|
||||||
this.bvh = new BVHTree();
|
this.bvh = new BVHTree();
|
||||||
for (surface in this.surfaces) {
|
for (surface in this.surfaces) {
|
||||||
this.bvh.add(surface);
|
this.bvh.add(surface);
|
||||||
}
|
}
|
||||||
|
#end
|
||||||
// this.bvh.build();
|
// this.bvh.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -240,9 +242,10 @@ class CollisionEntity implements IOctreeObject implements IBVHObject {
|
||||||
// if (testDot > bestDot) {
|
// if (testDot > bestDot) {
|
||||||
// bestDot = testDot;
|
// bestDot = testDot;
|
||||||
|
|
||||||
var cinfo = new CollisionInfo();
|
var cinfo = CollisionPool.alloc();
|
||||||
cinfo.normal = normal.clone();
|
cinfo.normal = normal.clone();
|
||||||
cinfo.point = closest.clone();
|
cinfo.point = closest.clone();
|
||||||
|
cinfo.collider = null;
|
||||||
// cinfo.collider = this;
|
// cinfo.collider = this;
|
||||||
cinfo.velocity = this.velocity.clone();
|
cinfo.velocity = this.velocity.clone();
|
||||||
cinfo.contactDistance = Math.sqrt(contactDist);
|
cinfo.contactDistance = Math.sqrt(contactDist);
|
||||||
|
|
|
||||||
|
|
@ -40,10 +40,11 @@ class CollisionHull extends CollisionEntity {
|
||||||
|
|
||||||
var pt = GJK.gjk(sph, this.hull).epa;
|
var pt = GJK.gjk(sph, this.hull).epa;
|
||||||
if (pt != null) {
|
if (pt != null) {
|
||||||
var cinfo = new CollisionInfo();
|
var cinfo = CollisionPool.alloc();
|
||||||
cinfo.normal = pt.normalized();
|
cinfo.normal = pt.normalized();
|
||||||
cinfo.point = sph.position.sub(pt);
|
cinfo.point = sph.position.sub(pt);
|
||||||
cinfo.velocity = velocity;
|
cinfo.velocity = velocity;
|
||||||
|
cinfo.collider = null;
|
||||||
cinfo.contactDistance = sph.radius + pt.length();
|
cinfo.contactDistance = sph.radius + pt.length();
|
||||||
cinfo.restitution = restitution;
|
cinfo.restitution = restitution;
|
||||||
cinfo.otherObject = this.go;
|
cinfo.otherObject = this.go;
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,10 @@ class CollisionInfo {
|
||||||
public var collider:CollisionEntity;
|
public var collider:CollisionEntity;
|
||||||
public var otherObject:GameObject;
|
public var otherObject:GameObject;
|
||||||
public var friction:Float;
|
public var friction:Float;
|
||||||
public var vAtCMag:Float;
|
|
||||||
public var normalForce:Float;
|
public var normalForce:Float;
|
||||||
public var restitution:Float;
|
public var restitution:Float;
|
||||||
public var contactDistance:Float;
|
public var contactDistance:Float;
|
||||||
public var force:Float;
|
public var force:Float;
|
||||||
public var penetration:Float;
|
|
||||||
|
|
||||||
public function new() {}
|
public function new() {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
21
src/collision/CollisionPool.hx
Normal file
21
src/collision/CollisionPool.hx
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
package collision;
|
||||||
|
|
||||||
|
class CollisionPool {
|
||||||
|
static var pool:Array<CollisionInfo> = [];
|
||||||
|
static var currentPtr = 0;
|
||||||
|
|
||||||
|
public static function alloc() {
|
||||||
|
if (pool.length <= currentPtr) {
|
||||||
|
pool.push(new CollisionInfo());
|
||||||
|
}
|
||||||
|
return pool[currentPtr++];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function clear() {
|
||||||
|
currentPtr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function freeMemory() {
|
||||||
|
pool = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -85,7 +85,7 @@ class SphereCollisionEntity extends CollisionEntity {
|
||||||
|
|
||||||
if (otherRadius * otherRadius * 1.01 > otherDist.lengthSq()) {
|
if (otherRadius * otherRadius * 1.01 > otherDist.lengthSq()) {
|
||||||
var normDist = otherDist.normalized();
|
var normDist = otherDist.normalized();
|
||||||
var contact = new CollisionInfo();
|
var contact = CollisionPool.alloc();
|
||||||
contact.collider = this;
|
contact.collider = this;
|
||||||
contact.friction = 1;
|
contact.friction = 1;
|
||||||
contact.restitution = 1;
|
contact.restitution = 1;
|
||||||
|
|
@ -95,7 +95,6 @@ class SphereCollisionEntity extends CollisionEntity {
|
||||||
contact.normal = normDist.multiply(-1);
|
contact.normal = normDist.multiply(-1);
|
||||||
contact.force = 0;
|
contact.force = 0;
|
||||||
contact.contactDistance = contact.point.distance(position);
|
contact.contactDistance = contact.point.distance(position);
|
||||||
contact.penetration = radius - (position.sub(contact.point).dot(contact.normal));
|
|
||||||
contacts.push(contact);
|
contacts.push(contact);
|
||||||
|
|
||||||
// var othercontact = new CollisionInfo();
|
// var othercontact = new CollisionInfo();
|
||||||
|
|
|
||||||
|
|
@ -573,7 +573,8 @@ class HuntMode extends NullMode {
|
||||||
"data/skies/gemCubemapUp3.png",
|
"data/skies/gemCubemapUp3.png",
|
||||||
'data/shapes/items/red.gem.png',
|
'data/shapes/items/red.gem.png',
|
||||||
"data/skies/gemCubemapUp.png",
|
"data/skies/gemCubemapUp.png",
|
||||||
'sound/gem_collect.wav'
|
'sound/gem_collect.wav',
|
||||||
|
'sound/opponent_gem_collect.wav'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import haxe.io.Bytes;
|
||||||
import datachannel.RTCPeerConnection;
|
import datachannel.RTCPeerConnection;
|
||||||
import datachannel.RTCDataChannel;
|
import datachannel.RTCDataChannel;
|
||||||
import net.MoveManager;
|
import net.MoveManager;
|
||||||
|
import src.TimeState;
|
||||||
|
|
||||||
enum abstract GameplayState(Int) from Int to Int {
|
enum abstract GameplayState(Int) from Int to Int {
|
||||||
var UNKNOWN;
|
var UNKNOWN;
|
||||||
|
|
@ -55,5 +56,29 @@ abstract class GameConnection {
|
||||||
state = GameplayState.GAME;
|
state = GameplayState.GAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function queueMove(m:NetMove) {
|
||||||
|
moveManager.queueMove(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function acknowledgeMove(m:Int, timeState:TimeState) {
|
||||||
|
return moveManager.acknowledgeMove(m, timeState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function getQueuedMoves() {
|
||||||
|
return @:privateAccess moveManager.queuedMoves;
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function getQueuedMovesLength() {
|
||||||
|
return moveManager.getQueueSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function recordMove(marble:src.Marble, motionDir:h3d.Vector, timeState:TimeState) {
|
||||||
|
return moveManager.recordMove(marble, motionDir, timeState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNextMove() {
|
||||||
|
return moveManager.getNextMove();
|
||||||
|
}
|
||||||
|
|
||||||
public function sendBytes(b:haxe.io.Bytes) {}
|
public function sendBytes(b:haxe.io.Bytes) {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,8 @@ class MarblePrediction {
|
||||||
if (p.netFlags != 0)
|
if (p.netFlags != 0)
|
||||||
subs += 1;
|
subs += 1;
|
||||||
// if (p.powerUpId != powerupItemId)
|
// if (p.powerUpId != powerupItemId)
|
||||||
// subs += 1; // temp
|
if (tick % 10 == 0)
|
||||||
|
subs += 1; // temp
|
||||||
// if (isControl)
|
// if (isControl)
|
||||||
// subs += Math.abs(blastAmount - p.blastAmount);
|
// subs += Math.abs(blastAmount - p.blastAmount);
|
||||||
return subs;
|
return subs;
|
||||||
|
|
|
||||||
|
|
@ -343,7 +343,7 @@ class Net {
|
||||||
var movePacket = new MarbleMovePacket();
|
var movePacket = new MarbleMovePacket();
|
||||||
movePacket.deserialize(input);
|
movePacket.deserialize(input);
|
||||||
var cc = clientIdMap[movePacket.clientId];
|
var cc = clientIdMap[movePacket.clientId];
|
||||||
cc.moveManager.queueMove(movePacket.move);
|
cc.queueMove(movePacket.move);
|
||||||
|
|
||||||
case PowerupPickup:
|
case PowerupPickup:
|
||||||
var powerupPickupPacket = new PowerupPickupPacket();
|
var powerupPickupPacket = new PowerupPickupPacket();
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,6 @@ class Octree {
|
||||||
|
|
||||||
public function new() {
|
public function new() {
|
||||||
this.root = new OctreeNode(this, 0);
|
this.root = new OctreeNode(this, 0);
|
||||||
// Init the octree to a 1x1x1 cube
|
|
||||||
this.root.bounds = new Bounds();
|
|
||||||
this.root.bounds.xMin = this.root.bounds.yMin = this.root.bounds.zMin = 0;
|
|
||||||
this.root.bounds.xMax = this.root.bounds.yMax = this.root.bounds.zMax = 1;
|
|
||||||
this.objectToNode = new Map();
|
this.objectToNode = new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,22 +75,24 @@ class Octree {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
averagePoint = averagePoint.multiply(1 / count); // count should be greater than 0, because that's why we're growing in the first place.
|
averagePoint.load(averagePoint.multiply(1 / count)); // count should be greater than 0, because that's why we're growing in the first place.
|
||||||
// Determine the direction from the root center to the determined point
|
// Determine the direction from the root center to the determined point
|
||||||
var rootCenter = this.root.bounds.getCenter().toVector();
|
var rootCenter = new Vector((this.root.xMax + this.root.xMin) / 2, (this.root.yMax + this.root.yMin) / 2, (this.root.zMax + this.root.zMin) / 2);
|
||||||
var direction = averagePoint.sub(rootCenter); // Determine the "direction of growth"
|
var direction = averagePoint.sub(rootCenter); // Determine the "direction of growth"
|
||||||
// Create a new root. The current root will become a quadrant in this new root.
|
// Create a new root. The current root will become a quadrant in this new root.
|
||||||
var newRoot = new OctreeNode(this, this.root.depth - 1);
|
var newRoot = new OctreeNode(this, this.root.depth - 1);
|
||||||
newRoot.bounds = this.root.bounds.clone();
|
newRoot.xMin = this.root.xMin;
|
||||||
newRoot.bounds.xSize *= 2;
|
newRoot.yMin = this.root.yMin;
|
||||||
newRoot.bounds.ySize *= 2;
|
newRoot.zMin = this.root.zMin;
|
||||||
newRoot.bounds.zSize *= 2;
|
newRoot.xMax = 2 * this.root.xMax - this.root.xMin;
|
||||||
|
newRoot.yMax = 2 * this.root.yMax - this.root.yMin;
|
||||||
|
newRoot.zMax = 2 * this.root.zMax - this.root.zMin;
|
||||||
if (direction.x < 0)
|
if (direction.x < 0)
|
||||||
newRoot.bounds.xMin -= this.root.bounds.xSize;
|
newRoot.xMin -= this.root.xMax - this.root.xMin;
|
||||||
if (direction.y < 0)
|
if (direction.y < 0)
|
||||||
newRoot.bounds.yMin -= this.root.bounds.ySize;
|
newRoot.yMin -= this.root.yMax - this.root.yMin;
|
||||||
if (direction.z < 0)
|
if (direction.z < 0)
|
||||||
newRoot.bounds.zMin -= this.root.bounds.zSize;
|
newRoot.zMin -= this.root.zMax - this.root.zMin;
|
||||||
if (this.root.count > 0) {
|
if (this.root.count > 0) {
|
||||||
var octantIndex = ((direction.x < 0) ? 1 : 0) + ((direction.y < 0) ? 2 : 0) + ((direction.z < 0) ? 4 : 0);
|
var octantIndex = ((direction.x < 0) ? 1 : 0) + ((direction.y < 0) ? 2 : 0) + ((direction.z < 0) ? 4 : 0);
|
||||||
newRoot.createOctants();
|
newRoot.createOctants();
|
||||||
|
|
@ -108,12 +106,12 @@ class Octree {
|
||||||
|
|
||||||
/** Tries to shrink the octree if large parts of the octree are empty. */
|
/** Tries to shrink the octree if large parts of the octree are empty. */
|
||||||
public function shrink() {
|
public function shrink() {
|
||||||
if (this.root.bounds.xSize < 1 || this.root.bounds.ySize < 1 || this.root.bounds.zSize < 1 || this.root.objects.length > 0)
|
if (this.root.xMax - this.root.xMin < 1 || this.root.yMax - this.root.yMin < 1 || this.root.zMax - this.root.zMin < 1 || this.root.objects.length > 0)
|
||||||
return;
|
return;
|
||||||
if (this.root.count == 0) {
|
if (this.root.count == 0) {
|
||||||
// Reset to default empty octree
|
// Reset to default empty octree
|
||||||
this.root.bounds.xMin = this.root.bounds.yMin = this.root.bounds.zMin = 0;
|
this.root.xMin = this.root.yMin = this.root.zMin = 0;
|
||||||
this.root.bounds.xMax = this.root.bounds.yMax = this.root.bounds.zMin = 1;
|
this.root.xMax = this.root.yMax = this.root.zMax = 1;
|
||||||
this.root.depth = 0;
|
this.root.depth = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,13 @@ class OctreeNode implements IOctreeElement {
|
||||||
public var position:Int;
|
public var position:Int;
|
||||||
|
|
||||||
/** The min corner of the bounding box. */
|
/** The min corner of the bounding box. */
|
||||||
public var bounds:Bounds;
|
public var xMin:Float;
|
||||||
|
|
||||||
|
public var yMin:Float;
|
||||||
|
public var zMin:Float;
|
||||||
|
public var xMax:Float;
|
||||||
|
public var yMax:Float;
|
||||||
|
public var zMax:Float;
|
||||||
|
|
||||||
/** The size of the bounding box on all three axes. This forces the bounding box to be a cube. */
|
/** The size of the bounding box on all three axes. This forces the bounding box to be a cube. */
|
||||||
public var octants:Array<OctreeNode> = null;
|
public var octants:Array<OctreeNode> = null;
|
||||||
|
|
@ -29,6 +35,12 @@ class OctreeNode implements IOctreeElement {
|
||||||
public function new(octree:Octree, depth:Int) {
|
public function new(octree:Octree, depth:Int) {
|
||||||
this.octree = octree;
|
this.octree = octree;
|
||||||
this.depth = depth;
|
this.depth = depth;
|
||||||
|
this.xMin = 0;
|
||||||
|
this.yMin = 0;
|
||||||
|
this.zMin = 0;
|
||||||
|
this.xMax = 1;
|
||||||
|
this.yMax = 1;
|
||||||
|
this.zMax = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function insert(object:IOctreeObject) {
|
public function insert(object:IOctreeObject) {
|
||||||
|
|
@ -80,16 +92,13 @@ class OctreeNode implements IOctreeElement {
|
||||||
for (i in 0...8) {
|
for (i in 0...8) {
|
||||||
var newNode = new OctreeNode(this.octree, this.depth + 1);
|
var newNode = new OctreeNode(this.octree, this.depth + 1);
|
||||||
newNode.parent = this;
|
newNode.parent = this;
|
||||||
var newSize = this.bounds.getSize().multiply(1 / 2);
|
var newSize = new Vector(xMax - xMin, yMax - yMin, zMax - zMin);
|
||||||
newNode.bounds = this.bounds.clone();
|
newNode.xMin = this.xMin + newSize.x * ((i & 1) >> 0);
|
||||||
newNode.bounds.setMin(new Point(this.bounds.xMin
|
newNode.yMin = this.yMin + newSize.y * ((i & 2) >> 1);
|
||||||
+ newSize.x * ((i & 1) >> 0), this.bounds.yMin
|
newNode.zMin = this.zMin + newSize.z * ((i & 4) >> 2);
|
||||||
+ newSize.y * ((i & 2) >> 1),
|
newNode.xMax = newNode.xMin + newSize.x;
|
||||||
this.bounds.zMin
|
newNode.yMax = newNode.yMin + newSize.y;
|
||||||
+ newSize.z * ((i & 4) >> 2)));
|
newNode.zMax = newNode.zMin + newSize.z;
|
||||||
newNode.bounds.xSize = newSize.x;
|
|
||||||
newNode.bounds.ySize = newSize.y;
|
|
||||||
newNode.bounds.zSize = newSize.z;
|
|
||||||
this.octants.push(newNode);
|
this.octants.push(newNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -141,24 +150,53 @@ class OctreeNode implements IOctreeElement {
|
||||||
this.octants = null; // ...then devare the octants
|
this.octants = null; // ...then devare the octants
|
||||||
}
|
}
|
||||||
|
|
||||||
public function largerThan(object:IOctreeObject) {
|
public inline function largerThan(object:IOctreeObject) {
|
||||||
return this.bounds.containsBounds(object.boundingBox);
|
return xMin <= object.boundingBox.xMin && yMin <= object.boundingBox.yMin && zMin <= object.boundingBox.zMin && xMax >= object.boundingBox.xMax
|
||||||
|
&& yMax >= object.boundingBox.yMax && zMax >= object.boundingBox.zMax;
|
||||||
// return this.size > (box.xMax - box.xMin) && this.size > (box.yMax - box.yMin) && this.size > (box.zMax - box.zMin);
|
// return this.size > (box.xMax - box.xMin) && this.size > (box.yMax - box.yMin) && this.size > (box.zMax - box.zMin);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function containsCenter(object:IOctreeObject) {
|
public inline function containsCenter(object:IOctreeObject) {
|
||||||
return this.bounds.contains(object.boundingBox.getCenter());
|
return this.containsPoint2(object.boundingBox.getCenter());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function containsPoint(point:Vector) {
|
public inline function containsPoint(p:Vector) {
|
||||||
return this.bounds.contains(point.toPoint());
|
return p.x >= xMin && p.x < xMax && p.y >= yMin && p.y < yMax && p.z >= zMin && p.z < zMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function containsPoint2(p:h3d.col.Point) {
|
||||||
|
return p.x >= xMin && p.x < xMax && p.y >= yMin && p.y < yMax && p.z >= zMin && p.z < zMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline function rayIntersection(r:Ray, bestMatch:Bool):Float {
|
||||||
|
var minTx = (xMin - r.px) / r.lx;
|
||||||
|
var minTy = (yMin - r.py) / r.ly;
|
||||||
|
var minTz = (zMin - r.pz) / r.lz;
|
||||||
|
var maxTx = (xMax - r.px) / r.lx;
|
||||||
|
var maxTy = (yMax - r.py) / r.ly;
|
||||||
|
var maxTz = (zMax - r.pz) / r.lz;
|
||||||
|
|
||||||
|
var realMinTx = Math.min(minTx, maxTx);
|
||||||
|
var realMinTy = Math.min(minTy, maxTy);
|
||||||
|
var realMinTz = Math.min(minTz, maxTz);
|
||||||
|
var realMaxTx = Math.max(minTx, maxTx);
|
||||||
|
var realMaxTy = Math.max(minTy, maxTy);
|
||||||
|
var realMaxTz = Math.max(minTz, maxTz);
|
||||||
|
|
||||||
|
var minmax = Math.min(Math.min(realMaxTx, realMaxTy), realMaxTz);
|
||||||
|
var maxmin = Math.max(Math.max(realMinTx, realMinTy), realMinTz);
|
||||||
|
|
||||||
|
if (minmax < maxmin)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return maxmin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function raycast(rayOrigin:Vector, rayDirection:Vector, intersections:Array<OctreeIntersection>) {
|
public function raycast(rayOrigin:Vector, rayDirection:Vector, intersections:Array<OctreeIntersection>) {
|
||||||
var ray = Ray.fromValues(rayOrigin.x, rayOrigin.y, rayOrigin.z, rayDirection.x, rayDirection.y, rayDirection.z);
|
var ray = Ray.fromValues(rayOrigin.x, rayOrigin.y, rayOrigin.z, rayDirection.x, rayDirection.y, rayDirection.z);
|
||||||
// Construct the loose bounding box of this node (2x in size, with the regular bounding box in the center)
|
// Construct the loose bounding box of this node (2x in size, with the regular bounding box in the center)
|
||||||
|
|
||||||
if (this.bounds.rayIntersection(ray, true) == -1)
|
if (rayIntersection(ray, true) == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (obj in this.objects) {
|
for (obj in this.objects) {
|
||||||
|
|
@ -181,42 +219,22 @@ class OctreeNode implements IOctreeElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function boundingSearch(bounds:Bounds, intersections:Array<IOctreeElement>) {
|
public function boundingSearch(b:Bounds, intersections:Array<IOctreeElement>) {
|
||||||
if (this.bounds.collide(bounds)) {
|
if (!(xMin > b.xMax || yMin > b.yMax || zMin > b.zMax || xMax < b.xMin || yMax < b.yMin || zMax < b.zMin)) {
|
||||||
for (obj in this.objects) {
|
for (obj in this.objects) {
|
||||||
if (obj.boundingBox.collide(bounds))
|
if (obj.boundingBox.collide(b))
|
||||||
intersections.push(obj);
|
intersections.push(obj);
|
||||||
}
|
}
|
||||||
if (octants != null) {
|
if (octants != null) {
|
||||||
for (octant in this.octants)
|
for (octant in this.octants)
|
||||||
octant.boundingSearch(bounds, intersections);
|
octant.boundingSearch(b, intersections);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getClosestPoint(point:Vector) {
|
public inline function getClosestPoint(point:Vector) {
|
||||||
var closest = new Vector();
|
var closest = new Vector(Math.min(Math.max(this.xMin, point.x), this.xMax), Math.min(Math.max(this.yMin, point.y), this.yMax),
|
||||||
if (this.bounds.xMin > point.x)
|
Math.min(Math.max(this.zMin, point.z), this.zMax));
|
||||||
closest.x = this.bounds.xMin;
|
|
||||||
else if (this.bounds.xMax < point.x)
|
|
||||||
closest.x = this.bounds.xMax;
|
|
||||||
else
|
|
||||||
closest.x = point.x;
|
|
||||||
|
|
||||||
if (this.bounds.yMin > point.y)
|
|
||||||
closest.y = this.bounds.yMin;
|
|
||||||
else if (this.bounds.yMax < point.y)
|
|
||||||
closest.y = this.bounds.yMax;
|
|
||||||
else
|
|
||||||
closest.y = point.y;
|
|
||||||
|
|
||||||
if (this.bounds.zMin > point.z)
|
|
||||||
closest.z = this.bounds.zMin;
|
|
||||||
else if (this.bounds.zMax < point.z)
|
|
||||||
closest.z = this.bounds.zMax;
|
|
||||||
else
|
|
||||||
closest.z = point.z;
|
|
||||||
|
|
||||||
return closest;
|
return closest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue