Roblox infinite rotating loop - loops

I am working on doing a health pack for Roblox for my game. the code is complete and it works perfectly, but I want the health pack itself to rotate slowly in a cool way so here is my code tell me what is wrong
local healthPack = script.Parent
local healAmount = 30
local cooldown = 5
local canHeal = true
local function handleTouch(otherPart)
local character = otherPart.Parent
local humanoid = character:FindFirstChild('Humanoid')
if humanoid and canHeal then
if game.Workspace.Player1.Humanoid.Health == 100 then
print("You have enough health")
else
canHeal = false
game.Workspace.HealthPack.Transparency = .75
local currentHealth = humanoid.Health
local newHealth = currentHealth + healAmount
humanoid.Health = newHealth
wait(cooldown)
canHeal = true
game.Workspace.HealthPack.Transparency = 0
end
end
end
healthPack.Touched:connect(handleTouch)
while true do
local currentRotationX = game.Workspace.HealthPack.Rotation.X
--local currentRotationX = game.Workspace.HealthPack.Rotation.Y
local currentRotationZ = game.Workspace.HealthPack.Rotation.Z
game.Workspace.HealthPack.Rotation.X = currentRotationX + 10
--game.Workspace.HealthPack.Rotation.Y = currentRotationY + 10
game.Workspace.HealthPack.Rotation.Z = currentRotationZ + 10
wait(.5)
end

Try the following code. In order to rotate an object correctly (modifying the rotation property usually doesn't do the trick, it's similar to the position property, it conforms to collisions) you must use CFrame.
local x = 0
while true do
game.Workspace.HealthPack.CFrame = game.Workspace.HealthPack.CFrame * CFrame.Angles(0, math.rad(x), 0)
x = x + 1
wait()
end
Fair disclaimer, I haven't worked with RBX.Lua in a while, so this might not be the best way to do it.

local runService = game:GetService("RunService")
runService.Heartbeat:Connect(function()
script.Parent.Orientation += Vector3.new(0,0.2,0)
end)
you could change the y axis (or any other axis) of the part's orientation forever to rotate slowly with runService.Heartbeat (while True do loop but quicker for a smoother rotation).

Related

How do I loop ROBLOX audio at a specific point?

Here's my local script placed into the starter gui. I need the sound to loop after 62 seconds.
game.Workspace.Sound.Play()
local sound = Instance.new("Sound", game.Workspace)
sound.SoundId = "rbxassetid://145294677"
sound.TimePosition = 0
sound:Play()
wait(62)
sound:Stop()
sound:Play()
Sound:Play() will reset the position to 0 or the last set value
local sound = Instance.new("Sound", game.Workspace)
sound.SoundId = "rbxassetid://145294677"
while true do
sound:Play()
wait(62)
end

NodeMcu Lua receive information from app in a server

