get blasting and server side powerup images working

This commit is contained in:
RandomityGuy 2024-02-03 01:06:40 +05:30
parent dc0f2df246
commit d651d32b4c
10 changed files with 147 additions and 41 deletions

View file

@ -17,7 +17,7 @@ class Debug {
}> = []; }> = [];
static var debugTriangles:h3d.scene.Mesh; static var debugTriangles:h3d.scene.Mesh;
static var debugSphere:h3d.scene.MeshBatch; static var debugSphere:src.MeshBatch;
public static function init() {} public static function init() {}
@ -43,7 +43,7 @@ class Debug {
var sphprim = new h3d.prim.Sphere(); var sphprim = new h3d.prim.Sphere();
sphprim.addUVs(); sphprim.addUVs();
sphprim.addNormals(); 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.castShadows = false;
debugSphere.material.receiveShadows = false; debugSphere.material.receiveShadows = false;
MarbleGame.instance.scene.addChild(debugSphere); MarbleGame.instance.scene.addChild(debugSphere);

View file

@ -72,15 +72,8 @@ import src.InteriorObject;
import src.Console; import src.Console;
import src.Gamepad; import src.Gamepad;
import net.Net; import net.Net;
import net.Move;
class Move { import src.Debug;
public var d:Vector;
public var jump:Bool;
public var powerup:Bool;
public var blast:Bool;
public function new() {}
}
enum Mode { enum Mode {
Start; Start;
@ -224,6 +217,8 @@ class Marble extends GameObject {
var minVelocityBounceSoft = 2.5; var minVelocityBounceSoft = 2.5;
var minVelocityBounceHard = 12.0; var minVelocityBounceHard = 12.0;
var bounceMinGain = 0.2; var bounceMinGain = 0.2;
var maxBlastRepulse = 60.0;
var blastRepulseDist = 10.0;
public var _bounceRestitution = 0.5; public var _bounceRestitution = 0.5;
@ -261,6 +256,10 @@ class Marble extends GameObject {
var blastUseTime:Float = -1e8; var blastUseTime:Float = -1e8;
public var blastAmount:Float = 0; 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 teleportEnableTime:Null<Float> = null;
var teleportDisableTime:Null<Float> = null; var teleportDisableTime:Null<Float> = null;
@ -510,7 +509,7 @@ class Marble extends GameObject {
this.helicopter.z = 1e8; this.helicopter.z = 1e8;
this.helicopter.scale(0.3 / 0.2); this.helicopter.scale(0.3 / 0.2);
if (this.controllable) { if (this.controllable || this.connection != null) {
var worker = new ResourceLoaderWorker(onFinish); var worker = new ResourceLoaderWorker(onFinish);
worker.addTask(fwd -> level.addDtsObject(this.helicopter, fwd)); worker.addTask(fwd -> level.addDtsObject(this.helicopter, fwd));
worker.addTask(fwd -> level.addDtsObject(this.blastWave, 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) if (this.mode == Finish)
return this.velocity.multiply(-16); return this.velocity.multiply(-16);
var gWorkGravityDir = this.currentUp.multiply(-1); var gWorkGravityDir = this.currentUp.multiply(-1);
@ -573,6 +572,12 @@ class Marble extends GameObject {
var force = cast(obj, ForceObject).getForce(this.collider.transform.getPosition()); var force = cast(obj, ForceObject).getForce(this.collider.transform.getPosition());
A = A.add(force.multiply(1 / _mass)); 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) { if (contacts.length != 0 && this.mode != Start) {
var contactForce = 0.0; var contactForce = 0.0;
@ -1483,8 +1488,8 @@ class Marble extends GameObject {
} }
// Blast // Blast
if (m.blast) { if (m != null && m.blast) {
this.useBlast(); this.useBlast(timeState);
if (level.isRecording) { if (level.isRecording) {
level.replay.recordMarbleStateFlags(false, false, false, true); level.replay.recordMarbleStateFlags(false, false, false, true);
} }
@ -1519,7 +1524,7 @@ class Marble extends GameObject {
var isCentered = this.computeMoveForces(m, aControl, desiredOmega); var isCentered = this.computeMoveForces(m, aControl, desiredOmega);
stoppedPaths = this.velocityCancel(timeState.currentAttemptTime, timeStep, isCentered, false, stoppedPaths, pathedInteriors); 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); 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.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); 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.omega = this.omega;
marbleUpdate.move = move; marbleUpdate.move = move;
marbleUpdate.moveQueueSize = this.connection != null ? this.connection.moveManager.getQueueSize() : 255; marbleUpdate.moveQueueSize = this.connection != null ? this.connection.moveManager.getQueueSize() : 255;
marbleUpdate.blastAmount = this.blastTicks;
marbleUpdate.blastTick = this.blastUseTick;
marbleUpdate.serialize(b); marbleUpdate.serialize(b);
return b.getBytes(); return b.getBytes();
} }
@ -1672,6 +1679,8 @@ class Marble extends GameObject {
this.collider.transform.setPosition(p.position); this.collider.transform.setPosition(p.position);
this.velocity = p.velocity; this.velocity = p.velocity;
this.omega = p.omega; this.omega = p.omega;
this.blastTicks = p.blastAmount;
this.blastUseTick = p.blastTick;
if (this.controllable && Net.isClient) { if (this.controllable && Net.isClient) {
// We are client, need to do something about the queue // We are client, need to do something about the queue
var mm = Net.clientConnection.moveManager; var mm = Net.clientConnection.moveManager;
@ -1721,6 +1730,10 @@ class Marble extends GameObject {
} }
move = new NetMove(innerMove, axis, timeState, 65535); move = new NetMove(innerMove, axis, timeState, 65535);
} }
if (this.blastTicks < (30000 >> 5))
this.blastTicks += 1;
playedSounds = []; playedSounds = [];
advancePhysics(timeState, move.move, collisionWorld, pathedInteriors); advancePhysics(timeState, move.move, collisionWorld, pathedInteriors);
physicsAccumulator = 0; physicsAccumulator = 0;
@ -1828,6 +1841,12 @@ class Marble extends GameObject {
|| Gamepad.isDown(Settings.gamepadSettings.powerup)) { || Gamepad.isDown(Settings.gamepadSettings.powerup)) {
move.powerup = true; 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) { if (MarbleGame.instance.touchInput.movementInput.pressed) {
move.d.y = -MarbleGame.instance.touchInput.movementInput.value.x; move.d.y = -MarbleGame.instance.touchInput.movementInput.value.x;
move.d.x = MarbleGame.instance.touchInput.movementInput.value.y; move.d.x = MarbleGame.instance.touchInput.movementInput.value.y;
@ -1838,7 +1857,7 @@ class Marble extends GameObject {
// SP only function // SP only function
public function update(timeState:TimeState, collisionWorld:CollisionWorld, pathedInteriors:Array<PathedInterior>) { public function update(timeState:TimeState, collisionWorld:CollisionWorld, pathedInteriors:Array<PathedInterior>) {
var move:Move = null; 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(); move = recordMove();
} }
@ -2042,7 +2061,7 @@ class Marble extends GameObject {
} }
public function updatePowerupStates(currentTime:Float, dt:Float) { public function updatePowerupStates(currentTime:Float, dt:Float) {
if (!this.controllable) if (!this.controllable && this.connection == null)
return; return;
if (currentTime - this.helicopterEnableTime < 5) { if (currentTime - this.helicopterEnableTime < 5) {
this.helicopter.setPosition(x, y, z); this.helicopter.setPosition(x, y, z);
@ -2053,6 +2072,7 @@ class Marble extends GameObject {
this.helicopter.setPosition(1e8, 1e8, 1e8); this.helicopter.setPosition(1e8, 1e8, 1e8);
this.helicopterSound.pause = true; this.helicopterSound.pause = true;
} }
if (this.blastUseTime > currentTime) { if (this.blastUseTime > currentTime) {
this.blastUseTime = Math.POSITIVE_INFINITY; this.blastUseTime = Math.POSITIVE_INFINITY;
this.blastWave.doSequenceOnceBeginTime = 0; this.blastWave.doSequenceOnceBeginTime = 0;
@ -2076,17 +2096,60 @@ class Marble extends GameObject {
} }
} }
public function useBlast() { public function useBlast(timeState:TimeState) {
if (this.blastAmount < 0.25) if (this.level.isMultiplayer) {
return false; if (this.blastTicks < (7500 >> 5))
var impulse = this.currentUp.multiply(this.blastAmount * 8); return false;
this.applyImpulse(impulse); this.blastUseTick = timeState.ticks;
if (this.controllable) var amount = this.blastTicks / (30000 >> 5);
AudioManager.playSound(ResourceLoader.getResource('data/sound/use_blast.wav', ResourceLoader.getAudio, this.soundResources)); this.blastPerc = amount;
this.blastWave.doSequenceOnceBeginTime = this.level.timeState.timeSinceLoad; var impulse = this.currentUp.multiply(amount * 8);
this.blastUseTime = this.level.timeState.currentAttemptTime; this.applyImpulse(impulse);
this.blastAmount = 0; if (this.controllable)
return true; 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) { public function applyImpulse(impulse:Vector, contactImpulse:Bool = false) {
@ -2156,6 +2219,8 @@ class Marble extends GameObject {
this.helicopterEnableTime = Math.NEGATIVE_INFINITY; this.helicopterEnableTime = Math.NEGATIVE_INFINITY;
this.megaMarbleEnableTime = Math.NEGATIVE_INFINITY; this.megaMarbleEnableTime = Math.NEGATIVE_INFINITY;
this.blastUseTime = Math.NEGATIVE_INFINITY; this.blastUseTime = Math.NEGATIVE_INFINITY;
this.blastUseTick = 0;
this.blastTicks = 0;
this.lastContactNormal = new Vector(0, 0, 1); this.lastContactNormal = new Vector(0, 0, 1);
this.contactEntities = []; this.contactEntities = [];
this.cloak = false; this.cloak = false;

View file

@ -119,6 +119,7 @@ class MarbleWorld extends Scheduler {
public var interiors:Array<InteriorObject> = []; public var interiors:Array<InteriorObject> = [];
public var pathedInteriors:Array<PathedInterior> = []; public var pathedInteriors:Array<PathedInterior> = [];
public var marbles:Array<Marble> = [];
public var dtsObjects:Array<DtsObject> = []; public var dtsObjects:Array<DtsObject> = [];
public var powerUps:Array<PowerUp> = []; public var powerUps:Array<PowerUp> = [];
public var forceObjects:Array<ForceObject> = []; public var forceObjects:Array<ForceObject> = [];
@ -982,6 +983,7 @@ class MarbleWorld extends Scheduler {
public function addMarble(marble:Marble, client:GameConnection, onFinish:Void->Void) { public function addMarble(marble:Marble, client:GameConnection, onFinish:Void->Void) {
marble.level = cast this; marble.level = cast this;
this.marbles.push(marble);
if (marble.controllable) { if (marble.controllable) {
marble.init(cast this, client, () -> { marble.init(cast this, client, () -> {
this.scene.addChild(marble.camera); this.scene.addChild(marble.camera);
@ -1234,7 +1236,7 @@ class MarbleWorld extends Scheduler {
|| Gamepad.isDown(Settings.gamepadSettings.blast) || Gamepad.isDown(Settings.gamepadSettings.blast)
&& !this.isWatching && !this.isWatching
&& this.game == "ultra") { && this.game == "ultra") {
this.marble.useBlast(); this.marble.useBlast(timeState);
} }
this.updateGameState(); this.updateGameState();
@ -1369,7 +1371,7 @@ class MarbleWorld extends Scheduler {
this.tickSchedule(timeState.currentAttemptTime); this.tickSchedule(timeState.currentAttemptTime);
if (this.isWatching && this.replay.currentPlaybackFrame.marbleStateFlags.has(UsedBlast)) if (this.isWatching && this.replay.currentPlaybackFrame.marbleStateFlags.has(UsedBlast))
this.marble.useBlast(); this.marble.useBlast(timeState);
// Replay gravity // Replay gravity
if (this.isWatching) { if (this.isWatching) {
@ -1441,6 +1443,7 @@ class MarbleWorld extends Scheduler {
} }
timeState.ticks++; timeState.ticks++;
} }
timeState.subframe = tickAccumulator / 0.032;
marble.updateClient(timeState, this.pathedInteriors); marble.updateClient(timeState, this.pathedInteriors);
for (client => marble in clientMarbles) { for (client => marble in clientMarbles) {
marble.updateClient(timeState, this.pathedInteriors); marble.updateClient(timeState, this.pathedInteriors);
@ -1600,16 +1603,27 @@ class MarbleWorld extends Scheduler {
} }
public function updateBlast(marble:Marble, timestate:TimeState) { public function updateBlast(marble:Marble, timestate:TimeState) {
if (marble.blastAmount < 1) { if (this.isMultiplayer) {
marble.blastAmount = Util.clamp(marble.blastAmount + (timeState.dt / 30), 0, 1); if (marble == this.marble) {
if (marble == this.marble) if (marble.blastTicks < (36000 >> 5)) {
this.renderBlastAmount = marble.blastAmount; 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 { } 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) 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() { function updateTexts() {
@ -2234,7 +2248,7 @@ class MarbleWorld extends Scheduler {
pathedInteriors.dispose(); pathedInteriors.dispose();
} }
pathedInteriors = null; pathedInteriors = null;
for (client => marble in clientMarbles) { for (marble in marbles) {
marble.dispose(); marble.dispose();
} }
clientMarbles = null; clientMarbles = null;

View file

@ -7,6 +7,7 @@ class TimeState {
var gameplayClock:Float; var gameplayClock:Float;
var dt:Float; var dt:Float;
var ticks:Int; // How many 32ms ticks have happened var ticks:Int; // How many 32ms ticks have happened
var subframe:Float;
public function new() {} public function new() {}
@ -17,6 +18,7 @@ class TimeState {
n.gameplayClock = this.gameplayClock; n.gameplayClock = this.gameplayClock;
n.dt = this.dt; n.dt = this.dt;
n.ticks = ticks; n.ticks = ticks;
n.subframe = subframe;
return n; return n;
} }
} }

View file

@ -12,16 +12,22 @@ class MarblePrediction {
var position:Vector; var position:Vector;
var velocity:Vector; var velocity:Vector;
var omega:Vector; var omega:Vector;
var isControl:Bool;
var blastAmount:Int;
public function new(marble:Marble, tick:Int) { public function new(marble:Marble, tick:Int) {
this.tick = tick; this.tick = tick;
position = @:privateAccess marble.newPos.clone(); position = @:privateAccess marble.newPos.clone();
velocity = @:privateAccess marble.velocity.clone(); velocity = @:privateAccess marble.velocity.clone();
omega = @:privateAccess marble.omega.clone(); omega = @:privateAccess marble.omega.clone();
blastAmount = @:privateAccess marble.blastTicks;
isControl = @:privateAccess marble.controllable;
} }
public inline function getError(p:MarbleUpdatePacket) { public inline function getError(p:MarbleUpdatePacket) {
var subs = position.sub(p.position).lengthSq() + velocity.sub(p.velocity).lengthSq() + omega.sub(p.omega).lengthSq(); 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; return subs;
} }
} }

12
src/net/Move.hx Normal file
View 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() {}
}

View file

@ -8,7 +8,7 @@ import src.Console;
import net.ClientConnection; import net.ClientConnection;
import net.Net.NetPacketType; import net.Net.NetPacketType;
import src.MarbleWorld; import src.MarbleWorld;
import src.Marble.Move; import net.Move;
import h3d.Vector; import h3d.Vector;
import src.Gamepad; import src.Gamepad;
import src.Settings; import src.Settings;

View file

@ -38,6 +38,8 @@ class MarbleUpdatePacket implements NetPacket {
var position:Vector; var position:Vector;
var velocity:Vector; var velocity:Vector;
var omega:Vector; var omega:Vector;
var blastAmount:Int;
var blastTick:Int;
var moveQueueSize:Int; var moveQueueSize:Int;
public function new() {} public function new() {}
@ -56,6 +58,8 @@ class MarbleUpdatePacket implements NetPacket {
b.writeFloat(omega.x); b.writeFloat(omega.x);
b.writeFloat(omega.y); b.writeFloat(omega.y);
b.writeFloat(omega.z); b.writeFloat(omega.z);
b.writeUInt16(blastAmount);
b.writeUInt16(blastTick);
} }
public inline function deserialize(b:haxe.io.BytesInput) { 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()); position = new Vector(b.readFloat(), b.readFloat(), b.readFloat());
velocity = 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()); omega = new Vector(b.readFloat(), b.readFloat(), b.readFloat());
blastAmount = b.readUInt16();
blastTick = b.readUInt16();
} }
} }

View file

@ -2,7 +2,7 @@ package rewind;
import src.MarbleWorld; import src.MarbleWorld;
import h3d.Vector; import h3d.Vector;
import src.Marble.Move; import net.Move;
@:publicFields @:publicFields
class InputRecorderFrame { class InputRecorderFrame {

View file

@ -34,6 +34,7 @@ class Blast extends PowerUp {
public function use(marble:Marble, timeState:TimeState) { public function use(marble:Marble, timeState:TimeState) {
marble.blastAmount = 1.2; marble.blastAmount = 1.2;
marble.blastTicks = 36000 >> 5;
} }
override function getPreloadMaterials(dts:dts.DtsFile) { override function getPreloadMaterials(dts:dts.DtsFile) {