Weird jittering when moving model over terrain

Why is the model moving like that? I expected it to always snap to the ground. It's like it's ray hit something in mid air?
No description
No description
5 Replies
PoppingPopper
PoppingPopperOP5mo ago
Full code if needed
import { Controller, OnRender } from "@flamework/core";
import { Players, Workspace } from "@rbxts/services";
import { t } from "@rbxts/t";
import { MAX_BUILD_RANGE } from "shared/constants/player-constants";
import { transparentify } from "shared/module";

interface PreviewModel extends Model {
RootPart: BasePart;
}

const localPlayer = Players.LocalPlayer;
const mouse = localPlayer.GetMouse();

@Controller({})
export class ShadowBuildPreview implements OnRender {
private previewModel: PreviewModel | undefined;

onRender() {
const character = localPlayer.Character;
if (!character) return;

const [center] = character.GetBoundingBox();

if (!this.previewModel) return;
const mousePosition = mouse.Hit.Position;
const rootPart = this.previewModel.RootPart;
const sizeOffset = new Vector3(0, rootPart.Size.Y / 2, 0);
let targetPosition = mousePosition.add(sizeOffset);

const distance = targetPosition.sub(center.Position).Magnitude;
if (distance > MAX_BUILD_RANGE) {
const direction = targetPosition.sub(center.Position).Unit;
targetPosition = center.Position.add(direction.mul(50));
}

const ray = new Ray(targetPosition, new Vector3(0, -1000, 0));
const raycastResult = Workspace.Raycast(ray.Origin, ray.Direction);

if (raycastResult) {
targetPosition = raycastResult.Position.add(sizeOffset);
}

this.previewModel.PivotTo(new CFrame(targetPosition));
}

public setPreviewModel(model: Model) {
const previewModel = model.Clone();
if (!isPreviewModel(previewModel))
return error(
`<ShadowBuildPreview.setPreviewModel()> Invalid preview model, RootPart could not be validated`,
);

this.previewModel = previewModel.Clone();
transparentify(this.previewModel, {
transparency: 0.6,
canCollide: false,
blacklist: [this.previewModel.RootPart],
});
this.previewModel.Parent = Workspace;
mouse.TargetFilter = this.previewModel;
}

public removePreviewModel() {
if (!this.previewModel) return;
this.previewModel.Destroy();
this.previewModel = undefined;
}

public getTargetCFrame() {
return this.previewModel?.PrimaryPart?.CFrame;
}
}

const IPreviewModel = t.interface({
RootPart: t.instanceIsA("BasePart"),
});

function isPreviewModel(value: Instance): value is PreviewModel {
const record: Record<string, Instance> = {};
for (const child of value.GetChildren()) {
record[child.Name] = child;
}
return IPreviewModel(record);
}
import { Controller, OnRender } from "@flamework/core";
import { Players, Workspace } from "@rbxts/services";
import { t } from "@rbxts/t";
import { MAX_BUILD_RANGE } from "shared/constants/player-constants";
import { transparentify } from "shared/module";

interface PreviewModel extends Model {
RootPart: BasePart;
}

const localPlayer = Players.LocalPlayer;
const mouse = localPlayer.GetMouse();

@Controller({})
export class ShadowBuildPreview implements OnRender {
private previewModel: PreviewModel | undefined;

onRender() {
const character = localPlayer.Character;
if (!character) return;

const [center] = character.GetBoundingBox();

if (!this.previewModel) return;
const mousePosition = mouse.Hit.Position;
const rootPart = this.previewModel.RootPart;
const sizeOffset = new Vector3(0, rootPart.Size.Y / 2, 0);
let targetPosition = mousePosition.add(sizeOffset);

const distance = targetPosition.sub(center.Position).Magnitude;
if (distance > MAX_BUILD_RANGE) {
const direction = targetPosition.sub(center.Position).Unit;
targetPosition = center.Position.add(direction.mul(50));
}

const ray = new Ray(targetPosition, new Vector3(0, -1000, 0));
const raycastResult = Workspace.Raycast(ray.Origin, ray.Direction);

if (raycastResult) {
targetPosition = raycastResult.Position.add(sizeOffset);
}

this.previewModel.PivotTo(new CFrame(targetPosition));
}

public setPreviewModel(model: Model) {
const previewModel = model.Clone();
if (!isPreviewModel(previewModel))
return error(
`<ShadowBuildPreview.setPreviewModel()> Invalid preview model, RootPart could not be validated`,
);

this.previewModel = previewModel.Clone();
transparentify(this.previewModel, {
transparency: 0.6,
canCollide: false,
blacklist: [this.previewModel.RootPart],
});
this.previewModel.Parent = Workspace;
mouse.TargetFilter = this.previewModel;
}

public removePreviewModel() {
if (!this.previewModel) return;
this.previewModel.Destroy();
this.previewModel = undefined;
}

public getTargetCFrame() {
return this.previewModel?.PrimaryPart?.CFrame;
}
}

const IPreviewModel = t.interface({
RootPart: t.instanceIsA("BasePart"),
});

function isPreviewModel(value: Instance): value is PreviewModel {
const record: Record<string, Instance> = {};
for (const child of value.GetChildren()) {
record[child.Name] = child;
}
return IPreviewModel(record);
}
Tester
Tester5mo ago
is model collision disabled? and can touch and can query? and for @rbxts/t i would suggest using Flamework since it can just generate it from the type 🤷‍♂️
Tester
Tester5mo ago
No description
Tester
Tester5mo ago
compiles to:
No description
PoppingPopper
PoppingPopperOP5mo ago
Yes, not the others though. I'll try turning them all off. Amazing! I will implement this. Ohhhhhh I see, so it appears I didn't add filtering to the ray. I noticed that it worked after I set CanQuery to false like you said. After setting some RaycastParams and filtering out itself it worked! Thank you so much sir!

Did you find this page helpful?