I developed a simple app in MIT APP Inventor that controls a heat pump water heater.
The app sends a different string for each button pressed and the NodeMcu verifies which button was pressed, as you can see in the code below.
srv=net.createServer(net.TCP)
srv:listen(80,function(conn)
conn:on("receive", function(client,request)
local buf = ""
local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP")
if(method == nil)then
_, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP")
end
local _GET = {}
if (vars ~= nil)then
for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do
_GET[k] = v
end
end
local _on,_off = "",""
if(_GET.pin == "ip")then
local ip=wifi.sta.getip()
local ler_ip=string.sub(ip,1,13)
dofile("novolcd.lua").cls()
dofile("novolcd.lua").lcdprint("IP="..ler_ip)
elseif(_GET.pin == "05a60")then
sp_temperaturas[5]=60
elseif(_GET.pin == "06a60")then
sp_temperaturas[6]=60
elseif(_GET.pin == "Ferias")then
dofile("novolcd.lua").cls()
dofile("novolcd.lua").lcdprint(" Modo ferias ")
modo_ferias()
elseif(_GET.pin == "Parar2")then
dofile("novolcd.lua").cls()
dofile("novolcd.lua").lcdprint(" Parar")
end
end)
conn:on("sent", function (c) c:close() end)
end)
And when the button "Ferias" is pressed the system starts the heating process by calling the function modo_ferias().
function aquecer()
local kp=100/10
local ki=5
local kd=5
local tempo_on=0
local tempo_off=0
i=0
local duty=0
erro=sp_temp-t_atual
soma_erro = soma_erro + erro/5;
dif_erro = (erro - erro_ant)/5;
erro_ant = erro;
print(erro.." "..soma_erro.." "..dif_erro)
duty= kp * erro + soma_erro / ki + dif_erro * kd
print(duty)
tempo_on= duty *50
if (tempo_on > 5000) then
tempo_on = 5000
end
tempo_off = 5000 - tempo_on
repeat
i = i + 1
tmr.delay(1000)
until (i >= tempo_off)
gpio.write(8, gpio.HIGH)
repeat
i = i + 1
tmr.delay(1000)
until (i == 5000)
gpio.mode(8, gpio.INPUT)
end
function modo_ferias()
repeat
sair_ferias=0
pressao()
if (pressao_psi <=3)
sair_ferias=1
end
t_atual=ler_temperatura()
local int = string.format("%d", t_atual ) -- parte inteira
local dec = string.format("%.1d", t_atual % 10000) -- parte decimal com uma casa
t_display = int .. "." .. dec
rtc()
dofile("novolcd.lua").cls()
dofile("novolcd.lua").lcdprint("Temp="..t_display.." ST="..sp_temp..data_horas)
sp_temp=40
local horas_ferias=hour
if(horas_ferias==0 or horas_ferias==1 or horas_ferias==2 or horas_ferias==3 or horas_ferias==4 or horas_ferias==5 or horas_ferias==6) then
sp_temp=70
end
if (sp_temp>t_atual) then
aquecer()
end
until (sair_ferias==1)
end
And here is where my problem appears. If I press a button form the app after the "Ferias" button been pressed, the NodeMcu won't know it because the program is in the heating functions and not verifying if the app sended any instruction.
Is there any way to listen the app commands and to do the heating process at the same time?
There are a few things
Global state
because the program is in the heating functions and not verifying if the app sended any instruction
If the commands triggered by pressing the various buttons can not run independently from each other then you need some form of global state to make sure they don't interfere.
Busy loop
repeat
i = i + 1
tmr.delay(1000)
until (i == 5000)
This is a no-go with NodeMCU as it's essentially a stop-the-world busy loop. Besides, tmr.delay is scheduled to be removed because it's abused so often.
Task posting
node.task.post is a possible solution to scheduling tasks for execution "in the near future". You could use this to post task from the on-receive callback rather executing them synchronously.

Lua / Corona SDK : Positional difference of display objects in loop

