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 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);

View file

@ -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;

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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
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.Net.NetPacketType;
import src.MarbleWorld;
import src.Marble.Move;
import net.Move;
import h3d.Vector;
import src.Gamepad;
import src.Settings;

View file

@ -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();
}
}

View file

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

View file

@ -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) {