Finish ragdoll rewrite, fix some linting error...
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { OnInit, OnStart, Service } from "@flamework/core";
|
import { OnStart, Service } from "@flamework/core";
|
||||||
import { Players, TextChatService } from "@rbxts/services";
|
import { Players, TextChatService } from "@rbxts/services";
|
||||||
import { makeRagdoll, stopRagdoll, takeNetworkOwner } from "shared/ragdoll";
|
import { RagdollHandler, takeNetworkOwner } from "shared/ragdoll";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup Chat Command
|
* Setup Chat Command
|
||||||
@@ -13,7 +13,8 @@ class CommandsService implements OnStart {
|
|||||||
ragdollCommand.PrimaryAlias = "/ragdoll";
|
ragdollCommand.PrimaryAlias = "/ragdoll";
|
||||||
ragdollCommand.Triggered.Connect((TextSource) => {
|
ragdollCommand.Triggered.Connect((TextSource) => {
|
||||||
const player = Players.GetPlayerByUserId(TextSource.UserId);
|
const player = Players.GetPlayerByUserId(TextSource.UserId);
|
||||||
makeRagdoll(player!.Character!);
|
const handler = RagdollHandler.getHandlerByCharacter(player!.Character!, true);
|
||||||
|
handler.ragdoll();
|
||||||
});
|
});
|
||||||
|
|
||||||
const unragdollCommand = new TextChatCommand();
|
const unragdollCommand = new TextChatCommand();
|
||||||
@@ -21,7 +22,8 @@ class CommandsService implements OnStart {
|
|||||||
unragdollCommand.PrimaryAlias = "/unragdoll";
|
unragdollCommand.PrimaryAlias = "/unragdoll";
|
||||||
unragdollCommand.Triggered.Connect((TextSource) => {
|
unragdollCommand.Triggered.Connect((TextSource) => {
|
||||||
const player = Players.GetPlayerByUserId(TextSource.UserId);
|
const player = Players.GetPlayerByUserId(TextSource.UserId);
|
||||||
stopRagdoll(player!.Character!);
|
const handler = RagdollHandler.getHandlerByCharacter(player!.Character!, true);
|
||||||
|
handler.stopRagdoll();
|
||||||
});
|
});
|
||||||
|
|
||||||
const takeownerCommand = new TextChatCommand();
|
const takeownerCommand = new TextChatCommand();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Players } from "@rbxts/services";
|
import { Players } from "@rbxts/services";
|
||||||
import { GameplayServerEvents } from "./networking";
|
import { GameplayServerEvents } from "./networking";
|
||||||
import { OnStart, Service } from "@flamework/core";
|
import { OnStart, Service } from "@flamework/core";
|
||||||
import { getRagdollEvent, makeRagdoll, prepareRagdoll, stopRagdoll, waitMotionLess } from "shared/ragdoll";
|
import { RagdollHandler } from "shared/ragdoll";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service related to Gameplay.
|
* Service related to Gameplay.
|
||||||
@@ -23,11 +23,11 @@ class GameplayService implements OnStart {
|
|||||||
let running_connection: RBXScriptConnection;
|
let running_connection: RBXScriptConnection;
|
||||||
|
|
||||||
player.CharacterAdded.Connect((character) => {
|
player.CharacterAdded.Connect((character) => {
|
||||||
prepareRagdoll(character);
|
const ragdollhandler = new RagdollHandler(character);
|
||||||
getRagdollEvent(character).Connect(() => {
|
ragdollhandler.getRagdollFallingEvent().Connect(() => {
|
||||||
makeRagdoll(character);
|
ragdollhandler.ragdoll();
|
||||||
waitMotionLess(character, 0.1).Wait();
|
ragdollhandler.waitMotionLess().Wait();
|
||||||
stopRagdoll(character);
|
ragdollhandler.stopRagdoll();
|
||||||
});
|
});
|
||||||
|
|
||||||
const humanoid = character.FindFirstChildWhichIsA("Humanoid");
|
const humanoid = character.FindFirstChildWhichIsA("Humanoid");
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
class AbilityBuilder {
|
// TODO
|
||||||
constructor() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PasiveBuilder {
|
// class AbilityBuilder {
|
||||||
constructor() {}
|
// constructor() {}
|
||||||
}
|
// }
|
||||||
|
|
||||||
class CharacterBuilder {
|
// class PasiveBuilder {
|
||||||
constructor() {}
|
// constructor() {}
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
// class CharacterBuilder {
|
||||||
|
// constructor() {}
|
||||||
|
// }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Networking } from "@flamework/networking";
|
import { Networking } from "@flamework/networking";
|
||||||
|
|
||||||
const { createEvent, createFunction } = Networking;
|
const { createEvent } = Networking;
|
||||||
|
|
||||||
interface GameplayClient {
|
interface GameplayClient {
|
||||||
sprint(enabled: boolean): void;
|
sprint(enabled: boolean): void;
|
||||||
|
|||||||
@@ -1,50 +1,6 @@
|
|||||||
import { RunService } from "@rbxts/services";
|
import { RunService } from "@rbxts/services";
|
||||||
import Signal from "@rbxts/signal";
|
import Signal from "@rbxts/signal";
|
||||||
|
|
||||||
class RagdollHandler {
|
|
||||||
private character: Model;
|
|
||||||
private humanoid: Humanoid;
|
|
||||||
constructor(character: Model) {
|
|
||||||
this.character = character;
|
|
||||||
this.humanoid = character.FindFirstAncestorOfClass("Humanoid")!;
|
|
||||||
}
|
|
||||||
|
|
||||||
prepareRagdoll() {
|
|
||||||
const children = this.character.GetDescendants();
|
|
||||||
children.forEach((motor) => {
|
|
||||||
if (motor.IsA("Motor6D")) {
|
|
||||||
const ballsocketconstraint = new BallSocketConstraint(),
|
|
||||||
attachment0 = new Attachment(),
|
|
||||||
attachment1 = new Attachment();
|
|
||||||
|
|
||||||
attachment0.CFrame = motor.C0;
|
|
||||||
attachment0.Parent = motor.Part0;
|
|
||||||
attachment0.AddTag("Ragdoll");
|
|
||||||
attachment0.Name = motor.Name;
|
|
||||||
|
|
||||||
attachment1.CFrame = motor.C1;
|
|
||||||
attachment1.Parent = motor.Part1;
|
|
||||||
attachment1.AddTag("Ragdoll");
|
|
||||||
attachment1.Name = motor.Name;
|
|
||||||
|
|
||||||
ballsocketconstraint.Attachment0 = attachment0;
|
|
||||||
ballsocketconstraint.Attachment1 = attachment1;
|
|
||||||
ballsocketconstraint.Parent = motor.Parent;
|
|
||||||
ballsocketconstraint.AddTag("Ragdoll");
|
|
||||||
ballsocketconstraint.Enabled = false;
|
|
||||||
|
|
||||||
if (motor.Name === "Left Hip") {
|
|
||||||
attachment0.CFrame = attachment0.CFrame.add(new Vector3(0.5, 0, 0));
|
|
||||||
attachment1.CFrame = attachment1.CFrame.add(new Vector3(0.5, 0, 0));
|
|
||||||
} else if (motor.Name === "Right Hip") {
|
|
||||||
attachment0.CFrame = attachment0.CFrame.sub(new Vector3(0.5, 0, 0));
|
|
||||||
attachment1.CFrame = attachment1.CFrame.sub(new Vector3(0.5, 0, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes the Network Ownership of a player's character.
|
* Takes the Network Ownership of a player's character.
|
||||||
* @param character The character of a player.
|
* @param character The character of a player.
|
||||||
@@ -58,7 +14,6 @@ export function takeNetworkOwner(character: Model) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Releases the Network Ownership of a player's character.
|
* Releases the Network Ownership of a player's character.
|
||||||
* @param character The character of a player
|
* @param character The character of a player
|
||||||
@@ -73,116 +28,150 @@ export function releaseNetworkOwnership(character: Model) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function prepareRagdoll(character: Model) {
|
|
||||||
const children = character.GetDescendants();
|
|
||||||
const humanoid = character.FindFirstChildOfClass("Humanoid")!;
|
|
||||||
humanoid.RequiresNeck = false;
|
|
||||||
children.forEach((motor) => {
|
|
||||||
if (motor.IsA("Motor6D")) {
|
|
||||||
const ballsocketconstraint = new BallSocketConstraint(),
|
|
||||||
attachment0 = new Attachment(),
|
|
||||||
attachment1 = new Attachment();
|
|
||||||
|
|
||||||
attachment0.CFrame = motor.C0;
|
|
||||||
attachment0.Parent = motor.Part0;
|
|
||||||
attachment0.AddTag("Ragdoll");
|
|
||||||
attachment0.Name = motor.Name;
|
|
||||||
|
|
||||||
attachment1.CFrame = motor.C1;
|
|
||||||
attachment1.Parent = motor.Part1;
|
|
||||||
attachment1.AddTag("Ragdoll");
|
|
||||||
attachment1.Name = motor.Name;
|
|
||||||
|
|
||||||
ballsocketconstraint.Attachment0 = attachment0;
|
|
||||||
ballsocketconstraint.Attachment1 = attachment1;
|
|
||||||
ballsocketconstraint.Parent = motor.Parent;
|
|
||||||
ballsocketconstraint.AddTag("Ragdoll");
|
|
||||||
ballsocketconstraint.Enabled = false;
|
|
||||||
|
|
||||||
if (motor.Name === "Left Hip") {
|
|
||||||
attachment0.CFrame = attachment0.CFrame.add(new Vector3(0.5, 0, 0));
|
|
||||||
attachment1.CFrame = attachment1.CFrame.add(new Vector3(0.5, 0, 0));
|
|
||||||
} else if (motor.Name === "Right Hip") {
|
|
||||||
attachment0.CFrame = attachment0.CFrame.sub(new Vector3(0.5, 0, 0));
|
|
||||||
attachment1.CFrame = attachment1.CFrame.sub(new Vector3(0.5, 0, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes the player's character Ragdoll by creating attachments for each part of the R6 Model.
|
* A class which help to ragdoll the player.
|
||||||
* @param character The character of a player.
|
|
||||||
*/
|
*/
|
||||||
export function makeRagdoll(character: Model) {
|
export class RagdollHandler {
|
||||||
takeNetworkOwner(character);
|
private character: Model;
|
||||||
const humanoid = character.FindFirstChildOfClass("Humanoid")!;
|
private humanoid: Humanoid;
|
||||||
humanoid.ChangeState(Enum.HumanoidStateType.Physics);
|
private ragdollattachment: Attachment[] = [];
|
||||||
character.GetDescendants().forEach((des) => {
|
private ragdollconstraint: BallSocketConstraint[] = [];
|
||||||
if (des.HasTag("Ragdoll") && des.IsA("BallSocketConstraint")) {
|
private motors: Motor6D[] = [];
|
||||||
des.Enabled = true;
|
private root: Part;
|
||||||
}
|
private static ragdollHandlers: Map<Model, RagdollHandler> = new Map();
|
||||||
if (des.IsA("Motor6D")) {
|
|
||||||
des.Enabled = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
takeNetworkOwner(character);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function stopRagdoll(character: Model) {
|
private getRagdollElements() {
|
||||||
releaseNetworkOwnership(character);
|
return [...this.ragdollattachment, ...this.ragdollconstraint];
|
||||||
character.GetDescendants().forEach((des) => {
|
}
|
||||||
if (des.HasTag("Ragdoll") && des.IsA("BallSocketConstraint")) {
|
|
||||||
des.Enabled = false;
|
|
||||||
}
|
|
||||||
if (des.IsA("Motor6D")) {
|
|
||||||
des.Enabled = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
constructor(character: Model) {
|
||||||
* This function return a signal which fire when the player stop moving.
|
this.character = character;
|
||||||
* @param character The character of the player
|
const humanoid = character.FindFirstAncestorOfClass("Humanoid");
|
||||||
* @param threshold The maximum distance (in studs) the player must travel in 0.3 seconds for the signal to be fired.
|
const root = character.FindFirstChild("HumanoidRootPart");
|
||||||
* @returns The signal.
|
if (!humanoid || !root?.IsA("Part")) throw '"character" isn\'t a player Character. Failed to handle ragdoll.';
|
||||||
*/
|
this.humanoid = humanoid;
|
||||||
export function waitMotionLess(character: Model, threshold: number) {
|
this.root = root;
|
||||||
const signal = new Signal();
|
this.prepareRagdoll();
|
||||||
let delta: number = -1;
|
RagdollHandler.ragdollHandlers.set(character, this);
|
||||||
const root = character.FindFirstChild("HumanoidRootPart");
|
}
|
||||||
if (!root?.IsA("Part")) throw "Bro are you an idiot ?";
|
|
||||||
task.spawn(() => {
|
|
||||||
while (0 > delta || delta > threshold) {
|
|
||||||
const lastPos = root.Position;
|
|
||||||
task.wait(0.3);
|
|
||||||
delta = root.Position.sub(lastPos).Magnitude;
|
|
||||||
}
|
|
||||||
signal.Fire();
|
|
||||||
});
|
|
||||||
return signal;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getRagdollEvent(character: Model) {
|
private prepareRagdoll() {
|
||||||
const humanoid = character.FindFirstChildOfClass("Humanoid");
|
const children = this.character.GetDescendants();
|
||||||
const root = character.WaitForChild("HumanoidRootPart") as Part;
|
children.forEach((motor) => {
|
||||||
if (!humanoid) throw "nya UwU eat my paw.";
|
if (motor.IsA("Motor6D")) {
|
||||||
const event = new Signal();
|
this.motors.push(motor);
|
||||||
let fired = false;
|
const ballsocketconstraint = new BallSocketConstraint(),
|
||||||
let beatEvent: RBXScriptConnection;
|
attachment0 = new Attachment(),
|
||||||
humanoid.FreeFalling.Connect((active) => {
|
attachment1 = new Attachment();
|
||||||
if (active) {
|
|
||||||
beatEvent = RunService.Heartbeat.Connect(() => {
|
attachment0.CFrame = motor.C0;
|
||||||
if (root.AssemblyLinearVelocity.Y < -38 && !fired) {
|
attachment0.Parent = motor.Part0;
|
||||||
event.Fire();
|
attachment0.AddTag("Ragdoll");
|
||||||
fired = true;
|
attachment0.Name = motor.Name;
|
||||||
|
this.ragdollattachment.push(attachment0);
|
||||||
|
|
||||||
|
attachment1.CFrame = motor.C1;
|
||||||
|
attachment1.Parent = motor.Part1;
|
||||||
|
attachment1.AddTag("Ragdoll");
|
||||||
|
attachment1.Name = motor.Name;
|
||||||
|
this.ragdollattachment.push(attachment1);
|
||||||
|
|
||||||
|
ballsocketconstraint.Attachment0 = attachment0;
|
||||||
|
ballsocketconstraint.Attachment1 = attachment1;
|
||||||
|
ballsocketconstraint.Parent = motor.Parent;
|
||||||
|
ballsocketconstraint.AddTag("Ragdoll");
|
||||||
|
ballsocketconstraint.Enabled = false;
|
||||||
|
this.ragdollconstraint.push(ballsocketconstraint);
|
||||||
|
|
||||||
|
if (motor.Name === "Left Hip") {
|
||||||
|
attachment0.CFrame = attachment0.CFrame.add(new Vector3(0.5, 0, 0));
|
||||||
|
attachment1.CFrame = attachment1.CFrame.add(new Vector3(0.5, 0, 0));
|
||||||
|
} else if (motor.Name === "Right Hip") {
|
||||||
|
attachment0.CFrame = attachment0.CFrame.sub(new Vector3(0.5, 0, 0));
|
||||||
|
attachment1.CFrame = attachment1.CFrame.sub(new Vector3(0.5, 0, 0));
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
} else {
|
});
|
||||||
beatEvent.Disconnect();
|
}
|
||||||
fired = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return event;
|
/**
|
||||||
|
* Ragdoll the charactere linked to this class.
|
||||||
|
*/
|
||||||
|
ragdoll() {
|
||||||
|
takeNetworkOwner(this.character);
|
||||||
|
this.humanoid.ChangeState(Enum.HumanoidStateType.Physics);
|
||||||
|
this.motors.forEach((motor) => (motor.Enabled = false));
|
||||||
|
this.ragdollconstraint.forEach((constraint) => (constraint.Enabled = true));
|
||||||
|
takeNetworkOwner(this.character);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop the Ragdoll.
|
||||||
|
*/
|
||||||
|
stopRagdoll() {
|
||||||
|
this.humanoid.ChangeState(Enum.HumanoidStateType.Running);
|
||||||
|
this.motors.forEach((motor) => (motor.Enabled = true));
|
||||||
|
this.ragdollconstraint.forEach((constraint) => (constraint.Enabled = false));
|
||||||
|
releaseNetworkOwnership(this.character);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function return a signal which fire when the player stop moving.
|
||||||
|
* @param threshold The maximum distance (in studs) the player must travel in 0.3 seconds for the signal to be fired.
|
||||||
|
* @returns The signal.
|
||||||
|
*/
|
||||||
|
waitMotionLess(threshold: number = 0.1) {
|
||||||
|
const signal = new Signal();
|
||||||
|
let delta: number = -1;
|
||||||
|
task.spawn(() => {
|
||||||
|
while (0 > delta || delta > threshold) {
|
||||||
|
const lastPos = this.root.Position;
|
||||||
|
task.wait(0.3);
|
||||||
|
delta = this.root.Position.sub(lastPos).Magnitude;
|
||||||
|
}
|
||||||
|
signal.Fire();
|
||||||
|
});
|
||||||
|
return signal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an Event which is fired when the player fall at an defined speed.
|
||||||
|
* @param maximumSpeed The limit speed before the event fired.
|
||||||
|
* @returns A signal which is fired when the player fall at the defined speed.
|
||||||
|
*/
|
||||||
|
getRagdollFallingEvent(maximumSpeed: number = 38) {
|
||||||
|
const event = new Signal();
|
||||||
|
let fired = false;
|
||||||
|
let beatEvent: RBXScriptConnection;
|
||||||
|
this.humanoid.FreeFalling.Connect((active) => {
|
||||||
|
if (active) {
|
||||||
|
beatEvent = RunService.Heartbeat.Connect(() => {
|
||||||
|
if (this.root.AssemblyLinearVelocity.Y < -maximumSpeed && !fired) {
|
||||||
|
event.Fire();
|
||||||
|
fired = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
beatEvent.Disconnect();
|
||||||
|
fired = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy all parts related to ragdoll.
|
||||||
|
*/
|
||||||
|
destroy() {
|
||||||
|
this.getRagdollElements().forEach((element) => element.Destroy());
|
||||||
|
}
|
||||||
|
|
||||||
|
static getHandlerByCharacter(character: Model, createifmissing?: false): RagdollHandler | undefined;
|
||||||
|
static getHandlerByCharacter(character: Model, createifmissing: true): RagdollHandler;
|
||||||
|
static getHandlerByCharacter(character: Model, createifmissing: boolean = false) {
|
||||||
|
return createifmissing
|
||||||
|
? (this.ragdollHandlers.get(character) ?? new this(character))
|
||||||
|
: this.ragdollHandlers.get(character);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user