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
Related
I was going through Apple's Arkit project sample. I was trying to understand the code since, I am still learning. I saw a function setting it self equals to another function can someone please explain what these functions are exactly doing. Please brief in detail.In the code the "mutating func normalize()" is setting it self to self.normalized why is it. What this code is doing. Can we not simply call "func normalized()" seems like we are re-creating the same function.
mutating func normalize() {
self = self.normalized()
}
func normalized() -> SCNVector3 {
if self.length() == 0 {
return self
}
return self / self.length()
}
func length() -> CGFloat {
return sqrt(self.x * self.x + self.y * self.y)
}
Values types in Swift can be mutable and immutable . So when you create struct( or any other value type) and assign it to variable (var) it is mutable and you call normalize() on it. It means that struct won’t be copied to another peace of memory and will be updated in place (will act like reference type). But when you assign it to constant (let) - it can’t be mutated so the only way to update values in this struct is to create new one with updated values as with normalized() method. Regarding your question - normalize() is just reusing logic for normalizing vector from normalized(). So this is completely fine solution. Assigning to self is only permitted in mutable methods. It’s basically rewrites value of struct with new one.
I'm assuming that this fragment is in a struct rather than a class.
self.normalized() makes a copy of self and divides the copy's components by its length and then returns the copy. self is not affected.
self.normalize() gets a normalised version of self and then replaces self by the copy. So it changes in place.
Under the hood, every member function passes self as an implicit argument. i.e. to the compiler the declaration looks like this:
func normalised(self: SCNVector3) -> SCNVector3
Putting mutating on the front of a function definition makes the hidden argument inout
func normalise(self: inout SCNVector3)
So, if you have
var a = SCNVector3(3, 4, 0)
let b = SCNVector3(4, 3, 0)
let c = b.normalized()
a.normalize()
After that code, c would be (0.8, 0.6, 0) and a would be (0.6, 0.8, 0). b would be unchanged.
Note that a has to be declared with var because it is changed in place by normalise()
Edit
In the comments khan asks:
What i am not able to understand is why do we have to create a func again we can use "func normalized"
The point being made is why can't we do something like this:
var a = SCNVector3(3, 4, 0)
a = a.normalized()
and not have the normalise() function at all?
The above will have exactly the same effect as a.normalize() and, in my opinion[1], is better style, being more "functional".
I think a.normalize() exists only because it is common in Swift to provide both forms of the function. For example, with sets you have both union() and formUnion(): the first returns the union of one set with another, the second replaces a set with the union of itself and another set. In some cases, the in place version of the function may be more efficient, but not, I think, with this normalize function.
Which you choose to use is a matter of your preference.
[1] Actually, the better style is
let a = SCNVector3(3, 4, 0).normalized()
I have noticed a few people in the industry will use the self keyword even when not explicitly required (i.e. outside of closures).
Example:
import UIKit
import MapView
import CoreLocation
class viewController: UIViewController, MKMapViewDelegate, CLLocationDelegate {
let mapView = MKMapView()
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
self.mapView.delegate = self
self.mapView.showsUserLocation = true
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
}
}
Is there a tangible benefit to this, runtime-wise? Or is this purely a stylistic choice?
There is.
In the examples you provided it makes no difference, it's purely a style choice. Some people might like it since it explicitly tells you you're modifying self, personally I think it looks cleaner without.
Where it matters is when you have a local variable with the same name. Let's say you have a class that has a var count: Int property. Then, in one of your methods, you declare a new variable with the same name.
The local variable will be used whenever you type count, so if you want to modify or read the object's variable, you'll need to use self.
Some examples where it makes a difference:
guard let count = calculateCount() as? Int else { return }
self.count = count
init(count: Int) {
self.count = count
}
func updateCount(_ count: Int) {
self.count = count
}
Yes there are some benefits.
Using keywords like self or init or Swift prevent Xcode from ambiguity of overloads
make it compile faster
brings autocomplete suggestions faster;
that's it! Even though you use them explicitly, the compiler removes them from compiled code for compressing reasons. But it is not preferred! It's all about the scope of variables and functions.
Take a look at this example:
let name = "global variable"
class MyClass {
let name = "object variable"
func testScopes() {
let name = "function local variable"
print(name) //prints: function local variable
print(self.name) //prints: object variable
print(MyProject.name) // prints: global variable
}
}
let myObject = MyClass()
myObject.testScopes()
Here are three variables with three different valid scopes. You can refer to each one you need differently.
Swift community suggested:
For conciseness, avoid using self since Swift does not require it to access an object's properties or invoke its methods.
Use self only when required by the compiler (in #escaping closures, or
in initializers to disambiguate properties from arguments). In other
words, if it compiles without self then omit it.
But it's ultimately up to you and your company's code style guide.
Aside from the practical reason where it is required when there is a local variable or parameter with the same name, I do it because for a couple of reasons:
Habit from Objective-C
It explicitly shows me (and anyone else that looks at my code) that I am accessing a property, not a local variable; ie. this action may have consequences (or be influenced by events) outside of the current context.
My personal convention is to only use self in closures. For a few reasons.
It tells me, as a developer, that we are explicitly in a closure, because self is required.
self is very important in closures, and lets us know of possible retain cycles and memory leaks when we capture self strongly.
It is redundant when not in a closure, when there are not multiple variables of the same name inside the same or different scopes.
One thing I will say, when coding, using self. is a quick way to see what's available in the class or struct we are in. However, I will remove it after I find what I need.
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.
I have created a subclass of SKSpriteNode. I connect instances of that class together with joints of type SKPhysicsJointLimit. I do this within my didEndContact(contact: SKPhysicsContact) in my GameScene:
var joint = SKPhysicsJointLimit.jointWithBodyA(contact.bodyA, bodyB: contact.bodyB, anchorA: pos1!, anchorB: pos2!)
self.physicsWorld.addJoint(joint)
This works well so far.
Then i come to the point where i want to release the node from the joint. According to the SKPhysicsBody docs there is a property called "joints" which is an array holding SKPhysicsJoint objects. I thought thats exactly what I need, but I am not able to iterate over an instance's joints and remove them from the physicsWorld. To do the job i added a method to my custom SKSpriteNode subclass.
func freeJoints(world: SKPhysicsWorld){
if let joints = self.physicsBody?.joints {
for joint in joints{
println("found a joint: \(joint)")
// example print:
//found a joint: <PKPhysicsJointRope: 0x7fbe39e95c50>
world.removeJoint(joint as SKPhysicsJoint)
}
}
}
Calling the method fails after the println() statement with the message "Swift dynamic cast failed". I would really appreciate your opinion in how to work with an SKPhysicsBody's joint property. More specifically: How to use (cast?) the items in the array to be able to remove them from a scene's SKPhysicsWorld.
I spent a little more time in investigating this. This is what I have come up with:
I decided to add an property to my SKSpriteNode subclass and manage the joints myself
var joints: [SKPhysicsJointLimit]
override init(){
...
self.joints = []
...
}
Everytime I add an joint to the scene's SKPHysicsWorld I also add it to the joints array of the SKNNode itself. Whilst iterating the SKPHysicsBody's joints-Array failed (see question) at the point I wanted to cast it to SKPhysicsJoint, removing items from the physics world works as intended when iterating the array of SKPhysicsJointLimit items:
func freeJoints(world: SKPhysicsWorld){
for item in self.joints{
println("removing item from physics world \(item)")
world.removeJoint(item)
}
self.joints.removeAll(keepCapacity: false)
}
}
This seems not to be the most elegant way to do the job, since there already is a framework managed array that promises to be same thing. But I was unable to utilize it and this works for now.
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.