so while building a mobile game with Corona SDK i am encountering some problems now and then. One of them I didn't seem to solve :
When spawning display objects in a loop, there seems to randomly appear a positional difference between two of the objects in a row.
At first, I thought this was due to large chunks of code that were executed between the actual spawning and the start of the transition, but then I managed to reproduce the same problem in few lines :
local rectangleLoopTimer;
local counter = 0;
local rectangleArray = {}
local function rectangleLoop()
counter = counter + 1
local thisRectangle = display.newRect(1, 1, 216, 400)
thisRectangle.anchorX = 0
table.insert(rectangleArray, thisRectangle)
transition.to(
thisRectangle,
{
time = 5000,
x = thisRectangle.x + 1080,
onComplete = function()
display.remove(thisRectangle)
table.remove(rectangleArray, counter)
end
}
)
end
rectangleLoopTimer = timer.performWithDelay(985, rectangleLoop, 0)
If one executes this, then one sees what I mean, so what do you think why this happens? I appreciate every answer!
Greetings, Nils
EDIT:
This also produces the same problem :
local rectangleLoopTimer;
local counter = 0
local rectangleArray = {}
local thisRectangle
local function rectangleLoop()
counter = counter + 1
thisRectangle = display.newRect(1, 1, 216, 400)
thisRectangle.anchorX = 0
thisRectangle.lastTime = 0
thisRectangle.rate = 216
table.insert(rectangleArray, thisRectangle)
thisRectangle.lastTime = system.getTimer()
thisRectangle.enterFrame = function(self, event)
local curTime = system.getTimer()
local dt = curTime - self.lastTime
self.lastTime = curTime
local dx = self.rate * dt / 1000
self.x = self.x + dx
end
Runtime:addEventListener("enterFrame", thisRectangle)
end
rectangleLoopTimer = timer.performWithDelay(1000, rectangleLoop, 0)
RE-EDIT:
This code also produces the same problem, albeit using framerate independent animation. The issue is getting emphasized when increasing the speed of the loop as in the code below :
local loopSpeed = 306
local loopTimerSpeed = 1000
local gapTable = {}
local gapLoopTimer
local frameTime
local gap
--enterFrame for time only
local function frameTime(event)
frameTime = system.getTimer()
end
--enterFrame
local function enterFrame(self, event)
local deltaTime = frameTime - self.time
print(deltaTime/1000)
self.time = frameTime
local speed = self.rate * deltaTime / 1000
self:translate(speed, 0)
end
--loop speed function
local function setLoopSpeed(factor)
loopSpeed = loopSpeed * factor
loopTimerSpeed = loopTimerSpeed / factor
end
--set the loop speed
setLoopSpeed(3)
--loop to create gaps
local function createGap()
gap = display.newRect(1, 1, 308, 442)
gap.time = system.getTimer()
gap.anchorX = 1
gap.anchorY = 0
--animation
gap.rate = loopSpeed
gap.enterFrame = enterFrame
Runtime:addEventListener("enterFrame", gap)
--fill table for cleaning up
table.insert(gapTable, gap)
--cleaning up
for i = #gapTable, 1, -1 do
local thisGap = gapTable[i]
if thisGap.x > display.contentWidth + 500 then
display.remove(thisGap)
table.remove(gapTable, i)
Runtime:removeEventListener("enterFrame", thisGap)
end
thisGap = nil
end
end
Runtime:addEventListener("enterFrame", frameTime)
gapLoopTimer = timer.performWithDelay(
loopTimerSpeed,
createGap,
0
)
This is a very common problem with transitions, and [to me] a bug in Corona SDK.
The important thing to note is how transitions work.
Transitions are nothing else than a table with references to objects and information about what should be done to them each frame.
Each frame such object is retrieved and current time is used to calculate the difference that should be applies to the values of the object, as specified in the transition itself.
This basically means that if you ask Corona to move an object from x = 0 to x = 100 in time = 100. Each frame, Corona will take that information, take current time, and will calculate the x value of your object.
The issue here is, that the current time taken, is current time at a time of calculation, and not time of the frame. It means, that if you have a lot of transitions, it could be quite a few milliseconds between first and last of the transitions within one frame. This will result in different positions within same frame.
If Corona would take frame time [so time at the beginning of the frame] it would use the same value to calculate everything, and no matter how many objects you would be transitioning from A to B, all of them would appear in the same place in all of the frames.
The easiest way to fix this, would be to handle transitions manually in enterFrame or use a library which does it for you, for example: AKTween.
Hope this helps.
EDIT:
Based on your additional code and comments, I think this should work as you wanted. Please forgive me the code quality, I wrote it from memory and didn't test it in Corona.
local rectangleLoopTimer;
local allRectangles = display.newGroup()
local lastTime = system.getTimer()
local function enterFrame()
local curTime = system.getTimer()
local dt = curTime - lastTime
lastTime = curTime
for i = allRectangles.numChildren, 1 do
local rect = allRectangles[i]
local dx = rect.rate * dt / 1000
rect.x = rect.x + dx
end
end
Runtime:addEventListener("enterFrame", enterFrame)
local function createRectangle()
local thisRectangle = display.newRect(1, 1, 216, 400)
thisRectangle.anchorX = 0
thisRectangle.lastTime = 0
thisRectangle.rate = 216
allRectangles:insert(thisRectangle)
end
timer.performWithDelay(1000, createRectangle, 0)
EDIT AFTER RE-EDIT of the post:
You have time set in enterFrame listener, but you don't actually know when it's going to be called. I would not count on the order of functions called during enterFrame stage.
If you don't need futher reference to rects use code below
local rand = math.random
local function rectangleLoop()
local thisRectangle = display.newRect(1, 1, 216, 400)
thisRectangle.anchorX = 0
thisRectangle:setFillColor(rand(), rand(), rand())
transition.to(thisRectangle, {time=5000,x=thisRectangle.x + 1080, onComplete=display.remove})
end
rectangleLoopTimer = timer.performWithDelay(985, rectangleLoop, 0)
Do you need use table to store rects?

Conversion of MetaTrader4 to NinjaTrader

