mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2025-10-30 08:11:25 +00:00
get blasting and server side powerup images working
This commit is contained in:
parent
dc0f2df246
commit
d651d32b4c
10 changed files with 147 additions and 41 deletions
|
|
@ -17,7 +17,7 @@ class Debug {
|
|||
}> = [];
|
||||
|
||||
static var debugTriangles:h3d.scene.Mesh;
|
||||
static var debugSphere:h3d.scene.MeshBatch;
|
||||
static var debugSphere:src.MeshBatch;
|
||||
|
||||
public static function init() {}
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ class Debug {
|
|||
var sphprim = new h3d.prim.Sphere();
|
||||
sphprim.addUVs();
|
||||
sphprim.addNormals();
|
||||
debugSphere = new h3d.scene.MeshBatch(sphprim, h3d.mat.Material.create());
|
||||
debugSphere = new src.MeshBatch(sphprim, h3d.mat.Material.create());
|
||||
debugSphere.material.castShadows = false;
|
||||
debugSphere.material.receiveShadows = false;
|
||||
MarbleGame.instance.scene.addChild(debugSphere);
|
||||
|
|
|
|||
119
src/Marble.hx
119
src/Marble.hx
|
|
@ -72,15 +72,8 @@ import src.InteriorObject;
|
|||
import src.Console;
|
||||
import src.Gamepad;
|
||||
import net.Net;
|
||||
|
||||
class Move {
|
||||
public var d:Vector;
|
||||
public var jump:Bool;
|
||||
public var powerup:Bool;
|
||||
public var blast:Bool;
|
||||
|
||||
public function new() {}
|
||||
}
|
||||
import net.Move;
|
||||
import src.Debug;
|
||||
|
||||
enum Mode {
|
||||
Start;
|
||||
|
|
@ -224,6 +217,8 @@ class Marble extends GameObject {
|
|||
var minVelocityBounceSoft = 2.5;
|
||||
var minVelocityBounceHard = 12.0;
|
||||
var bounceMinGain = 0.2;
|
||||
var maxBlastRepulse = 60.0;
|
||||
var blastRepulseDist = 10.0;
|
||||
|
||||
public var _bounceRestitution = 0.5;
|
||||
|
||||
|
|
@ -261,6 +256,10 @@ class Marble extends GameObject {
|
|||
var blastUseTime:Float = -1e8;
|
||||
|
||||
public var blastAmount:Float = 0;
|
||||
public var blastTicks:Int = 0;
|
||||
public var blastUseTick:Int = 0; // blast is 12 ticks long
|
||||
|
||||
var blastPerc:Float = 0.0;
|
||||
|
||||
var teleportEnableTime:Null<Float> = null;
|
||||
var teleportDisableTime:Null<Float> = null;
|
||||
|
|
@ -510,7 +509,7 @@ class Marble extends GameObject {
|
|||
this.helicopter.z = 1e8;
|
||||
this.helicopter.scale(0.3 / 0.2);
|
||||
|
||||
if (this.controllable) {
|
||||
if (this.controllable || this.connection != null) {
|
||||
var worker = new ResourceLoaderWorker(onFinish);
|
||||
worker.addTask(fwd -> level.addDtsObject(this.helicopter, fwd));
|
||||
worker.addTask(fwd -> level.addDtsObject(this.blastWave, fwd));
|
||||
|
|
@ -559,7 +558,7 @@ class Marble extends GameObject {
|
|||
}
|
||||
}
|
||||
|
||||
function getExternalForces(currentTime:Float, m:Move, dt:Float) {
|
||||
function getExternalForces(currentTime:Float, m:Move, dt:Float, tick:Int) {
|
||||
if (this.mode == Finish)
|
||||
return this.velocity.multiply(-16);
|
||||
var gWorkGravityDir = this.currentUp.multiply(-1);
|
||||
|
|
@ -573,6 +572,12 @@ class Marble extends GameObject {
|
|||
var force = cast(obj, ForceObject).getForce(this.collider.transform.getPosition());
|
||||
A = A.add(force.multiply(1 / _mass));
|
||||
}
|
||||
for (marble in level.marbles) {
|
||||
if (marble != this) {
|
||||
var force = marble.getForce(this.collider.transform.getPosition(), tick);
|
||||
A = A.add(force.multiply(1 / _mass));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (contacts.length != 0 && this.mode != Start) {
|
||||
var contactForce = 0.0;
|
||||
|
|
@ -1483,8 +1488,8 @@ class Marble extends GameObject {
|
|||
}
|
||||
|
||||
// Blast
|
||||
if (m.blast) {
|
||||
this.useBlast();
|
||||
if (m != null && m.blast) {
|
||||
this.useBlast(timeState);
|
||||
if (level.isRecording) {
|
||||
level.replay.recordMarbleStateFlags(false, false, false, true);
|
||||
}
|
||||
|
|
@ -1519,7 +1524,7 @@ class Marble extends GameObject {
|
|||
var isCentered = this.computeMoveForces(m, aControl, desiredOmega);
|
||||
|
||||
stoppedPaths = this.velocityCancel(timeState.currentAttemptTime, timeStep, isCentered, false, stoppedPaths, pathedInteriors);
|
||||
var A = this.getExternalForces(timeState.currentAttemptTime, m, timeStep);
|
||||
var A = this.getExternalForces(timeState.currentAttemptTime, m, timeStep, timeState.ticks);
|
||||
var a = this.applyContactForces(timeStep, m, isCentered, aControl, desiredOmega, A);
|
||||
this.velocity.set(this.velocity.x + A.x * timeStep, this.velocity.y + A.y * timeStep, this.velocity.z + A.z * timeStep);
|
||||
this.omega.set(this.omega.x + a.x * timeStep, this.omega.y + a.y * timeStep, this.omega.z + a.z * timeStep);
|
||||
|
|
@ -1654,6 +1659,8 @@ class Marble extends GameObject {
|
|||
marbleUpdate.omega = this.omega;
|
||||
marbleUpdate.move = move;
|
||||
marbleUpdate.moveQueueSize = this.connection != null ? this.connection.moveManager.getQueueSize() : 255;
|
||||
marbleUpdate.blastAmount = this.blastTicks;
|
||||
marbleUpdate.blastTick = this.blastUseTick;
|
||||
marbleUpdate.serialize(b);
|
||||
return b.getBytes();
|
||||
}
|
||||
|
|
@ -1672,6 +1679,8 @@ class Marble extends GameObject {
|
|||
this.collider.transform.setPosition(p.position);
|
||||
this.velocity = p.velocity;
|
||||
this.omega = p.omega;
|
||||
this.blastTicks = p.blastAmount;
|
||||
this.blastUseTick = p.blastTick;
|
||||
if (this.controllable && Net.isClient) {
|
||||
// We are client, need to do something about the queue
|
||||
var mm = Net.clientConnection.moveManager;
|
||||
|
|
@ -1721,6 +1730,10 @@ class Marble extends GameObject {
|
|||
}
|
||||
move = new NetMove(innerMove, axis, timeState, 65535);
|
||||
}
|
||||
|
||||
if (this.blastTicks < (30000 >> 5))
|
||||
this.blastTicks += 1;
|
||||
|
||||
playedSounds = [];
|
||||
advancePhysics(timeState, move.move, collisionWorld, pathedInteriors);
|
||||
physicsAccumulator = 0;
|
||||
|
|
@ -1828,6 +1841,12 @@ class Marble extends GameObject {
|
|||
|| Gamepad.isDown(Settings.gamepadSettings.powerup)) {
|
||||
move.powerup = true;
|
||||
}
|
||||
|
||||
if (Key.isDown(Settings.controlsSettings.blast)
|
||||
|| (MarbleGame.instance.touchInput.blastbutton.pressed)
|
||||
|| Gamepad.isDown(Settings.gamepadSettings.blast))
|
||||
move.blast = true;
|
||||
|
||||
if (MarbleGame.instance.touchInput.movementInput.pressed) {
|
||||
move.d.y = -MarbleGame.instance.touchInput.movementInput.value.x;
|
||||
move.d.x = MarbleGame.instance.touchInput.movementInput.value.y;
|
||||
|
|
@ -1838,7 +1857,7 @@ class Marble extends GameObject {
|
|||
// SP only function
|
||||
public function update(timeState:TimeState, collisionWorld:CollisionWorld, pathedInteriors:Array<PathedInterior>) {
|
||||
var move:Move = null;
|
||||
if (this.controllable && this.mode != Finish && !MarbleGame.instance.paused && !this.level.isWatching && !this.level.isReplayingMovement) {
|
||||
if (this.controllable && !this.level.isWatching && !this.level.isReplayingMovement) {
|
||||
move = recordMove();
|
||||
}
|
||||
|
||||
|
|
@ -2042,7 +2061,7 @@ class Marble extends GameObject {
|
|||
}
|
||||
|
||||
public function updatePowerupStates(currentTime:Float, dt:Float) {
|
||||
if (!this.controllable)
|
||||
if (!this.controllable && this.connection == null)
|
||||
return;
|
||||
if (currentTime - this.helicopterEnableTime < 5) {
|
||||
this.helicopter.setPosition(x, y, z);
|
||||
|
|
@ -2053,6 +2072,7 @@ class Marble extends GameObject {
|
|||
this.helicopter.setPosition(1e8, 1e8, 1e8);
|
||||
this.helicopterSound.pause = true;
|
||||
}
|
||||
|
||||
if (this.blastUseTime > currentTime) {
|
||||
this.blastUseTime = Math.POSITIVE_INFINITY;
|
||||
this.blastWave.doSequenceOnceBeginTime = 0;
|
||||
|
|
@ -2076,17 +2096,60 @@ class Marble extends GameObject {
|
|||
}
|
||||
}
|
||||
|
||||
public function useBlast() {
|
||||
if (this.blastAmount < 0.25)
|
||||
return false;
|
||||
var impulse = this.currentUp.multiply(this.blastAmount * 8);
|
||||
this.applyImpulse(impulse);
|
||||
if (this.controllable)
|
||||
AudioManager.playSound(ResourceLoader.getResource('data/sound/use_blast.wav', ResourceLoader.getAudio, this.soundResources));
|
||||
this.blastWave.doSequenceOnceBeginTime = this.level.timeState.timeSinceLoad;
|
||||
this.blastUseTime = this.level.timeState.currentAttemptTime;
|
||||
this.blastAmount = 0;
|
||||
return true;
|
||||
public function useBlast(timeState:TimeState) {
|
||||
if (this.level.isMultiplayer) {
|
||||
if (this.blastTicks < (7500 >> 5))
|
||||
return false;
|
||||
this.blastUseTick = timeState.ticks;
|
||||
var amount = this.blastTicks / (30000 >> 5);
|
||||
this.blastPerc = amount;
|
||||
var impulse = this.currentUp.multiply(amount * 8);
|
||||
this.applyImpulse(impulse);
|
||||
if (this.controllable)
|
||||
AudioManager.playSound(ResourceLoader.getResource('data/sound/use_blast.wav', ResourceLoader.getAudio, this.soundResources));
|
||||
this.blastWave.doSequenceOnceBeginTime = this.level.timeState.timeSinceLoad;
|
||||
this.blastUseTime = this.level.timeState.currentAttemptTime;
|
||||
this.blastTicks = 0;
|
||||
return true;
|
||||
} else {
|
||||
if (this.blastAmount < 0.25)
|
||||
return false;
|
||||
var impulse = this.currentUp.multiply(this.blastAmount * 8);
|
||||
this.applyImpulse(impulse);
|
||||
if (this.controllable)
|
||||
AudioManager.playSound(ResourceLoader.getResource('data/sound/use_blast.wav', ResourceLoader.getAudio, this.soundResources));
|
||||
this.blastWave.doSequenceOnceBeginTime = this.level.timeState.timeSinceLoad;
|
||||
this.blastUseTime = this.level.timeState.currentAttemptTime;
|
||||
this.blastAmount = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function getForce(position:Vector, tick:Int) {
|
||||
var retForce = new Vector();
|
||||
if (tick - blastUseTick >= 12)
|
||||
return retForce;
|
||||
var delta = position.sub(newPos);
|
||||
var deltaLen = delta.length();
|
||||
|
||||
var maxDist = Math.max(blastRepulseDist, blastRepulseDist * blastPerc);
|
||||
var maxRepulse = maxBlastRepulse * blastPerc;
|
||||
|
||||
if (deltaLen > maxDist)
|
||||
return retForce;
|
||||
|
||||
if (deltaLen >= 0.05) {
|
||||
var dist = 0.0;
|
||||
if (deltaLen >= 1.0)
|
||||
dist = (1.0 / deltaLen - 1.0 / maxDist) * maxRepulse;
|
||||
else
|
||||
dist = maxRepulse / deltaLen;
|
||||
|
||||
retForce.load(retForce.add(delta.multiply(dist)));
|
||||
} else {
|
||||
retForce.load(retForce.add(this.currentUp.multiply(maxRepulse)));
|
||||
}
|
||||
return retForce;
|
||||
}
|
||||
|
||||
public function applyImpulse(impulse:Vector, contactImpulse:Bool = false) {
|
||||
|
|
@ -2156,6 +2219,8 @@ class Marble extends GameObject {
|
|||
this.helicopterEnableTime = Math.NEGATIVE_INFINITY;
|
||||
this.megaMarbleEnableTime = Math.NEGATIVE_INFINITY;
|
||||
this.blastUseTime = Math.NEGATIVE_INFINITY;
|
||||
this.blastUseTick = 0;
|
||||
this.blastTicks = 0;
|
||||
this.lastContactNormal = new Vector(0, 0, 1);
|
||||
this.contactEntities = [];
|
||||
this.cloak = false;
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ class MarbleWorld extends Scheduler {
|
|||
|
||||
public var interiors:Array<InteriorObject> = [];
|
||||
public var pathedInteriors:Array<PathedInterior> = [];
|
||||
public var marbles:Array<Marble> = [];
|
||||
public var dtsObjects:Array<DtsObject> = [];
|
||||
public var powerUps:Array<PowerUp> = [];
|
||||
public var forceObjects:Array<ForceObject> = [];
|
||||
|
|
@ -982,6 +983,7 @@ class MarbleWorld extends Scheduler {
|
|||
|
||||
public function addMarble(marble:Marble, client:GameConnection, onFinish:Void->Void) {
|
||||
marble.level = cast this;
|
||||
this.marbles.push(marble);
|
||||
if (marble.controllable) {
|
||||
marble.init(cast this, client, () -> {
|
||||
this.scene.addChild(marble.camera);
|
||||
|
|
@ -1234,7 +1236,7 @@ class MarbleWorld extends Scheduler {
|
|||
|| Gamepad.isDown(Settings.gamepadSettings.blast)
|
||||
&& !this.isWatching
|
||||
&& this.game == "ultra") {
|
||||
this.marble.useBlast();
|
||||
this.marble.useBlast(timeState);
|
||||
}
|
||||
|
||||
this.updateGameState();
|
||||
|
|
@ -1369,7 +1371,7 @@ class MarbleWorld extends Scheduler {
|
|||
this.tickSchedule(timeState.currentAttemptTime);
|
||||
|
||||
if (this.isWatching && this.replay.currentPlaybackFrame.marbleStateFlags.has(UsedBlast))
|
||||
this.marble.useBlast();
|
||||
this.marble.useBlast(timeState);
|
||||
|
||||
// Replay gravity
|
||||
if (this.isWatching) {
|
||||
|
|
@ -1441,6 +1443,7 @@ class MarbleWorld extends Scheduler {
|
|||
}
|
||||
timeState.ticks++;
|
||||
}
|
||||
timeState.subframe = tickAccumulator / 0.032;
|
||||
marble.updateClient(timeState, this.pathedInteriors);
|
||||
for (client => marble in clientMarbles) {
|
||||
marble.updateClient(timeState, this.pathedInteriors);
|
||||
|
|
@ -1600,16 +1603,27 @@ class MarbleWorld extends Scheduler {
|
|||
}
|
||||
|
||||
public function updateBlast(marble:Marble, timestate:TimeState) {
|
||||
if (marble.blastAmount < 1) {
|
||||
marble.blastAmount = Util.clamp(marble.blastAmount + (timeState.dt / 30), 0, 1);
|
||||
if (marble == this.marble)
|
||||
this.renderBlastAmount = marble.blastAmount;
|
||||
if (this.isMultiplayer) {
|
||||
if (marble == this.marble) {
|
||||
if (marble.blastTicks < (36000 >> 5)) {
|
||||
this.renderBlastAmount = (marble.blastTicks + timestate.subframe) / (30000 >> 5);
|
||||
} else {
|
||||
this.renderBlastAmount = Math.min(marble.blastTicks / (30000 >> 5), timestate.dt * 0.75 + this.renderBlastAmount);
|
||||
}
|
||||
this.playGui.setBlastValue(this.renderBlastAmount);
|
||||
}
|
||||
} else {
|
||||
if (marble.blastAmount < 1) {
|
||||
marble.blastAmount = Util.clamp(marble.blastAmount + (timeState.dt / 30), 0, 1);
|
||||
if (marble == this.marble)
|
||||
this.renderBlastAmount = marble.blastAmount;
|
||||
} else {
|
||||
if (marble == this.marble)
|
||||
this.renderBlastAmount = Math.min(marble.blastAmount, timestate.dt * 0.75 + this.renderBlastAmount);
|
||||
}
|
||||
if (marble == this.marble)
|
||||
this.renderBlastAmount = Math.min(marble.blastAmount, timestate.dt * 0.75 + this.renderBlastAmount);
|
||||
this.playGui.setBlastValue(this.renderBlastAmount);
|
||||
}
|
||||
if (marble == this.marble)
|
||||
this.playGui.setBlastValue(this.renderBlastAmount);
|
||||
}
|
||||
|
||||
function updateTexts() {
|
||||
|
|
@ -2234,7 +2248,7 @@ class MarbleWorld extends Scheduler {
|
|||
pathedInteriors.dispose();
|
||||
}
|
||||
pathedInteriors = null;
|
||||
for (client => marble in clientMarbles) {
|
||||
for (marble in marbles) {
|
||||
marble.dispose();
|
||||
}
|
||||
clientMarbles = null;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ class TimeState {
|
|||
var gameplayClock:Float;
|
||||
var dt:Float;
|
||||
var ticks:Int; // How many 32ms ticks have happened
|
||||
var subframe:Float;
|
||||
|
||||
public function new() {}
|
||||
|
||||
|
|
@ -17,6 +18,7 @@ class TimeState {
|
|||
n.gameplayClock = this.gameplayClock;
|
||||
n.dt = this.dt;
|
||||
n.ticks = ticks;
|
||||
n.subframe = subframe;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,16 +12,22 @@ class MarblePrediction {
|
|||
var position:Vector;
|
||||
var velocity:Vector;
|
||||
var omega:Vector;
|
||||
var isControl:Bool;
|
||||
var blastAmount:Int;
|
||||
|
||||
public function new(marble:Marble, tick:Int) {
|
||||
this.tick = tick;
|
||||
position = @:privateAccess marble.newPos.clone();
|
||||
velocity = @:privateAccess marble.velocity.clone();
|
||||
omega = @:privateAccess marble.omega.clone();
|
||||
blastAmount = @:privateAccess marble.blastTicks;
|
||||
isControl = @:privateAccess marble.controllable;
|
||||
}
|
||||
|
||||
public inline function getError(p:MarbleUpdatePacket) {
|
||||
var subs = position.sub(p.position).lengthSq() + velocity.sub(p.velocity).lengthSq() + omega.sub(p.omega).lengthSq();
|
||||
if (isControl)
|
||||
subs += Math.abs(blastAmount - p.blastAmount);
|
||||
return subs;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
12
src/net/Move.hx
Normal file
12
src/net/Move.hx
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package net;
|
||||
|
||||
import h3d.Vector;
|
||||
|
||||
class Move {
|
||||
public var d:Vector;
|
||||
public var jump:Bool;
|
||||
public var powerup:Bool;
|
||||
public var blast:Bool;
|
||||
|
||||
public function new() {}
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ import src.Console;
|
|||
import net.ClientConnection;
|
||||
import net.Net.NetPacketType;
|
||||
import src.MarbleWorld;
|
||||
import src.Marble.Move;
|
||||
import net.Move;
|
||||
import h3d.Vector;
|
||||
import src.Gamepad;
|
||||
import src.Settings;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ class MarbleUpdatePacket implements NetPacket {
|
|||
var position:Vector;
|
||||
var velocity:Vector;
|
||||
var omega:Vector;
|
||||
var blastAmount:Int;
|
||||
var blastTick:Int;
|
||||
var moveQueueSize:Int;
|
||||
|
||||
public function new() {}
|
||||
|
|
@ -56,6 +58,8 @@ class MarbleUpdatePacket implements NetPacket {
|
|||
b.writeFloat(omega.x);
|
||||
b.writeFloat(omega.y);
|
||||
b.writeFloat(omega.z);
|
||||
b.writeUInt16(blastAmount);
|
||||
b.writeUInt16(blastTick);
|
||||
}
|
||||
|
||||
public inline function deserialize(b:haxe.io.BytesInput) {
|
||||
|
|
@ -66,5 +70,7 @@ class MarbleUpdatePacket implements NetPacket {
|
|||
position = new Vector(b.readFloat(), b.readFloat(), b.readFloat());
|
||||
velocity = new Vector(b.readFloat(), b.readFloat(), b.readFloat());
|
||||
omega = new Vector(b.readFloat(), b.readFloat(), b.readFloat());
|
||||
blastAmount = b.readUInt16();
|
||||
blastTick = b.readUInt16();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package rewind;
|
|||
|
||||
import src.MarbleWorld;
|
||||
import h3d.Vector;
|
||||
import src.Marble.Move;
|
||||
import net.Move;
|
||||
|
||||
@:publicFields
|
||||
class InputRecorderFrame {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ class Blast extends PowerUp {
|
|||
|
||||
public function use(marble:Marble, timeState:TimeState) {
|
||||
marble.blastAmount = 1.2;
|
||||
marble.blastTicks = 36000 >> 5;
|
||||
}
|
||||
|
||||
override function getPreloadMaterials(dts:dts.DtsFile) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue