weird situation while using timer and movie clip in giderous studio - lua

I'm currently using giderous studio to make a tower defense game. However the code doesn't run as expected.
I made a function that make the monster in the game move according to the route settled in a JSON file. The move process go well EXCEPT the first monster being spawned firet, I have absolutely no ideas why the monster stop on its way. (As shown as diagram)
The following is my code:
level.lua:
level = Core.class(Sprite)
function level:init(levelId)
local level = dataSaver.load("level");
--load attributes
self.lives=level[tostring(levelId)]["lives"];
self.route=level[tostring(levelId)]["route"];
self.round=level[tostring(levelId)]["rounds"];
self.towersAllowed=level[tostring(levelId)]["towers"];
--some varibles
self.currentRound=1;
self.monsterList={};
end
function level:spawnMonster()
local monsterType=self.round[1]["type"];
local spawnNumber=self.round[1]["number"];
--set timer for spawn
local timer = Timer.new(self.round[1]["spawnInterval"],0);--spawnNumber);
timer:start();
--spawn
timer:addEventListener(Event.TIMER,function()
local spawnedMonster = monster.new(monsterType);
spawnedMonster.instance:setPosition(self.route[1]["x"],self.route[1]["y"]);
self:moveMonster(spawnedMonster);
end);
--after spawn finished, wait for next round.
timer:addEventListener(Event.TIMER_COMPLETE,function()
local nextRound = Timer.new(self.round[1]["timeUntilNextRound"],1);
nextRound:start();
nextRound:addEventListener(Event.TIMER_COMPLETE,function()
print("nextRound");
end);
end);
end
function level:moveMonster(monsterToMove)
if (monsterToMove.currentDes<=#self.route) then
monsterToMove:move(self.route[monsterToMove.currentDes]["x"],self.route[monsterToMove.currentDes]["y"]);
monsterToMove:addEventListener("monsterMoveDone",function()
monsterToMove.currentDes=monsterToMove.currentDes+1;
self:moveMonster(monsterToMove);
end);
end
end
monster.lua:
monster = Core.class(Sprite)
function monster:init(type)
local monstersList = dataSaver.load("monster");
self.instance = quickImage(monstersList[type]["image"], _W/2, _H/2,monstersList[type]["width"], monstersList[type]["height"]);
self.speed=monstersList[type]["speed"];
self.health=monstersList[type]["health"];
stage:addChild(self.instance);
---some varibles...
self.currentDes=2
end
function monster:move(desX,desY)
local time=getDistance(math.abs(self.instance:getX()-desX),math.abs(self.instance:getY()-desY))/self.speed
local mc = MovieClip.new{
{1, time, self.instance, {x = {self.instance:getX(), desX, "linear"}}},
{1, time, self.instance, {y = {self.instance:getY(), desY, "linear"}}},
}
mc:addEventListener(Event.COMPLETE,function()
self:dispatchEvent(Event.new("monsterMoveDone"))
end);
end
from the code, quickImage(); is just a little function for making image sprite
Any ideas, I thought maybe i make the memory allocating wrong.
Special Note. I run Gideros Studio under OpenSUSE 12.2 with Wine, but i don't think its a matter because all stuff go well.

Related

Running "RecomputeTargetPath()" causes Garry's Mod to crash

So I have been coding a nextbot in Gmod for a while now and have found a bug that causes Gmod to crash every time the function is run. here is the function:
function ENT:RecomputeTargetPath(path_target)
if self.testmode then
PrintMessage(HUD_PRINTTALK, 'recomputing target path')
end
self.path = Path("Chase")
if (CurTime() - self.LastPathingInfraction < 5) then
return
end
local targetPos = path_target:GetPos()
-- Run toward the position below the ENTity we're targetting, since we can't fly.
trace.start = targetPos
trace.filter = self:GetEnemy()
local tr = util.TraceEntity(trace, self:GetEnemy())
-- Of course, we sure that there IS a "below the target."
if (tr.Hit and util.IsInWorld(tr.HitPos)) then
targetPos = tr.HitPos
end
local rTime = SysTime()
self.path:Compute(self, targetPos)
if (SysTime() - rTime > 0.005) then
self.LastPathingInfraction = CurTime()
end
end
When this function is run, it recomputes the target path for the nextbot to make it move differently.
It's used in the context of an if that looks like this or something very close:
if (CurTime() - self.LastPathRecompute > 0.1) then
self.LastPathRecompute = CurTime()
self:RecomputeTargetPath(self:GetEnemy():GetPos())
end
As far as I know, all variables in the if are called before each.
As far as I know, all variables in the if are called before each.
I tried recalling them but that didn't work at all... I don't know what is happening.
Also, side note, the function gets called multiple times per second based on the player's movement.
I've also added debug prints to every line of the code to see where the issue was and the bug fixed itself when I added them but when I removed them the bug came back...
Any help?

Other players can not see an object duplicate

I have this script that duplicates an object and teleports it to the player when the GUI button is pressed (You can think of GMod to make things easier). It is stored in a LocalScript inside the button and when you press it, but it's only visible for the player that clicked the button.
I'm not exactly sure how I would solve the problem or what the problem is, but I think it's because it's all stored into a LocalScript. I'm new to Lua and Roblox game development and I didn't really take any lessons on it, I'm just working from my memory and experience. Any and all suggestions are greatly appreciated. Also, if I need to give more information, please ask and I will provide it.
My script:
local player = game.Players.LocalPlayer
script.Parent.MouseButton1Click:Connect(function()
local rag = game.Lighting.ragdolls_presets["Wood Crate"]:Clone()
local X = player.Character.UpperTorso.Position.X
local Y = player.Character.UpperTorso.Position.Y + 10
local Z = player.Character.UpperTorso.Position.Z
rag.Parent = game.Workspace.ragdolls
local children = rag:GetChildren()
for i = 1, #children do
local child = children[i]
child.Position = Vector3.new(X,Y,Z)
end
end)
Thank you in advance!
When you clone something in a LocalScript, it only clones on the client side. Changes done on the client side never gets replicated to the server side, however all changes done on the server side would get replicated to all clients, which are the players.
So to fix this you'd need to use RemoteEvents, which is a way for the client to tell the server to do something.
So instead of doing this in a LocalScript
local player = game.Players.LocalPlayer
script.Parent.MouseButton1Click:Connect(function()
local rag = game.Lighting.ragdolls_presets["Wood Crate"]:Clone()
local X = player.Character.UpperTorso.Position.X
local Y = player.Character.UpperTorso.Position.Y + 10
local Z = player.Character.UpperTorso.Position.Z
rag.Parent = game.Workspace.ragdolls
local children = rag:GetChildren()
for i = 1, #children do
local child = children[i]
child.Position = Vector3.new(X,Y,Z)
end
end)
Put a new RemoteEvent in game.Replicated Storage, then:
This should be the LocalScript
local Event = game.ReplicatedStorage.RemoteEvent
script.Parent.MouseButton1Click:Connect(function()
Event:Fire()
end)
And this should be the ServerScript (or Script for short)
local Event = game.ReplicatedStorage.RemoteEvent
Event.OnServerEvent:Connect(function(player)
local rag = game.Lighting.ragdolls_presets["Wood Crate"]:Clone()
local X = player.Character.UpperTorso.Position.X
local Y = player.Character.UpperTorso.Position.Y + 10
local Z = player.Character.UpperTorso.Position.Z
rag.Parent = game.Workspace.ragdolls
local children = rag:GetChildren()
for i = 1, #children do
local child = children[i]
child.Position = Vector3.new(X,Y,Z)
end
end)
Also, it is very important to do server-side validation when using RemoteEvents, for example: instead of checking whether a player has enough money to spawn something in a LocalScript before the RemoteEvent is fired, it should be done in both LocalScript and the ServerScript. The cause for this is that players can change anything in their client side, so information from the client can NOT be trusted. Optionally you can also have time-outs in each side because, lets say a player has millions of money, he can keep executing the RemoteEvent hundreds of times in under a minute which can crash the server or cause extreme lag. So a 3 second - 1 minute time out is sometimes necessary
More information about Roblox's Client-Server Model: https://create.roblox.com/docs/scripting/networking/client-server-model
More information about Roblox RemoteEvents: https://create.roblox.com/docs/reference/engine/classes/RemoteEvent

Need help on ROBLOX script (Lua)

I`m making a script for my UFO in ROBLOX where whenever the UFO passes overhead it plays an audio. I made a script that goes as follows
while true do
if script.Parent.Parent.Velocity.Magnitude>10 then
if local h = hit.Parent:FindFirstChild("Humanoid")
then script.parent:play()
wait(5)
else
wait()
end
wait()
end
Any corrections would be a real help!
Thanks!
Everything aside, at the root there are a lot of syntax errors as well as the error of implementation, all in all the code block you've given us won't do what you wanted it to.
However, here's a basic idea of what the solution is:
local newThread = coroutine.create(function()
while true do
for i, v in game.Players:GetPlayers()
local playerListener = workspace[v.Name]["Head"]
local ufoListener = workspace.Ufo:FindFirstChild('Listener')
local magnitude = (playerListener.Position - ufoListener.Position).magnitude
if (magnitude > 10) then
script.Parent:play()
else
wait(0.5)
end
end
end
end)
coroutine.resume(newThread)
Essentially, here's the rundown: We're using coroutines so this while loop doesn't yield this thread for all eternity. There are some more complex avenues using bindable events and maybe some server-client handshake where, when fired from the LocalPlayer, it calls an event in the server- but I digress. This should be perfect for your needs without confusing you too much.

How do I make os.pullEvent not yield?

I'm trying to create a while true do loop, that reacts to clicks, using os.pullEvent, and also updates a monitor.
Problem being, it only updates the screen when I press one of the on screen buttons, and I've found out that's because pullEvent stops the script, until an event is fired.
Is it possible to make it so pullEvent doesn't stop me updating the monitor?
function getClick()
event,side,x,y = os.pullEvent("monitor_touch")
button.checkxy(x,y)
end
local tmp = 0;
while true do
button.label(2, 2, "Test "..tmp)
button.screen()
tmp++
getClick()
end
You can easily use the parallel api to run both codes essentially at the same time. How it works is it runs them in sequence until it hits something that uses os.pullEvent and then swaps over and does the other side, and if both stop at something that does os.pullEvent then it keeps swapping between until one yields and continues from there.
local function getClick()
local event,side,x,y = os.pullEvent("monitor_touch")
buttoncheckxy(x,y)
end
local tmp = 0
local function makeButtons()
while true do
button.label(2,2,"Test "..tmp)
button.screen()
tmp++
sleep(0)
end
end
parallel.waitForAny(getClick,makeButtons)
Now if you notice, first thing, I've made your while loop into a function and added a sleep inside it, so that it yields and allows the program to swap. At the end you see parallel.waitForAny() which runs the two functions that are specified and when one of them finishes, which in this case whenever you click on a button, then it ends. Notice however inside the arguments that I'm not calling the functions, I'm just passing them.
I don't have computercraft handy right now or look up the functions but i know that you can use the function os.startTimer(t) that will cause an event in t seconds (I think it is seconds)
usage:
update_rate = 1
local _timer = os.startTimer(update_rate)
while true do
local event = os.pullEvent()
if event == _timer then
--updte_screen()
_timer = os.startTimer(update_rate)
elseif event == --some oter events you want to take action for
--action()
end
end
note: the code is not tested and I didn't use computercraft in quite a while so pleas correct me if i did a mistake.

Easiest way to make lua script wait/pause/sleep/block for a few seconds?

I cant figure out how to get lua to do any common timing tricks, such as
sleep - stop all action on thread
pause/wait - don't go on to the next
command, but allow other code in the
application to continue
block - don't go on to next command until the
current one returns
And I've read that a
while os.clock()<time_point do
--nothing
end
eats up CPU time.
Any suggestions? Is there an API call I'm missing?
UPDATE: I wrote this question a long time ago trying to get WOW Lua to replay actions on a schedule (i.e. stand, wait 1 sec, dance, wait 2 sec, sit. Without pauses, these happen almost all in the same quarter second.) As it turned out WOW had purposely disabled pretty much everything that allows doing action on a clock because it could break the game or enable bots. I figured to re-create a clock once it had been taken away, I'd have to do something crazy like create a work array (with an action and execution time) and then register an event handler on a bunch of common events, like mouse move, then in the even handler, process any action whose time had come. The event handler wouldn't actually happen every X milliseconds, but if it was happening every 2-100 ms, it would be close enough. Sadly I never tried it.
[I was going to post this as a comment on John Cromartie's post, but didn't realize you couldn't use formatting in a comment.]
I agree. Dropping it to a shell with os.execute() will definitely work but in general making shell calls is expensive. Wrapping some C code will be much quicker at run-time. In C/C++ on a Linux system, you could use:
static int lua_sleep(lua_State *L)
{
int m = static_cast<int> (luaL_checknumber(L,1));
usleep(m * 1000);
// usleep takes microseconds. This converts the parameter to milliseconds.
// Change this as necessary.
// Alternatively, use 'sleep()' to treat the parameter as whole seconds.
return 0;
}
Then, in main, do:
lua_pushcfunction(L, lua_sleep);
lua_setglobal(L, "sleep");
where "L" is your lua_State. Then, in your Lua script called from C/C++, you can use your function by calling:
sleep(1000) -- Sleeps for one second
If you happen to use LuaSocket in your project, or just have it installed and don't mind to use it, you can use the socket.sleep(time) function which sleeps for a given amount of time (in seconds).
This works both on Windows and Unix, and you do not have to compile additional modules.
I should add that the function supports fractional seconds as a parameter, i.e. socket.sleep(0.5) will sleep half a second. It uses Sleep() on Windows and nanosleep() elsewhere, so you may have issues with Windows accuracy when time gets too low.
You can't do it in pure Lua without eating CPU, but there's a simple, non-portable way:
os.execute("sleep 1")
(it will block)
Obviously, this only works on operating systems for which "sleep 1" is a valid command, for instance Unix, but not Windows.
Sleep Function - Usage : sleep(1) -- sleeps for 1 second
local clock = os.clock
function sleep(n) -- seconds
local t0 = clock()
while clock() - t0 <= n do
end
end
Pause Function - Usage : pause() -- pause and waits for the Return key
function pause()
io.stdin:read'*l'
end
hope, this is what you needed! :D - Joe DF
for windows you can do this:
os.execute("CHOICE /n /d:y /c:yn /t:5")
It doesn't get easier than this. Sleep might be implemented in your FLTK or whatever, but this covers all the best ways to do standard sort of system sleeps without special event interrupts. Behold:
-- we "pcall" (try/catch) the "ex", which had better include os.sleep
-- it may be a part of the standard library in future Lua versions (past 5.2)
local ok,ex = pcall(require,"ex")
if ok then
-- print("Ex")
-- we need a hack now too? ex.install(), you say? okay
pcall(ex.install)
-- let's try something else. why not?
if ex.sleep and not os.sleep then os.sleep = ex.sleep end
end
if not os.sleep then
-- we make os.sleep
-- first by trying ffi, which is part of LuaJIT, which lets us write C code
local ok,ffi = pcall(require,"ffi")
if ok then
-- print("FFI")
-- we can use FFI
-- let's just check one more time to make sure we still don't have os.sleep
if not os.sleep then
-- okay, here is our custom C sleep code:
ffi.cdef[[
void Sleep(int ms);
int poll(struct pollfd *fds,unsigned long nfds,int timeout);
]]
if ffi.os == "Windows" then
os.sleep = function(sec)
ffi.C.Sleep(sec*1000)
end
else
os.sleep = function(sec)
ffi.C.poll(nil,0,sec*1000)
end
end
end
else
-- if we can't use FFI, we try LuaSocket, which is just called "socket"
-- I'm 99.99999999% sure of that
local ok,socket = pcall(require,"socket")
-- ...but I'm not 100% sure of that
if not ok then local ok,socket = pcall(require,"luasocket") end
-- so if we're really using socket...
if ok then
-- print("Socket")
-- we might as well confirm there still is no os.sleep
if not os.sleep then
-- our custom socket.select to os.sleep code:
os.sleep = function(sec)
socket.select(nil,nil,sec)
end
end
else
-- now we're going to test "alien"
local ok,alien = pcall(require,"alien")
if ok then
-- print("Alien")
-- beam me up...
if not os.sleep then
-- if we still don't have os.sleep, that is
-- now, I don't know what the hell the following code does
if alien.platform == "windows" then
kernel32 = alien.load("kernel32.dll")
local slep = kernel32.Sleep
slep:types{ret="void",abi="stdcall","uint"}
os.sleep = function(sec)
slep(sec*1000)
end
else
local pol = alien.default.poll
pol:types('struct', 'unsigned long', 'int')
os.sleep = function(sec)
pol(nil,0,sec*1000)
end
end
end
elseif package.config:match("^\\") then
-- print("busywait")
-- if the computer is politically opposed to NIXon, we do the busywait
-- and shake it all about
os.sleep = function(sec)
local timr = os.time()
repeat until os.time() > timr + sec
end
else
-- print("NIX")
-- or we get NIXed
os.sleep = function(sec)
os.execute("sleep " .. sec)
end
end
end
end
end
For the second request, pause/wait, where you stop processing in Lua and continue to run your application, you need coroutines. You end up with some C code like this following:
Lthread=lua_newthread(L);
luaL_loadfile(Lthread, file);
while ((status=lua_resume(Lthread, 0) == LUA_YIELD) {
/* do some C code here */
}
and in Lua, you have the following:
function try_pause (func, param)
local rc=func(param)
while rc == false do
coroutine.yield()
rc=func(param)
end
end
function is_data_ready (data)
local rc=true
-- check if data is ready, update rc to false if not ready
return rc
end
try_pause(is_data_ready, data)
I would implement a simple function to wrap the host system's sleep function in C.
Pure Lua uses only what is in ANSI standard C. Luiz Figuereido's lposix module contains much of what you need to do more systemsy things.
require 'alien'
if alien.platform == "windows" then
kernel32 = alien.load("kernel32.dll")
sleep = kernel32.Sleep
sleep:types{ret="void",abi="stdcall","uint"}
else
-- untested !!!
libc = alien.default
local usleep = libc.usleep
usleep:types('int', 'uint')
sleep = function(ms)
while ms > 1000 do
usleep(1000)
ms = ms - 1000
end
usleep(1000 * ms)
end
end
print('hello')
sleep(500) -- sleep 500 ms
print('world')
I agree with John on wrapping the sleep function.
You could also use this wrapped sleep function to implement a pause function in lua (which would simply sleep then check to see if a certain condition has changed every so often). An alternative is to use hooks.
I'm not exactly sure what you mean with your third bulletpoint (don't commands usually complete before the next is executed?) but hooks may be able to help with this also.
See:
Question: How can I end a Lua thread cleanly?
for an example of using hooks.
You can use:
os.execute("sleep 1") -- I think you can do every command of CMD using os.execute("command")
or you can use:
function wait(waitTime)
timer = os.time()
repeat until os.time() > timer + waitTime
end
wait(YourNumberHere)
You want win.Sleep(milliseconds), methinks.
Yeah, you definitely don't want to do a busy-wait like you describe.
It's also easy to use Alien as a libc/msvcrt wrapper:
> luarocks install alien
Then from lua:
require 'alien'
if alien.platform == "windows" then
-- untested!!
libc = alien.load("msvcrt.dll")
else
libc = alien.default
end
usleep = libc.usleep
usleep:types('int', 'uint')
function sleep(ms)
while ms > 1000 do
usleep(1000)
ms = ms - 1000
end
usleep(1000 * ms)
end
print('hello')
sleep(500) -- sleep 500 ms
print('world')
Caveat lector: I haven't tried this on MSWindows; I don't even know if msvcrt has a usleep()
I started with Lua but, then I found that I wanted to see the results instead of just the good old command line flash. So i just added the following line to my file and hey presto, the standard:
please press any key to continue...
os.execute("PAUSE")
My example file is only a print and then a pause statment so I am sure you don't need that posted here.
I am not sure of the CPU implications of a running a process for a full script. However stopping the code mid flow in debugging could be useful.
I believe for windows you may use: os.execute("ping 1.1.1.1 /n 1 /w <time in milliseconds> >nul as a simple timer.
(remove the "<>" when inserting the time in milliseconds) (there is a space between the rest of the code and >nul)
cy = function()
local T = os.time()
coroutine.yield(coroutine.resume(coroutine.create(function()
end)))
return os.time()-T
end
sleep = function(time)
if not time or time == 0 then
time = cy()
end
local t = 0
repeat
local T = os.time()
coroutine.yield(coroutine.resume(coroutine.create(function() end)))
t = t + (os.time()-T)
until t >= time
end
You can do this:
function Sleep(seconds)
local endTime = os.time() + seconds
while os.time() < endTime do
end
end
print("This is printed first!")
Sleep(5)
print("This is printed 5 seconds later!")
You could try this:
function wait(seconds)
local start = os.time()
repeat until os.time() > start + seconds
end
wait(5) print("cargo. Cargo what? Cargo, storage.") -- waits 5 seconds and then prints
It worked for me in Lua CLI.
This should work:
os.execute("PAUSE")

Resources