Adding to sceneGroup - Attempt to index global 'self' (a nil value) - coronasdk

Yet another problem with sceneGroup.
local function addScore (event)
local sceneGroup = self.view -- where the error is
then later:
sceneGroup:insert( scoreStars )
local sceneGroup = self.view under scene:create, under sceneLshow(event), local sceneGroup = self.view, scene:hide( event ) and at the start of the lua file.

In functions like scene:something you get hidden parameter self which reference to scene itself. In those cases scene == self. Outside of those functions you need use scene.view assuming scene object exists. So in addScore function use scene.view instead of self.view.
More information you find in Understanding the colon vs. dot operator or Introducing the Composer API.

Related

Love 2D(Lua) unexpected nil in object

Trying to get my feet wet with LUA and Love2D, and I am having an issue with object instantiation / access in Lua.
Source with the bug can be found here: https://bitbucket.org/dannsee/love_scrollingshooter
I am In my main, I create an object, Enemies
enemies = Enemies:new()
and inside of the enemies object, i create an object to hold peristant values, which I am calling Timers.
timers = Timers:new()
So the enemies 'constructor' method looks (basically) like this
Enemies = {} -- so that Enemies will not be nil when new() is called
timers = {} -- so that timers will be accessible in the class scope
function Enemies:new(enemies)
enemies = enemies or {}
timers = Timers:new()
setmetatable(enemies, self)
self.__index = self
return enemies
end
while the Timers being created are looking as such
Timers = {} -- so that Timers will not be nil when new() is called
function Timers:new(timers)
timers = timers or {
miniBombTimerMax = 0.2,
miniBombTimer = minibombTimerMax
}
setmetatable(timers, self)
self.__index = self
return timers
end
But when I try to refrence one of the timers ( from inside the enemies object) , I am getting a nil value exception.
timers.miniBombTimer -- Produces nil exception
It seems to me that this should both 1. be in scope, since it is an object created inside this class, and is instantiated locally as timers = {} before it is assigned a value, and 2. not nil becuase it is being given a value in the 'constructor'. But it seems there is more going on here that I am not grasping.
I am new to Lua, which may be obvious at this point, but from what I have read about variable scope it seems that this should be valid. I don't understand why the timers are not being created with values.
Careful with your globals! In Lua, it's very easy to accidentally set a global variable when you don't mean to, and it looks like that's exactly what's happening.
function Enemies:new(enemies)
enemies = enemies or {}
timers = Timers:new()
setmetatable(enemies, self)
self.__index = self
return enemies
end
On the third line here, since timers doesn't exist as a local variable here, this value ends up getting put into a global variable called timers instead. If you want to set a property of enemies, you need to mention enemies explicitly:
function Enemies:new(enemies)
enemies = enemies or {}
enemies.timers = Timers:new()
setmetatable(enemies, self)
self.__index = self
return enemies
end
Now, you write:
But when I try to refrence one of the timers ( from inside the enemies object) , I am getting a nil value exception.
Lua doesn't really have any concept of being "inside an object" or "inside a class". In some languages, when you're writing code inside of a class, all of the class's members are in scope and you can refer to them "bare". Lua is not one of those languages; in Lua, if you want to refer to a "class member", you need to use the dot notation, explicitly stating which object you're accessing. (Or you can do the "advanced method", using _ENV.)
By the way...
timers = {} -- so that timers will be accessible in the class scope
From what I see in the question, this line doesn't do much; it just creates a global variable which is never used.
Also, this line in Enemies:new:
self.__index = self
This just sets Enemies.__index every time Enemies:new is called. This is fine, but you may as well just set it once:
function Enemies:new(enemies)
enemies = enemies or {}
enemies.timers = Timers:new()
setmetatable(enemies, self)
return enemies
end
Enemies.__index = Enemies

Why do I keep getting this error when I try to sequence my actions in Swift?

This is the error I get. I have a sequence that Im using so I could call the actions in order. I put the function addGameBall() in a runBlock so I could have that action finish last. Is that the correct way to do that. Here is the code I have: What am I doing wrong? Thanks!
Attemped to add a SKNode which already has a parent
//RightSide
if firstBody.categoryBitMask == GameBallCategory && fourthBody.categoryBitMask == WallCategpory {
println("GoalRight")
let waitBall = SKAction.waitForDuration(1.0)
let removeFromParent = SKAction.removeFromParent()
let respawnBall = SKAction.runBlock(self.addGameBall)
let sequenceThis = SKAction.sequence([waitBall, removeFromParent, respawnBall])
runAction(sequenceThis)
}
"Attempting to add a sknode which already has a parent" means you're adding a node twice. I can't see your addGameBall code but i'm pretty confident you have a line in their that says. self.addChild(ball)//or whatever your code is called.Everytime this functions runs, the line is executed so the same reference to the ball node is added multiple times which is why the compiler is complaining. The problem could be solved by declaring ball as a local variable so that when the function runs, a new reference to the node is being created. Happy coding.

How do I fix my string issue?

