Creating buttons through iteration? - loops

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])

Related

Roblox infinite rotating loop

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).

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.

Lua/LOVE indexing problems

I'm getting a very irritating error whenever I do anything like this with arrays. I have code that sets up the array in the love.load() function:
function iceToolsInit()
objectArray = {} --for object handling
objectArrayLocation = 0
end
and then code that allows for the creation of an object. It basically grabs all of the info about said object and plugs it into an array.
function createObject(x, y, renderimage) --used in the load function
--objectArray is set up in the init function
objectArrayLocation = objectArrayLocation + 1
objectArray[objectArrayLocation] = {}
objectArray[objectArrayLocation]["X"] = x
objectArray[objectArrayLocation]["Y"] = y
objectArray[objectArrayLocation]["renderimage"] =
love.graphics.newImage(renderimage)
end
After this, an update function reads through the objectArray and renders the images accordingly:
function refreshObjects() --made for the update function
arrayLength = #objectArray
arraySearch = 0
while arraySearch <= arrayLength do
arraySearch = arraySearch + 1
renderX = objectArray[arraySearch]["X"]
renderY = objectArray[arraySearch]["Y"]
renderimage = objectArray[arraySearch]["renderimage"]
if movingLeft == true then --rotation for rightfacing images
renderRotation = 120
else
renderRotation = 0
end
love.graphics.draw(renderimage, renderX, renderY, renderRotation)
end
end
I of course clipped some unneeded code (just extra parameters in the array such as width and height) but you get the gist. When I set up this code to make one object and render it, I get this error:
attempt to index '?' (a nil value)
the line it points to is this line:
renderX = objectArray[arraySearch]["X"]
Does anyone know what's wrong here, and how I could prevent it in the future? I really need help with this.
It's off-by-one error:
arraySearch = 0
while arraySearch <= arrayLength do
arraySearch = arraySearch + 1
You run through the loop arrayLength+1 number of times, going through indexes 1..arrayLength+1. You want to go through the loop only arrayLength number of times with indexes 1..arrayLength. The solution is to change the condition to arraySearch < arrayLength.
Another (more Lua-ly way) is to write this as:
for arraySearch = 1, #objectArray do
Even more Lua-ly way is to use ipairs and table.field reference instead of (table["field"]):
function refreshObjects()
for _, el in ipairs(objectArray) do
love.graphics.draw(el.renderimage, el.X, el.Y, movingLeft and 120 or 0)
end
end
objectArray and movingLeft should probably be passed as parameters...

Corona SDK array index is beyond array bounds, advice needed

