Click Detectors not being created in roblox typescript

  1. What do you want to achieve? In this rng adventure type of game, i am working on making the players inventory, i use claude ai to help me code fast and also learn things because i am a beginner, and i also code with typescript. anyways, i want to make it so you can scroll through swords in your inventory using the arrow buttons, so i tried asking claude to build some code to put click detectors inside the left arrow and right arrow when you step on the pressure plate, and delete them when you step off.

  2. What is the issue? the click detectors aren’t appearing at all! i checked what he made, and it seems correct.
    Roblox Studio - /Users/air/Documents/Dev/Roblox-TS-Template/Roblox-TS-Template.rbxl - Roblox Studio - 3 September 2024 | Loom

  3. What solutions have you tried so far? i couldn’t find anything on the developer hub, i tried checking it myself, i tried talking to claude more on fixing it, and seeing youtube videos, none of them worked.

im not sure which parts specifically to show, so i will show you the whole file i use for the pressure plate code.

import { Workspace, Players } from "@rbxts/services";
import { getPlayerInventory, SwordItem } from "./SwordsInventory";

const objectsFolder = Workspace.FindFirstChild("Objects") as Folder;
if (!objectsFolder) {
    throw `Objects folder does not exist in the Workspace!`;
}

const squarePlate = objectsFolder.FindFirstChild("Plate1") as Part;
if (!squarePlate) {
    throw `Plate1 does not exist in the Objects folder!`;
}

const swordsModel = objectsFolder.FindFirstChild("SwordsP") as Model;
const unclaimedModel = objectsFolder.FindFirstChild("Unclaimed") as Model;
const swordMesh = objectsFolder.FindFirstChild("SwordMesh") as Part;

if (!swordsModel || !unclaimedModel || !swordMesh) {
    throw `SwordsP, Unclaimed model, or SwordMesh not found in the Objects folder!`;
}

const signPart = unclaimedModel.FindFirstChild("Sign") as Part;
const surfaceGui = signPart?.FindFirstChild("SurfaceGui") as SurfaceGui;
const signLabel = surfaceGui?.FindFirstChild("SIGN") as TextLabel;

const playersOnPlate = new Set<Player>();
const playerInventoryOffsets = new Map<Player, number>();

function setModelTransparency(model: Model, transparency: number, decalTransparency: number) {
    model.GetDescendants().forEach((descendant) => {
        if (descendant.IsA("BasePart")) {
            if (descendant.Name !== "right arrow" && descendant.Name !== "left arrow") {
                descendant.Transparency = transparency;
            }
            const decal = descendant.FindFirstChild("Decal") as Decal;
            if (decal) {
                decal.Transparency = decalTransparency;
            }
        }
    });
}

function createCapsuleCollider(character: Model) {
    const hrp = character.WaitForChild("HumanoidRootPart") as Part;

    const capsule = new Instance("Part");
    capsule.Name = "CapsuleCollider";
    capsule.Shape = Enum.PartType.Cylinder;
    capsule.Size = new Vector3(6, 15, 7);
    capsule.Anchored = false;
    capsule.CanCollide = true;
    capsule.CFrame = hrp.CFrame;
    capsule.Transparency = 1;
    capsule.CanCollide = false;

    capsule.Parent = character;

    const weld = new Instance("WeldConstraint");
    weld.Part0 = hrp;
    weld.Part1 = capsule;
    weld.Parent = hrp;
}

Players.PlayerAdded.Connect((player) => {
    player.CharacterAdded.Connect((character) => {
        createCapsuleCollider(character);
    });
});

function createColoredSwordMesh(sword: SwordItem): Part {
    print(`Creating colored sword mesh for ${sword.name}`);
    const newSwordPart = swordMesh.Clone();
    newSwordPart.Name = sword.name;
    
    const mesh = newSwordPart.FindFirstChild("Mesh") as SpecialMesh;
    if (!mesh) {
        print(`Mesh not found in SwordMesh part for ${sword.name}!`);
        return newSwordPart;
    }
    
    let color: Vector3;
    switch (sword.id) {
        case "wooden_sword":
            color = new Vector3(0.627, 0.322, 0.176);
            break;
        case "iron_sword":
            color = new Vector3(0.8, 0.8, 0.8);
            break;
        case "steel_sword":
            color = new Vector3(0.6, 0.6, 0.6);
            break;
        case "golden_sword":
            color = new Vector3(1, 0.843, 0);
            break;
        case "plasma_sword":
            color = new Vector3(2, 1, 2);
            break;
        case "diamond_sword":
            color = new Vector3(0.114, 0.675, 0.839);
            break;
        case "obsidian_sword":
            color = new Vector3(0.18, 0.18, 0.31);
            break;
        default:
            color = new Vector3(1, 1, 1);
    }
    
    mesh.VertexColor = color;
    print(`Set VertexColor for ${sword.name} to ${color}`);
    
    return newSwordPart;
}