local background = display.newImage("black.png", 0, 0)
local submit = display.newImage("submit.png")
submit.x = display.contentWidth/2
submit.y = display.contentHeight-100
local nameInstructions = display.newText("Enter your name", 10, 50, native.systemFont, 24)
local usersName = native.newTextField(10, 100, 350, 50)
usersName.inputType = "default"
local function keyboardListener (event)
native.setKeyboardFocus(nil)
end
background:addEventListener("tap", keyboardListener)
local function reverseName(event)
reverseUsersName = string.reverse(usersName)
end
submit:addEventListener("tap", reverseName)
local reverse = display.newText(reverseUsersName)
reverse.x = display.contentWidth/2
reverse.y = display.contentHeight/2
Every time that I run this using my Corona SDK thing, I get this:
Bad argument #-1 to 'newText' (string expected, got nil)
stack traceback:
[C]: ?
[C]: in function 'newText'
...Corona Projects/Assignment 4.3/main.lua/src/main.lua:24: in main chunk
reverseName is in the local function reverseName(event), but this function is called once u press or tap on the submit . But here local reverse = display.newText(reverseUsersName), is called before you tap on the sumbit . That is why its giving you error.
The only place that reverseUsersName, accessed on line 24, is set, is inside the function reverseName(event). In this function, reverseUsersName is a global so after the function is run once, that variable will be accessible from other parts of your script, but until then, it does not exist.
Now in line 22 you've registered reverseName as event listener for "tap" events, but events are only generated after your script has been executed once (and in between calls to your script callbacks like reverseName and keyboardListener are callbacks), so when you create the display text just after, the variable does not yet exist.
So what you would have to do is update the text of the reverse display item in your reverseName listener so that every time you click on the button, the reversed name becomes visible. And because of that, you would have to declare your reverse variable above reverseName function so that it is available as an upvalue (read the Corona getting started docs, they are excellent and discuss this subtlety) in that function. And presumably you would want to initialize with showing the usersName rather than reverse.
So you would need something like
local reverse = display.newText(usersName)
local function reverseName(event)
reverseUsersName = string.reverse(usersName)
reverse.SetText(reverseUserName)
end
submit:addEventListener("tap", reverseName)
Note that if you want the string being displayed to be reversed every time you press tap, rather than only first time you press it, you will have to use
local function reverseName(event)
reverseUsersName = string.reverse(reverseUsersName)
reverse.SetText(reverseUserName)
end
reverseUsersName = usersName
Check your function reverseName and the text object(reverse) with the following code:
local reverse --[[ Initialize the object with a global scope,
so you can access it anywhere from the page. --]]
local function reverseName(event)
--[[ In the below line, usersName is a table value. It is the reason
of the error. For getting the string from the text field, you
have to provide 'usersName.text' --]]
reverseUsersName = string.reverse(usersName.text)
reverse.text = reverseUsersName -- Assign the text field value to your text object
end
submit:addEventListener("tap", reverseName)
reverse = display.newText("",20,20,nil,20) --see the parameters of display.newText()*
reverse.x = display.contentWidth/2
reverse.y = display.contentHeight/2
*Corona API: display.newText()

Why attempt to index global (a nil value) Lua?

Actually I'm working from a tutorial and there is some error in that tutorial.
There is the code:
class "Game"( Graphics )
Game.menuScreen = nil
Game.gameScreen = nil
Game.achScreen = nil
Game.screen = nil
-- main
function Game:main()
-- Create the screens and store their links within the class
Game.menuScreen = MainMenu.new()
Game.gameScreen = GameScreen.new()
Game.achScreen = AchScreen.new()
-- Display menuScreen
Game.showScreen( 'menuScreen' )
end
-- showScreen
function Game.showScreen( name )
-- If a screen is being displayed - remove it from the stage
if Game.screen then
Stage.detach( Game.screen )
Game.screen = nil
end
-- Retrieve a screen link by name
local screen = Game[name]
if not screen then
return nil
end
-- If the screen is found - add it to the stage
Stage.attach( screen )
-- Save the displayed screen
Game.screen = screen
return screen
end
It write to me [string "Game.script"]:11: attempt to index global 'MainMenu' (a nil value)
I use Dreemchest Composer and this one is the tutirul: http://dreemchest.com/doc/en/Game%20menu%20and%20screen.html
Actually I remowed the LEVEL select screen from this code, cos I don't want to implement a level selection to my first game in this.
I have a script named MainMenu and it's class's MainMenu, Superclass is soMainMenu.
I have got it, thank you!
I had to create Stage Objects for all menu points to get it work. It's easy but the tutorial may didn't wrote it or I just didn't understand it.

How to use a value in a table inside itself (Lua language)?

I have a lua table like this:
local defaultSize = 14
local field = {
sizeA = defaultSize,
sizeB = sizeA,
}
My intention is to set sizeB to the value of field.sizeA, however the code above does not work. field.sizeB is nil in this case.
How to set sizeB to whatever sizeA is inside the table definition directly?
You could have an init function in table and call that:
local defaultSize = 14
local field = {
init = function (self, size)
self.sizeA = size or defaultSize -- size only if given, otherwise defaultSize
self.sizeB = self.sizeA
end
}
field:init() -- implicit "self" arg is "field", defaultSize will be used
field:init(16) -- size will be 16 rather than 14
print(field.sizeB) -- prints 14
This has the clear advantage of aggregating all initialization of table instance in one place, you can have conditionals etc once your logic gets more complex. You don't have to have init() as member of table, but it is always a good idea to keep dependencies obvious and close together.

Resources