I will try to as concise as possible with my issue.
Firstly, files are:
block.lua
base.lua
main.lua
In block.lua I create a block, add collision detection and a cleanup code.
In base.lua I create a base made up of 4 columns and 10 rows. 40 blocks in total.
In main.lua I create 4 bases made from the base.class.
All is working fine once the game begins.
I remove the bases and call them again on level 2.
They create themselves ok BUT
when the enemy is destroyed once again, and the bases are to be rebuilt, I get an:
array index 1 is beyond array bounds:1..1
-- all the way up to--
array index 800 is beyond array bounds:1..159
it will then create the bases and continue until the enemys are destroyed and do the same again starting at :
array index 800 is beyond array bounds:1..159
-- all the way up to--
array index 4000 is beyond array bounds:1..159
The terminal points me at block.lua line 23
blockGroup:insert(blockNum,self.block)
Now I cant see anything wrong in the class, I have looked and googled for hours but all to no avail.
I would really appreciate a helping hand to guide me here please.
I have tried rewriting the "cleanup" etc but no joy.
I left a few commented out bits in there and removed some of the irrelevant stuff.
I post below the relevant code:
--MAIN.LUA--
function gameOver()
Runtime:removeEventListener("enterFrame", onEnterFrame)
Runtime:removeEventListener("enterFrame", movePlayer)
layers:removeSelf()
layers = nil
enemyCount = 0
for i = 1,#allEnemys do
timer.cancel(allEnemys[i].clock)
Runtime:removeEventListener( "enterFrame", allEnemys[i] )
display.remove(allEnemys[i].image)
allEnemys[i].image=nil
end
allEnemys=nil
cleanupBlocks()
end
----------------------------------------------------------------------
-- LEVEL UP --
----------------------------------------------------------------------
function levelUp(level)
enemyCount = 0
local enemys = require("modules.enemy")
if allEnemys ~= nil then
for i = 1,#allEnemys do
timer.cancel(allEnemys[i].clock)
Runtime:removeEventListener( "enterFrame", allEnemys[i] )
display.remove(allEnemys[i].image)
allEnemys[i].image=nil
end
end
allEnemys=nil
cleanupBlocks()
levels()
end
----------------------------------------------------------------------
-- LEVELS --
----------------------------------------------------------------------
function levels(level)
function createInvader(x, y, row)
for j = 1, 2 do
for i = 1, 2 do
if allEnemys == nil then
allEnemys = {}
else
enemysCount=#allEnemys
end
allEnemys[#allEnemys + 1] = enemys:new()
allEnemys[#allEnemys ]:init(i * 60, j * 70 + 70,j)
allEnemys[#allEnemys ]:start()
end
end
end
createInvader()
--[[function createBases1()
local base = require("modules.base")
for i = 1, 4 do
base:new()
base:init(i * 180 - 130, 850)
end
end ]]--
createBases()
end
--BLOCK.LUA--
local block = {}
local block_mt = { __index = block}
local scene = scene
local blockGroup = display.newGroup()
local blockNum = 0
function block:new() -- constructor
local group = {}
return setmetatable( group, block_mt )
end
function block:init(xloc,yloc) --initializer
-- Create attributes
self.block = display.newRect( xloc,yloc,10,10)
self.block:setFillColor ( 2, 255, 14 )
blockNum = blockNum + 1
blockGroup:insert(blockNum,self.block)
local blockCollisionFilter = { categoryBits = 128, maskBits = 387}
physics.addBody( self.block, "static", {filter = blockCollisionFilter})
self.count = 1
end
function cleanupBlocks()
--[[ print(blockNum, blockGroup.numChildren)
for i=1,blockGroup.numChildren do
blockGroup[1]:removeSelf()
blockGroup[1] = nil
end ]]--
print(blockNum, blockGroup.numChildren)
while blockGroup.numChildren>0 do
display.remove(blockGroup[1])
blockGroup[1]=nil
end
end
function block:start()
--- Create Listeneres
self.block:addEventListener( "collision", self )
scene:addEventListener('base_block_event', self)
end
return block
--BASE.LUA--
local base = {}
local base_mt = { __index = base}
local scene = scene
local block = require("modules.block")
function base:new() -- constructor
local group = {}
return setmetatable( group, base_mt )
end
function base:init(xloc, yloc) --initializer
-- Create attributes
local base
for j = 1, 4 do
for i = 1, 10 do
base = block:new()
base:init(xloc+i * 10,yloc+j * 10)
base:start()
end
end
end
return base
I see you use
blockNum = blockNum + 1
blockGroup:insert(blockNum,self.block)
Try to use
blockGroup:insert(self.block)
just to see if you still get that error.

Mom file creation (5 product limit)

Ok, I realize this is a very niche issue, but I'm hoping the process is straight forward enough...
I'm tasked with creating a data file out of Customer/Order information. Problem is, the datafile has a 5 product max limit.
Basically, I get my data, group by cust_id, create the file structure, within that loop, group by product_id, rewrite the fields in previous file_struct with new product info. That's worked all well and good until a user exceeded that max.
A brief example.. (keep in mind, the structure of the array is set by another process, this CANNOT change)
orderArray = arranyew(2);
set order = 1;
loop over cust_id;
field[order][1] = "field(1)"; // cust_id
field[order][2] = "field(2)"; // name
field[order][3] = "field(3)"; // phone
field[order][4] = ""; // product_1
field[order][5] = ""; // quantity_1
field[order][6] = ""; // product_2
field[order][7] = ""; // quantity_2
field[order][8] = ""; // product_3
field[order][9] = ""; // quantity_3
field[order][10] = ""; // product_4
field[order][11] = ""; // quantity_4
field[order][12] = ""; // product_5
field[order][13] = ""; // quantity_5
field[order][14] = "field(4)"; // trx_id
field[order][15] = "field(5)"; // total_cost
counter = 0;
loop over product_id
field[order[4+counter] = productCode;
field[order[5+counter] = quantity;
counter = counter + 2;
end inner loop;
order = order + 1;
end outer loop;
Like I said, this worked fine until I had a user who ordered more than 5 products.
What I basically want to do is check the number of products for each user if that number is greater than 5, start a new line in the text field, but I'm stufk on how to get there.
I've tried numerous fixes, but nothing gives the results I need.
I can send the entire file if It can help, but I don't want to post it all here.
You need to move the inserting of the header and footer fields into product loop eg. the custid and trx_id fields.
Here's a rough idea of one why you can go about this based on the pseudo code you provided. I'm sure that there are more elegant ways that you could code this.
set order = 0;
loop over cust_id;
counter = 1;
order = order + 1;
loop over product_id
if (counter == 1 || counter == 6) {
if (counter == 6) {
counter == 1;
order= order+1;
}
field[order][1] = "field(1)"; // cust_id
field[order][2] = "field(2)"; // name
field[order][3] = "field(3)"; // phone
}
field[order][counter+3] = productCode; // product_1
field[order][counter+4] = quantity; // quantity_1
counter = counter + 1;
if (counter == 6) {
field[order][14] = "field(4)"; // trx_id
field[order][15] = "field(5)"; // total_cost
}
end inner loop;
if (counter == 6) {
// loop here to insert blank columns and the totals field to fill out the row.
}
end outer loop;
One thing goes concern me. If you start a new line every five products then your transaction id and total cost is going to be entered into the file more than once. You know the receiving system. It may be a non-issue.
Hope this helps
As you put the data into the row, you need check if there are more than 5 products and then create an additional line.
loop over product_id
if (counter mod 10 == 0 and counter > 0) {
// create the new row, and mark it as a continuation of the previous order
counter = 0;
order = order + 1;
field[order][1] = "";
...
field[order][15] = "";
}
field[order[4+counter] = productCode;
field[order[5+counter] = quantity;
counter = counter + 2;
end inner loop;
I've actually done the export from an ecommerce system to MOM, but that code has since been lost. I have samples of code in classic ASP.

Resources