I am trying to write an indicator originally from MT4 into NT7.
I have the following calculations in MT4:
dayi = iBarShift(Symbol(), myPeriod, Time[i], false);
Q = (iHigh(Symbol(), myPeriod,dayi+1) - iLow(Symbol(),myPeriod,dayi+1));
L = iLow(NULL,myPeriod,dayi+1);
H = iHigh(NULL,myPeriod,dayi+1);
O = iOpen(NULL,myPeriod,dayi+1);
C = iClose(NULL,myPeriod,dayi+1);
myperiod is a variable where I place the period in minutes (1440 = 1day).
What are the equivalent functions in NT7 to iBarShift, iHigh and so on?
Thanks in advance
For NinjaTrader:
iLow = Low or Lows for multi-time frame
iHigh = High or Highs
iOpen = Open or Opens
iClose = Close or Closes
So an example would be
double low = Low[0]; // Gets the low of the bar at index 0, or the last fully formed bar (If CalculateOnBarClose = true)
In order to make sure you are working on the 1440 minute time frame, you will need to add the following in the Initialize() method:
Add(PeriodType.Minute, 1440);
If there are no Add statements prior to this one, it will place it at index 1 (O being the chart default index) in a 2 dimensional array. So to access the low of the 1440 minute bar at index 0 would be:
double low = Lows[1][0];
For iBarShift look at
int barIndex = Bars.GetBar(time);
which will give you the index of the bar with the matching time. If you need to use this function on the 1440 bars (or other ones), use the BarsArray property to access the correct Bar object and then use the GetBar method on it. For example:
int barIndex = BarsArray[1].GetBar(time);
Hope that helps.

Creating buttons through iteration?

I've been using the Corona engine and I'm trying to create multiple buttons through a loop rather than explicitly creating each individual button. Problem is the loop only seems to be generating one button which suggests it's only iterating once.
Below is what I've got so far...
UPDATED
--> Create Level Selection:
local levelSelectionGroup = display.newGroup( );
--> Level Selected:
local function levelSelected()
print(id);
end
--> Button Creation:
local function createLevelSelection()
local levelsToBeMade = 30; -- Ignore these random numbers for now.
local positionX = 1; -- Ignore again.
local positionY = 1; -- Ignore again.
for buttonNumber=1, levelsToBeMade do
print(buttonNumber);
positionX = (positionX + 10); -- Ignore again.
positionY = (positionY + 10); -- Ignore again.
levelButton[buttonNumber] = widget.newButton{
id = buttonNumber,
label = buttonNumber,
default = "images/levelButton.png",
over = "images/levelButtonPressed.png",
width = 50,
height = 50,
onRelease = levelSelected
}
levelButton[buttonNumber].x = positionX;
levelButton[buttonNumber].y = positionY;
levelSelectionGroup:insert(levelButton[buttonNumber]);
end
end
The console states...
attempt to index global 'levelButton' (a nil value)
I guess you might have a problem with your variables or your scopes. So make sure that levelsToBeMade variable and positionX and positionY variables are correct. If you are absolutely sure, this should work: ( I don't see anything wrong in your code but, for loops are more trustable I guess. )
for i=1, levelsToBeMade do
print( "levelButton+1).." will be created." )
positionX = positionX + 10; -- Ignore numbers.
positionY = postionY + 10; -- Ignore numbers.
levelButton[#levelButton+1] = widget.newButton{
id = #levelButton,
label = #levelButton,
default = "images/levelButton.png",
over = "images/levelButtonPressed.png",
width = 50,
height = 50,
onRelease = levelSelected
}
levelButton[#levelButton].x = positionX;
levelButton[#levelButton].y = positionY;
end
If it doesn't work, just check console and see if the loop is executed desired times.
Last edit:
Oh, didn't notice that. You never created levelButton table before! Before starting to create level buttons you should create that like this: local levelButton = {}, at outside of for loop
You might want to reconsider your algorithm and change this while loop.
If the number of levels to be generated is going to stay constant you might want to do a for loop until the 31 st loop is reached.
for i=1,levelstToBeMade do
levelstToBeMade = (levelsToBeMade - 1); -- Ignore numbers.
positionX = positionX + 10; -- Ignore numbers.
positionY = postionY + 10; -- Ignore numbers.
levelButton[levelsToBeMade] = widget.newButton{
id = levelsToBeMade,
label = levelsToBeMade,
default = "images/levelButton.png",
over = "images/levelButtonPressed.png",
width = 50,
height = 50,
onRelease = levelSelected
}
levelButton[levelsToBeMade].x = positionX;
levelButton[levelsToBeMade].y = positionY;
end
Hope this helps.
Cheers
(Sorry, I don't know Corona so this might not apply.)
What is levelButton, and are you sure it exists? Maybe it should be levelButtons?
If that's fine as it is, then check to make sure newButton() actually returns a table as expected: print(levelButton[buttonNumber])

Resources