Coroutine problems - lua

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

Related

Script isn't detecting a change with a BoolValue (Roblox Studio)

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.

Attempt to call a Instance value

This error keeps popping up in output, and I'm not sure what I am doing wrong.
Here's the code:
function bullet() --function giving me errors
bullet = Instance.new("Part") --instance
bullet.Size = Vector3.new(1,1,1)
bullet.Position = script.Parent.Position
bullet.Parent = workspace
bullet.Velocity = script.Parent.CFrame.LookVector * 90
bullet.CanCollide = false
--dont think making the script disable then enable after a certain time will work
end
script.Parent.Parent.Activated:Connect(function() --the script is in the handle of the tool
bullet() -- where the error is
--weird thing is, i have made functions like "explode()" that worked just like this and did not have any errors
--pretty sure this is a roblox problem, but i am not sure
--someone help
end)
the error: "Workspace.Tool.Handle.Script:12: attempt to call a Instance value"
--pretty sure this is a roblox problem, but i am not sure
Not the cause is your code.
You define a global function named bullet
function bullet()
-- more code
end
The first thing you do in that function is
bullet = Instance.new("Part")
Doing that you assign the return value of Instance.new("Part") to bullet.
Let's call function bullet the first time bullet()
Now the function is executed and bullet becomes an Instance. It is not a function anymore.
If we now call bullet a second time we get the error
"Workspace.Tool.Handle.Script:12: attempt to call a Instance value"
So bullet basically overwrites itself so it can not be called a second time.
Just use different names to avoid this. Then you should think about the scope. If you want to create a new bullet every time you call bullet you need to make the Intance value local as you would otherwise overwrite the same global bullet every time you call the function.
Try something like
function SpawnBullet() --function giving me errors
local bullet = Instance.new("Part") --instance
bullet.Size = Vector3.new(1,1,1)
bullet.Position = script.Parent.Position
bullet.Parent = workspace
bullet.Velocity = script.Parent.CFrame.LookVector * 90
bullet.CanCollide = false
return bullet
end
script.Parent.Parent.Activated:Connect(function()
SpawnBullet()
end)
Try naming the bullet variable inside the bullet function something besides bullet or change the name of the function
Did you try changing the name of the function or the variable? Maybe that's the problem.
Try:
function CreateBullet() --function giving me errors
bullet = Instance.new("Part") --instance
bullet.Size = Vector3.new(1,1,1)
bullet.Position = script.Parent.Position
bullet.Parent = workspace
bullet.Velocity = script.Parent.CFrame.LookVector * 90
bullet.CanCollide = false
end
script.Parent.Parent.Activated:Connect(function()
CreateBullet()
end)
I'm sorry if it didn't work or if I wasn't helpful.

Lua - World of Warcraft API Debuff frame

I have the strange problem, that with this AddOn it shows a frame with the current debuff. I think it displays only the first one and if another one is applied it just overlaps the first one. How can i make it so it displays the new ones next to the old ones?
This is the code:
function WCCPlayer_OnLoad()
this:SetHeight(40)
this:SetWidth(40)
this:SetPoint("CENTER", 0, 0)
this:RegisterEvent("UNIT_AURA")
this:RegisterEvent("PLAYER_AURAS_CHANGED")
this.texture = this:CreateTexture(this, "BACKGROUND")
this.texture:SetAllPoints(this)
this.cooldown = CreateFrame("Model", "Cooldown", this, "CooldownFrameTemplate")
this.cooldown:SetAllPoints(this)
this.maxExpirationTime = 0
this:Hide()
end
function WCCPlayer_OnEvent()
local spellFound = false
for i=1, 16 do -- 16 is enough due to HARMFUL filter
local texture = UnitDebuff("player", i)
WCCTooltip:ClearLines()
WCCTooltip:SetUnitDebuff("player", i)
local buffName = WCCTooltipTextLeft1:GetText()
if spellIds[buffName] then
spellFound = true
for j=0, 31 do
local buffTexture = GetPlayerBuffTexture(j)
if texture == buffTexture then
local expirationTime = GetPlayerBuffTimeLeft(j)
this:Show()
this.texture:SetTexture(buffTexture)
this.cooldown:SetModelScale(1)
if this.maxExpirationTime <= expirationTime then
CooldownFrame_SetTimer(this.cooldown, GetTime(), expirationTime, 1)
this.maxExpirationTime = expirationTime
end
return
end
end
end
end
if spellFound == false then
this.maxExpirationTime = 0
this:Hide()
end
end
function WCCTarget_OnLoad()
end
function WCCTarget_OnEvent()
end
I think it is all about the frame position, and as you said, the new frame is displaying on top of the previous frame.
You need to have the new frame position next to the previous so each time you run your WCCPlayer_OnLoad() function it increase the X coordinate by the width of the frame.
First declare a local setPointX variable out side of the function, then increment the setPointX variable by the frame width, (in your case it is 40), each time the function is run;
local setPointX, setPointY = 0,0 -- x and y variables
function WCCPlayer_OnLoad()
this:SetHeight(40)
this:SetWidth(40)
this:SetPoint('CENTER', setPointX, setPointY) -- use variables to set the frame point
this:RegisterEvent('UNIT_AURA')
this:RegisterEvent('PLAYER_AURAS_CHANGED')
this.texture = this:CreateTexture(this, 'BACKGROUND')
this.texture:SetAllPoints(this)
this.cooldown = CreateFrame('Model', 'Cooldown', this, 'CooldownFrameTemplate')
this.cooldown:SetAllPoints(this)
this.maxExpirationTime = 0
this:Hide()
setPointX = setPointX + 40 -- increase the x variable by the width of the frame
end
I have no background in programming, (just trying to teach myself Java and Lua), so there undoubtedly will be better and more efficient/effective ways to solve your issue.

Roblox script running multiple times?

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

Gideros GTween Event Listener

I'm trying a GTween example from the following link
Gideros GTween with Easing
The example doesn't work out of the box, so I dug into the source code of GTween and added the following lines to my example in order to allow event dispatching.
local tween = GTween.new(jewel, 2, animProperties, gtweenProperties)
tween.suppressEvents = false -- New Line #1
tween.dispatchEvents = true -- New Line #2
tween:addEventListener('complete', function()
stage:removeChild(jewel)
jewel = nil
end)
However, the app crashes. I tried commenting the following line in gtween.lua
self:dispatchEvent(Event.new(name))
and the app doesn't crash, however the callbacks aren't invoked (obviously, why would it?)
This is the stack trace from the app.
gtween.lua:445: attempt to call method 'dispatchEvent' (a boolean value)
stack traceback:
gtween.lua:445: in function 'dispatchEvt'
gtween.lua:255: in function 'setPosition'
gtween.lua:86: in function <gtween.lua:74>
Any pointers would be greatly appreciated. Thanks.
PS: I'm not sure if this is a bug on Gideros.
i just tried with the latest gideros' gtween (note that it is edited 10 days ago), and use this sample (i took the sample from your link and add sprite definition, also include a image file in project) and it works(the callback is called) :
local animate = {}
animate.y = 100
animate.x = 100
animate.alpha = 0.5
animate.scaleX = 0.5
animate.scaleY = 0.5
animate.rotation = math.random(0, 360)
local properties = {}
properties.delay = 0
properties.ease = easing.inElastic
properties.dispatchEvents = true
local sprite = Bitmap.new(Texture.new("box.png")) -- ADD THIS
stage:addChild(sprite) -- ADD THIS
local tween = GTween.new(sprite, 10, animate, properties)
tween:addEventListener("complete", function()
stage:removeChild(sprite)
sprite = nil
end)

Resources