I'm trying to make a procedurally generating game (ignore the goal of the game).
Currently I'm trying to make it so when you walk over a grid piece and collide with an invisible part it makes that specific grid piece the Current Global Object (CGO).
Using a BoolValue I made it possible to use this as some form of global variable, but whenever I try to use said value it only detects it as false even when it is indeed showing as true in the Explorer. It only works when I set the value to true BEFORE testing the game.
Here's the code in the script that's meant to detect the value:
it's a regular script and not a LocalScript fyi
local CGO = "0,0"
local tracker = game.Workspace.Tracker00
--local CGOa = tracker.CGOa
local trackerPos = tracker.Position
local trackerX = trackerPos.X
local trackerY = trackerPos.Y
local trackerZ = trackerPos.Z
while true do
while tracker.CGOa.Value == false do
tracker.YVal.Value = 7
print("Set TrackerYVal to 7")
wait()
if tracker.CGOa.Value == true then
break
end
end
while tracker.CGOa.Value == true do
tracker.YVal.Value = 14
print("Set TrackerYVal to 14")
wait()
end
tracker.CFrame = CFrame.new(trackerX, trackerY, trackerZ)
wait()
end
Any help would be much appreciated.
Rather than using infinite while loops, consider listening for the Changed signal. It's possible that the break command might be escaping both loops.
local tracker = game.Workspace.Tracker00
tracker.CGOa.Changed:Connect(function(newVal)
print("CGOa changed to ", newVal)
if newVal then
tracker.YVal.Value = 14
print("Set TrackerYVal to 14")
else
tracker.YVal.Value = 7
print("Set TrackerYVal to 7")
end
-- update the tracker position based on newly updated values
local x = tracker.XVal.Value
local y = tracker.YVal.Value
local x = tracker.ZVal.Value
tracker.CFrame = CFrame.new(Vector3.new(x, y, z))
end)
I made some assumptions about how you were positioning the tracker, because the old code would reset its position after every loop.
Related
I have been trying to work on a Region3 script were when you are in it, it plays a song. But I've come across 2 issues, 1 being it thinks the player is always in it when you the player isn't. And the second being the script runs so fast that it keeps repeating before anything can happen
local RegionPart = game.Workspace.RegionArea
local pos1 = RegionPart.Position - (RegionPart.Size / 2)
local pos2 = RegionPart.Position + (RegionPart.Size / 2)
local Region = Region3.new(pos1, pos2)
while true do
wait()
local burhj = workspace:FindPartsInRegion3(Region, nil, 1000)
local song = game.Workspace.bb
song:Play()
print("THE SCRIPT WORKS!")
end
You query the objects which are in Region, but never used the result and just continued. Loop over burhj and check for valid parts.
In this forum the use of FindFirstChild is suggested:
for i,v in ipairs(burhj) do
local player = v.Parent:FindFirstChild("Humanoid")
if player then
print("player is in region: " + player.Parent.Name)
end
end
Alternatively, you can directly use the player position, if the player object or position is known:
local pos = yourPlayer.HumanoidRootPart.Position
local center = region.CFrame
local size = region.Size
if pos.X > center.X - size.X / 2 and pos.X < center.X + size.X / 2 and ... then
print("player is in region")
end
A helper function, if not already present, might be helpful.
For the second problem, set a flag if the player is in the region. Play the sound when the flag was not already set. Unset the flag if you leave the region.
--here are your vars
local enteredFlag = false
while true do
wait()
if playerIsWithinRegion then --here come whatever approach you chose earlier
if not enteredFlag then
enteredFlag = true
local song = game.Workspace.bb
song:Play()
print("THE SCRIPT WORKS!")
end
else
--no player is in the region, lets reset the flag
enteredFlag = false
end
end
so I'm trying to make a basic GUI animation system in ROBLOX, using individual frames and a loop to put them into an imagelabel.
This is the function:
local playAnimation = coroutine.create(function(anim,pos,tank)
while true do
local animBase = sp.AnimBase:Clone()
animBase.Parent = tank
animBase.Visible = true
animBase.Position = pos -- line that causes the error mentioned below.
local frame = 1
for i = 0, animations[anim]["FrameNum"] do
frame = frame + 1
animBase.Image = animations[anim]["Frames"][frame]
NewWait(.1) --this right here, the wait, interfears with the yield.
if frame >= animations[anim]["FrameNum"] then
pos,anim,tank = coroutine.yield()
break
end
end
animBase:Destroy()
end
end)
There are two main problems with this:
every time it runs, I get this error:
20:41:01.934 - Players.Player1.PlayerGui.ScreenGui.Gui-MAIN:65: bad argument #3 to 'Position' (UDim2 expected, got number)
Although this error doesn't seem to do anything. (eg. stop the script completely)
The line causing the error is marked with a comment.
I've made sure that pos is correct. I even tried printing it before setting it, it prints the correct thing which is:
{0,120},{0,65}
The other main problem is that I can't resume it after using it once. It can run this line multiple times fine:
coroutine.resume(playAnimation,"Cannon Fire",UDim2.new(0,120,0,68-25),tank.Frame)
but it won't run:
if tank2:FindFirstChild("Ammo") and isTouching(ammoFrame,tank2:GetChildren()[3]) then
local lastAmmoPos = ammoFrame.Position
ammoFrame:Destroy()
coroutine.resume(playAnimation,"Explosion",lastAmmoPos-UDim2.new(0,25-(ammoTypes[type]["Size"].X.Offset)/2,0,25),tank.Frame)
tank2:GetChildren()[3]:Destroy()
end
Yes, the if statement is working fine. ammoFrame is destroyed and so is the third child of tank2. The coroutine just won't resume.
Fixed by removing the coroutine completely and wrapping the for loop inside a spawn function.
local playAnimation = function(anim,pos,tank)
local animBase = sp.AnimBase:Clone()
animBase.Parent = tank
animBase.Visible = true
animBase.Position = pos
local frame = 1
spawn(function()
for i = 0, animations[anim]["FrameNum"] do
frame = frame + 1
animBase.Image = animations[anim]["Frames"][frame]
wait(.1) --this right here, the wait, interfears with the yield.
if frame >= animations[anim]["FrameNum"] then
break
end
end
animBase:Destroy()
end)
end
I need a bit of help. Basically I have this code:
local plyIsEntered = false
function onTouched(hit)
plyIsEntered = true
if not plyIsEntered then
end
if plyIsEntered then
local humanoid = hit.Parent:FindFirstChild("Humanoid")
local ply = humanoid.Parent
if humanoid ~= nil then
print("Hit")
local playerName = hit.Parent.Name
print(playerName)
local laserEmitter = game.Workspace["Enterance PC"]:FindFirstChild("laserEmitter")
local scanLaser = Instance.new("Part", game.Workspace)
scanLaser.Position = laserEmitter.Position
scanLaser.Name = "ScanLaser"
scanLaser.Size = Vector3.new(1,1,1)
local scanLaserMesh = Instance.new("SpecialMesh", game.Workspace.ScanLaser)
scanLaserMesh.Name = "Cone mesh"
scanLaserMesh.MeshType = ""
plyIsEntered = false
end
end
end
script.Parent.Touched:connect(onTouched)
Now I'm checking if the player touches a box, it has no collisions and is invisible; when they do I want to create a laser that will scan them and open a door. The problem I'm having is when I walk into the trigger box it creates 8 or 9 blocks. One of those blocks is the block I'm applying a mesh too.
What I need to do is make sure it's only running once and not creating more than 1 brick. Hopefully someone can help me!
I believe to fix this you'll need to add a debounce.
You see, the touched event of a Part actually fires many times, so your code will execute multiple times if it is inside of the event.
To fix this, we use a debounce, which means your code won't execute if your part is touched too much in the same time frame. Here is an example:
local debounce = false
part.Touched:connect(function()
if debounce == false then
debounce = true
--Your code goes here.
wait(1)--Wait one second until you'll be able to execute the code again.
debounce = false
end
end)
To read more on debounces: http://wiki.roblox.com/index.php?title=Debounce
For example: The script works fine in one game session, but then in another, it doesn't work at all; almost as if there's some sort of random chance for the script to be deleted or completely ignored. If I remove the debounce, there's a 100% chance for the script to work once again. What could possibly be going wrong here?
local radius = script.Parent
local light = radius.Parent.Light
local sound = radius.Parent.lighton
local debounce = false
radius.Touched:connect(function(hit)
if debounce == false then debounce = true
if game.Players:GetPlayerFromCharacter(hit.Parent) then
light.PointLight.Brightness = 10
light.Material = "Neon"
sound:Play()
wait(5.5)
light.PointLight.Brightness = 0
light.Material = "Plastic"
sound:Play()
wait(0.5)
debounce = false
end
end
end)
Your problem is one of scoping. The debounce will always be set to true, but will only sometimes be set back to false. If it doesn't get changed, the function will obviously never be run again. You'll want to avoid lines like if debounce == false then debounce = true, as they make it more difficult for you to notice that the debounce is not changed in the same scope.
Fixed code:
local radius = script.Parent
local light = radius.Parent.Light
local sound = radius.Parent.lighton
local debounce = false
radius.Touched:connect(function(hit)
if debounce == false then
debounce = true
if game.Players:GetPlayerFromCharacter(hit.Parent) then
light.PointLight.Brightness = 10
light.Material = "Neon"
sound:Play()
wait(5.5)
light.PointLight.Brightness = 0
light.Material = "Plastic"
sound:Play()
wait(0.5)
end
debounce = false
end
end)
Note that both statements changing the value of debounce align.
I have a model called door
Inside I have a BoolValue named Open
I have a model called Top that has all of the door blocks named Work Mabey Comeon and Proboblynot
And I have Block that when touched is supposed to make Top move up
Directly inside door I have this script
door = script.Parent
open = door.Open
Top = door.Top
opener = 18
speed = 100
steps = speed
startl = Top.CFrame
function MoveDoorToCFrame(cfrm,dr)
dr.Work.CFrame = cfrm
dr.Mabey.CFrame = dr.Work.CFrame * CFrame.new(0,-7.2,0)
dr.Comeon.CFrame = dr.Work.CFrame * CFrame.new(0,10.8,0)
dr.Problynot.CFrame = dr.Work.CFrame * CFrame.new(0,10.8,0)
end
function Update()
if speed/steps < 0.5 then
calc = 1-math.cos(math.rad((-90/speed)*steps*2))
else
calc = 1+math.sin(math.rad((90/speed)*((speed/2)-steps)*2))
end
MoveDoorToCFrame(startl * CFrame.new(0,(calc/2)*opener,0),Top)
end
Update()
while true do
wait()
if not open.Value and steps < speed then
steps = steps + 1
Update()
elseif open.Value and steps > 0 then
steps = steps - 1
Update()
end
end
Inside the button that is supposed to activate on touch I have
script.Parent.Touched:connect(function()
script.Parent.Parent.Open.Value = not script.Parent.Parent.Open.Value
end)
script.Parent.Parent.Open.Changed:connect(Update)
Update()
If you know how to fix this it would be gladly appreciated.
Update November 2015:
Using PrimaryPart
Since writing this post, ROBLOX has changed a lot in regards to the API. To move a model like requested, you should set the PrimaryPart property of the model to a central part inside the model. This will act as the origin for the model's movements.
You can then use model:SetPrimaryPartCFrame(cframe) to set the CFrame of the model. You can also retrieve this property by using model:GetPrimaryPartCFrame(), although I believe that is just a shortcut method for model.PrimaryPart.CFrame.
In code, it would look like this:
-- Set PrimaryPart:
MODEL.PrimaryPart = MODEL.SomeCentralPart
...
-- CFrame movement:
local movement = CFrame.new(0, 10, 0)
-- Move the model:
MODEL:SetPrimaryPartCFrame(MODEL:GetPrimaryPartCFrame() * movement)
Option A: Use Model's methods
I think you are making this much more difficult than it needs to be. Whenever you run into an issue like this, be sure to check the current APIs provided. The ROBLOX Model object contains a nifty method called 'TranslateBy' which takes a Vector3 argument to translate the model.
Using MODEL:TranslateBy(Vector3) is similar to moving a model via CFrame, since it ignores collisions.
Another alternative is MODEL:MoveTo(Vector3) which moves a whole model to the given Vector3 world position. The downside to this is that it does collide.
One way to get the same MoveTo effect but without collisions can be done with the TranslateBy method:
MODEL:TranslateBy(Vector3Position - MODEL:GetModelCFrame().p)
Option B: Write a custom function to manipulate the model's CFrame
Another alternative would be to manipulate the whole model's CFrame entirely. To do this, you can write a clever function that will move a whole model relative to an 'origin' point. This is similar to moving shapes on a grid given their points and an origin, except in three dimensions. Using ROBLOX's built-in functions, this is much easier though.
A good way to do this would be to write a function that lets you actually assign a CFrame value to a whole model. Another way would be to allow a translation via CFrame too.
Here's an example:
function ModelCFrameAPI(model)
local parts = {} -- Hold all BasePart objects
local cf = {} -- API for CFrame manipulation
do
-- Recurse to get all parts:
local function Scan(parent)
for k,v in pairs(parent:GetChildren()) do
if (v:IsA("BasePart")) then
table.insert(parts, v)
end
Scan(v)
end
end
Scan(model)
end
-- Set the model's CFrame
-- NOTE: 'GetModelCFrame()' will return the model's CFrame
-- based on the given PrimaryPart. If no PrimaryPart is provided
-- (which by default is true), ROBLOX will try to determine
-- the center CFrame of the model and return that.
function cf:SetCFrame(cf)
local originInverse = model:GetModelCFrame():inverse()
for _,v in pairs(parts) do
v.CFrame = (cf * (originInverse * v.CFrame))
end
end
-- Translate the model's CFrame
function cf:TranslateCFrame(deltaCf)
local cf = (model:GetModelCFrame() * deltaCf)
self:SetCFrame(cf)
end
return cf
end
-- Usage:
local myModel = game.Workspace.SOME_MODEL
local myModelCF = ModelCFrameAPI(myModel)
-- Move to 10,10,10 and rotate Y-axis by 180 degrees:
myModelCF:SetCFrame(CFrame.new(10, 10, 10) * CFrame.Angles(0, math.pi, 0))
-- Translate by 30,0,-10 and rotate Y-axis by 90 degrees
myModelCF:TranslateCFrame(CFrame.new(30, 0, -10) * CFrame.Angles(0, math.pi/2, 0))
This might be hard.
You might want to look to free models for this one unless the people above get it to work.
I, however, do have a script to move a model:
game.Workspace.Model:MoveTo(Vector3.new(0,0,0))
Your code indeed needs fixing.
You should NOT use a never-ending loop to make your stuff work (unless that is the only way).
You should rather base actions on events.
Consider to use this:
Structure:
Door [Model]
DoorScript [Script]
Button [Part]
DoorOpen [BoolValue]
Top [Model]
Mabey [Part]
Comeon [Part]
Problynot [Part]
DoorScript:
local Model = script.Parent
local Door = Model.Top
local Button = Model.Button
local DoorOpen = Model.DoorOpen
local Offset = 0
local ToOffset = 100
local Direction = 1
local StepLength = 0.1
local Moving = false
function StartMoving()
if Moving then return end
Moving = true
while (DoorOpen.Value and Offset ~= ToOffset) or (not DoorOpen.Value and Offset ~= 0) do
local Change = Offset
Offset = math.max(0,math.min(ToOffset,Offset + StepLength * (DoorOpen.Value and 1 or -1)))
Change = Offset - Change
Top:TranslateBy(Vector3.new(0,Change,0))
wait()
end
Moving = false
end
StartMoving()
DoorOpen.Changed:connect(StartMoving)
local Debounce = false
Button.Touched:connect(function()
if Debounce then return end
Debounce = true
DoorOpen.Value = not DoorOpen.Value
wait(4)
Debounce = false
end)
You might want to adjust the speed tho.
This can be used to move models, try adding something like this into your code. It's more dynamic.
a = Workspace.Model
for i=0.1,40 do
for i,v in pairs(a:getChildren()) do
if v:IsA("Part") then
v.CFrame = CFrame.new(v.CFrame + Vector3.new(0,0.1,0))
else print("Not a part")
end
end
end