function displayPlayerSwords(player: Player, offset: number = 0) {
    print(`Displaying swords for ${player.Name} with offset ${offset}`);
    const inventory = getPlayerInventory(player);
    print(`Raw inventory data:`, inventory);
    print(`Inventory size: ${inventory.size()}`);
    print(`Player inventory: ${inventory.map(sword => `${sword.name} (${sword.id})`).join(", ")}`);
    const tiles = swordsModel.GetChildren().filter((child): child is Part => child.IsA("Part"));
    
    tiles.forEach(tile => {
        if (tile.Name !== "right arrow" && tile.Name !== "left arrow") {
            tile.GetChildren().forEach(child => {
                if (child.Name !== "Decal" && child.Name !== "ClickDetector") {
                    child.Destroy();
                }
            });
        }
    });
    
    for (let i = 0; i < 3; i++) {
        const inventoryIndex = i + offset;
        if (inventoryIndex < inventory.size()) {
            const sword = inventory[inventoryIndex];
            const tile = tiles[i];
            if (tile && tile.Name !== "right arrow" && tile.Name !== "left arrow") {
                print(`Processing sword ${inventoryIndex + 1}:`, sword);
                const swordPart = createColoredSwordMesh(sword);
                swordPart.Parent = tile;
                swordPart.CFrame = tile.CFrame.mul(new CFrame(0, 1, 0).mul(CFrame.Angles(0, math.pi/2, 0)));
                print(`Placed ${sword.name} (${sword.id}) on tile ${i + 1}`);
            }
        }
    }
}

function handleArrowClick(direction: "left" | "right") {
    print(`Arrow clicked: ${direction}`);
    if (playersOnPlate.size() > 0) {
        let player: Player | undefined;
        for (const p of playersOnPlate) {
            player = p;
            break;
        }
        if (player) {
            const inventory = getPlayerInventory(player);
            let offset = playerInventoryOffsets.get(player) ?? 0;
            
            print(`Current offset: ${offset}, Inventory size: ${inventory.size()}`);
            
            if (direction === "right" && offset + 3 < inventory.size()) {
                offset++;
                playerInventoryOffsets.set(player, offset);
                displayPlayerSwords(player, offset);
                print(`Moved right, new offset: ${offset}`);
            } else if (direction === "left" && offset > 0) {
                offset--;
                playerInventoryOffsets.set(player, offset);
                displayPlayerSwords(player, offset);
                print(`Moved left, new offset: ${offset}`);
            } else {
                print(`Cannot move ${direction}`);
            }
        } else {
            print("No player found on plate");
        }
    } else {
        print("No players on plate");
    }
}

function setClickDetectorsEnabled(enabled: boolean) {
    const rightArrow = swordsModel.FindFirstChild("right arrow") as Part;
    const leftArrow = swordsModel.FindFirstChild("left arrow") as Part;

    if (rightArrow && leftArrow) {
        [rightArrow, leftArrow].forEach(arrow => {
            const clickDetector = arrow.FindFirstChild("ClickDetector") as ClickDetector;
            if (clickDetector) {
                // Use MaxActivationDistance instead of Enabled
                clickDetector.MaxActivationDistance = enabled ? 80 : 0;
            }
        });
    }
}

squarePlate.Touched.Connect((otherPart) => {
    if (otherPart.Name === "CapsuleCollider") {
        const character = otherPart.Parent;
        if (character && character.FindFirstChild("Humanoid")) {
            const player = Players.GetPlayerFromCharacter(character);
            if (player && !playersOnPlate.has(player)) {
                playersOnPlate.add(player);
                playerInventoryOffsets.set(player, 0);
                print(`${player.Name} has entered the square plate`);
                squarePlate.Color = new Color3(0.941, 0.973, 1);
                setModelTransparency(swordsModel, 0, 0);
                setModelTransparency(unclaimedModel, 1, 1);
                signLabel.Text = "";
                displayPlayerSwords(player, 0);
                setClickDetectorsEnabled(true);
            }
        }
    }
});

squarePlate.TouchEnded.Connect((otherPart) => {
    if (otherPart.Name === "CapsuleCollider") {
        const character = otherPart.Parent;
        if (character && character.FindFirstChild("Humanoid")) {
            const player = Players.GetPlayerFromCharacter(character);
            if (player && playersOnPlate.has(player)) {
                playersOnPlate.delete(player);
                playerInventoryOffsets.delete(player);
                print(`${player.Name} has left the square plate`);
                squarePlate.Color = new Color3(0.333, 0.333, 0.333);
                if (playersOnPlate.size() === 0) {
                    setModelTransparency(swordsModel, 1, 1);
                    setModelTransparency(unclaimedModel, 0, 0);
                    signLabel.Text = "unclaimed";
                    swordsModel.GetChildren().forEach(child => {
                        if (child.IsA("Part") && child.Name !== "right arrow" && child.Name !== "left arrow") {
                            child.GetChildren().forEach(grandchild => {
                                if (grandchild.Name !== "Decal" && grandchild.Name !== "ClickDetector") {
                                    grandchild.Destroy();
                                }
                            });
                        }
                    });
                    print("Cleared all swords from display");
                    setClickDetectorsEnabled(false);
                }
            }
        }
    }
});

// Disable ClickDetectors at the start
setClickDetectorsEnabled(false);

// Set up ClickDetector events
const rightArrow = swordsModel.FindFirstChild("right arrow") as Part;
const leftArrow = swordsModel.FindFirstChild("left arrow") as Part;

if (rightArrow && leftArrow) {
    [rightArrow, leftArrow].forEach(arrow => {
        const clickDetector = arrow.FindFirstChild("ClickDetector") as ClickDetector;
        if (clickDetector) {
            clickDetector.MouseClick.Connect(() => {
                handleArrowClick(arrow === rightArrow ? "right" : "left");
            });
            clickDetector.MouseHoverEnter.Connect(() => {
                arrow.Transparency = 0.5;
            });
            clickDetector.MouseHoverLeave.Connect(() => {
                arrow.Transparency = 0;
            });
        }
    });
}

it seems as if every small part in my game is sooo complicated… :face_exhaling:

1 Like

Why not go to View > Studio Assistant to help with your scripting instead? It may not be perfect, but it usually gives you an idea of where to go.

Just put a ClickDetector in each of the Parts in the Explorer window, then make them Enabled true or false to turn them on or off.

1 Like

how did you use typeScript for roblox ?? roblox studio use luau only right?

1 Like

i used rojo, visual studio code, ts… well, you can see this tutorial i made. https://www.youtube.com/watch?v=kMU8mICfdM4
sorry it’s not in the best quality

1 Like

but i am coding in visual studio code, and rojo is converting typescript to lua. anyways, i will try the “enabled” property

i cannot see enabled property when looking in the workspace… i’ll try asking claude

Right click the Part. and add a ClickDetector to it.
Select the ClickDetector.
In the Properties window you can see the Enabled Property.

If you wonder about any of the Roblox instances go to Documentation - Roblox Creator Hub and use the Search tool. It can tell you a lot about the item, and sometimes gives you information about how to use it.

For instance: ClickDetector | Documentation - Roblox Creator Hub

Does this print when you touch the square plate?

yea it is, i dunno why nothing happens to the click detector… let me edit the post to have new code i tried


i added a ClickDetector to these 2 parts, i don’t see an enabled property :confused:

Oh, shoot. I was thinking something else.

However you can change MaxActivationDistance to 0 to disable it, and change it back to however many studs you want the player to be able to click on it to enable it again.

why have you done this.

luau so much easier

From what I can tell your script never creates the click detectors. It just checks if they are there. I may be wrong though as I don’t use Roblox Typescript. Try adding them manually and see how that goes.

When searching for the arrow parts, the names in the screen shot are different, so it’s simply not finding the arrows.

Can I ask why? Life is much simpler with luau

i am doing that, but maxactivationdistance doesn’t get changed at all

MaxActivationDistance is just a number so making it enabled doesn’t work.
Dang it’s hard for us to tell you how to fix your script if it’s not in written in Luau.

I really recommend trying the Studio AI Assistant (found in the View toolbar) instead of a 3rd party AI to help you code, or by watching some Roblox coding tutorials.

clickDetector.MaxActivationDistance = 0 -- to turn it 'off'
clickDetector.MaxActivationDistance = 10 -- or whatever value you want it as to turn it 'on'

well, i’m much more used to javascript. i have been using it since i was 6. :coefficients:

But that might be your issue when scripting with Luau. The translator AI likely can’t predict everything 100% correctly.

Also, did you try my sections of code in the post above? That should solve your issue with the ClickDetector.

i don’t think it uses the same ai roblox does, but thanks for the support, i already solved it.