I have the following code :
{
identifier = "hand:" .. card.name,
area = { x, y, 100, 100 },
on_click = function()
-- Code goes here
end
}
I want to use the card variable and a reference to the object where this code is placed to modify a variable of the class with a value of the card variable.
So, how can I give parameters from the local context to the function who will be called in other pieces of code ?
I wish to launch the on_click function in an event management loop.
If I understand the question correctly, you want to be able to reference from on_click handler the object that on_click handler belongs to. To do this, you need to split the statement you have:
local card = { name = "my card" }
local object = {
identifier = "hand:" .. card.name,
area = { x, y, 100, 100 },
}
object.on_click = function()
-- Code goes here
-- you can reference card and object here (they are upvalues in this context)
print(card.name, object.area[3])
end
object.click()
You can also define on_click a bit differently; in this case you get object as implicitly declared self variable (note that you call it a bit differently too):
function object:on_click()
-- Code goes here
-- you can reference card and object here
print(card.name, self.area[3])
end
object:click() -- this is the same as object.click(object)
save it when you assign the function, like this
{
identifier = "hand:" .. card.name,
area = { x, y, 100, 100 },
on_click = function()
local a_card = card
print(a_card.name)
end
}
Related
I have been working on a survival game base on "Booga Booga" but i cant seem to find out how to load player data on the game. The data im trying to load is saved in the for loop that follows:
module.SaveData = function (player, DT)
local data_saved = {}
local setData = player.inventory.Inv:GetChildren()
for i, v in pairs(setData) do
table.insert(data_saved, {[v] = {
value = v.Value,
name = v.Name
}})
end
Data_Store:SetAsync(player.UserId, data_saved)
end
I've done multiple things to attempt to solve this problem
I've tried load with http service
I've already attempted loading the raw table
and I've tried to use a global data store instead
here is my code that loads the data as of now:
game.Players.PlayerAdded:Connect(function(plr)
CF.PlayerInventorySetup(plr) -- not relavent
p = plr -- not relavent
local PD =require(game.ServerScriptService.DataHandler)
local plrdata =PD.FetchData(plr)
for i, v in pairs(plrdata) do -- this is what im having trouble with
if not plr.inventory.Inv:FindFirstChild(v) then
local newint = Instance.new("NumberValue")
newint.Name = v.name -- the ouput says: string expected, got nil
newint.Value = v.value --
newint.Parent = plr.inventory.Inv
end
end
end)
I actually don't know wtf to do.
Before we talk about a solution, let's talk about what's happening when you save the data. Let's say for example, your inventory is a list of NumberValues like this :
Fish (value of 3)
Iron (value of 10)
Grass (value of 8)
Your FetchData function expects that the saved player data is formatted like this :
{
{ value = 3, name = "Fish" },
{ value = 10, name = "Iron" },
{ value = 8, name = "Grass" },
}
However, the result of the loop in the SaveData function would be this :
{
{ Fish(NumberValue) = { value=3, name="Fish" }},
{ Iron(NumberValue) = { value=10, name="Iron" }},
{ Grass(NumberValue) = { value=8, name="Grass" }},
}
On every step of the loop, you are pushing a new dictionary into the data_saved table.
The FetchData function expects that dictionary to have keys for "name" and "value". But, you've pushed that data one layer deeper, so those keys don't exist where the FetchData code expects them to and it throws errors.
So to fix your issue in the SetData function, remove the outer layer of that table, and just use the raw data.
table.insert(data_saved, {
value = v.Value,
name = v.Name
})
Edited for more details:
I'm trying to have a turtle that is sitting in front of a sapling wait for it to grow before cutting it down. It compares the log to the item in front until it matches. The system I'm currently using works, but I was hoping there was a slightly more minimal way to write it.
checkTarget = {
forward = function(tgt)
check = {turtle.inspect()} --creates table with first as boolean, second as information table
local rtn = {false, check[2]}
if type(tgt) == "table" then
for k, v in pairs(tgt) do
if check[2].name == v then
rtn = {true, v}
break
end
end
elseif tgt == nil then
return check[1]
elseif check[2].name == tgt then
rtn[1] = true
end
return rtn
end,--continued
This takes an argument, either a string or an array of strings, to compare against. When it checks the block in front it saves the detailed information to the second element in rtn and the first to a default of false. If the string matches the checked block's name, then it changes rtn[1] to true and returns all of it, which is the table at the bottom when doing checkTarget.forward("minecraft:log").
My question was, I am currently making a disposable variable to store the array that is returned from checkTarget, and then calling the variable's first element to get if it's true or not. I was hoping there was a way to include it in the if statement without the disposable variable (tempV)
repeat
local tempV = fox.checkTarget.forward("minecraft:log")
if tempV[1] then
cut()
fox.goTo({x = 0, y = 0, z = 0})
fox.face(0)
end
tempV = fox.checkTarget.forward("minecraft:log")
until not run
{
false,
{
state = {
stage = 0,
type = "birch",
},
name = "minecraft:sapling",
metadata = 2
}
}
Instead of
local tempV = fox.checkTarget.forward("minecraft:log")
if tempV[1] then
end
You can do
if fox.checkTarget.forward("minecraft:log")[1] then
end
and then calling the variable's first element to get if it's true or
not.
With tempV[1] you're not calling the first element, you're indexing it.
To call something you have to use the call operator () which doesn't make sense as a boolean is not callable.
No matter how I approach Lua, I run into this error all the time, so I must not understand something inherit to the language:
attempt to call method 'func' (a nil value)
I've seen the error here a few times as well but the problem doesn't seem clear to me.
Here's my module:
actor.lua
Actor = {
x = 0,
mt = {},
new = function()
local new_actor = {}
new_actor.x = Actor.x
new_actor.mt = Actor.mt
return new_actor
end,
test = function(self, a, b)
print(a, b)
end
}
I'm using Löve.
main.lua
require "game/actor"
local a = Actor:new() --works fine
function love.load()
a.x = 10
print(a.x) --output: 10
a:test(11, 12) --error: attempt to call method 'test' (a nil value)
end
I'm also not sure when it's appropriate to use the previous styling over this in a module.
Actor = {
x = 0
}
Actor.mt = {}
function Actor.new()
print(42)
end
I'm honestly not sure what is more correct than the other but considering I run into a simple error either way, there's probably something I'm missing entirely?
It looks like you're trying to instance a kind of class made of metatables. You basically need to assign new_actor's metatable with Actor.mt. (Resuming the problem: when you're indexing new_actor you're not indexing Actor in this case)
setmetatable(new_actor, Actor.mt);
Even if the metatable is being added, it won't work until you put the meta "__index" event to index a table containing your class methods/values, in this case:
Actor.mt = {
__index = Actor
};
I'd suggest moving your class methods/values into a new table, like Actor.prototype, Actor.fn, etc... avoiding conflicts:
Actor.fn = {
test = function(self, a, b)
print(a, b)
end
};
Actor.mt = {
__index = Actor.fn
};
More about metatables in Lua 5.3 manual.
Im just alittle curious, as well as a bit confused. In my lua code im setting a new object like so from the start.
enemy = {};
enemy.__index = enemy;
function enemy.new(args)
Obj = {};
setmetatable(Obj,enemy);
Obj.name = "bullet";
Obj.x = args.x;
Obj.y = args.y;
Obj.spriteTexFile= "Invader.png";
Obj.sprite = display.newImage( Obj.spriteTexFile);
Obj.sprite:setReferencePoint ( display.TopLeftReferencePoint );
Obj.sprite.x = Obj.x;
Obj.sprite.y = Obj.y;
Obj.sprite.alpha = 0;
Obj.health = 100;
Obj.activeBul = false;
Obj.bullet = Bullet.new({x=Obj.sprite.x,y=Obj.sprite.y});
return Obj;
end
...
return enemy;
end
So when instantiating a new Enemy obj I call the new function above. NOW in the same file, a function in the Enemy Object I have the following function for example which allows me to acces the "self.bullet", a Bullet Object created when the Enemy is created. It also allows me to call the function trajectBullet in this Bullet instants.
function enemy:shoot()
local Bullet = require "Bullet";
local DEFAULTTIME = 5;--Movement time per space
self.bullet:trajectBullet({x=self.sprite.x,y=display.contentHeight, time =
DEFAULTTIME*display.contentHeight-self.sprite.y)});
end
My Question comes with a call like the following. If I try setting a property of a Bullet in this case, the owner property, i get a nil error and wont let me change it. If someone could help me understand alittle how accessing keys and properties really works that would help me out alot.
function enemy:setBulletOwner()
self.bullet.owner = self;
end
UPDATE:
bullet = {};
bullet.__index = bullet;
function bullet.new(arg)
local Obj = {};
setmetatable ( Obj, bullet );
Obj.sprite = display.newRect( 0, 0, 3, 7 );
Obj.sprite.x = arg.x;
Obj.sprite.y = arg.y;
Obj.sprite:setFillColor ( 255, 255, 255 );
Obj.sprite:setReferencePoint ( display.TopLeftReferencePoint );
Obj.owner = nil;
return Obj;
end
function bullet:trajectBullet(arg)
self.sprite.tween = transition.to(self.sprite,{ tansistion = easing.outExpo, y = arg.y, x=arg.x,time= arg.time,onComplete = function() bullet:cancelTween(self.sprite);
self.owner.sprite:dispatchEvent( {name = "canShootAgain"} ); end});
end
Keep in mind Obj.owner should be getting set from the function below.
function enemy:setBulletOwner()
print("BULLET MADE");
self.bullet.owner = self;
end
You should have your classes set up like this
Bullet
Bullet = {}
Bullet_mt = { __index = Bullet }
function Bullet:new(co_ordinates)
local obj = {x=co_ordinates[1],y=co_ordinates[2]}
obj.owner = "You" --etc...
return setmetatable(obj,Bullet_mt)
end
Enemy
Enemy = {slogan="Gettm!'"}
Enemy_mt = {__index = Enemy;}
function Enemy:new(args)
local obj = {}
--etc..
obj.bullet = Bullet:new({0,0})
return setmetatable(obj,Enemy_mt)
--alert return setmetatable(obj,getmetatable(self))
end
function Enemy:getBulletOwner()
return self.bullet.owner;
end
You shouldn't be requiring "Bullet" each time the enemy shoots in enemy:shoot. When you want to create a bullet for an enemy if you only want the enemy to have one bullet you should
create a new 'instance' of the bullet class and associate it with the key bullet like you've been doing obj.bullet= Bullet.new(...) but also introduce this functionality into a method of Enemy (so you can add a new bullet after the old one goes out of range etc...).
If a index doesn't exist within a table, it will go looking for the index in the table associated with __index in the metatable assigned to the table in question. As an example say a = Enemy:new(), and we wanted to find out the slogan of the enemy, via a.slogan we would look for the index slogan in a but not find it. So we would then go check what __index was associated with in the metatable of a, in this case Enemy. So we look for slogan in Enemy, it exists so we end up with `"Gettm!'".
Adding the following code beneath the class definitions
en = Enemy:new()
print(en:getBulletOwner())
print(en.slogan)
Produces
You
Gettm!'
Also be weary of the difference between a:b(arg1,arg2) and a.b(arg1,arg2). a:b(arg1,arg2) is essentially equivalent to a.b(a,arg1,arg2) where a is bound to self within the function. An example of this would be:
print(en.getBulletOwner())
produces
lua: l.lua:22: attempt to index local 'self' (a nil value)
while
print(en:getBulletOwner())
produces
You
Below is a ES5 shim for JS binding.I dont understand self.apply in the bound function.
I know how to use apply method, but where is self pointing to in this case ? It it supposed to be a
function, but here self looks like an object.
if ( !Function.prototype.bind ) {
Function.prototype.bind = function( obj ) {
var slice = [].slice,
args = slice.call(arguments, 1),
self = this,
nop = function () {},
bound = function () {
return self.apply( this instanceof nop ? this : ( obj || {} ), // self in this line is supposed
to // represent a function ?
args.concat( slice.call(arguments) ) );
};
nop.prototype = self.prototype;
bound.prototype = new nop();
return bound;
};
}
self is being used in the shim you have listed to accommodate the fact that this changes along with scope changes. Within the direct scope of the Function.prototype.bind function this will refer to the object on which the bind function was called.
Once you enter the scope of the nested bound function this has changed; so the author has assigned self = this within the bind function to allow the value of this at the time bind is called to remain available to the bound function via lexical scoping (closure).
Scoping within JavaScript can get pretty complicated; for a detailed explanation take a look at this article.
Everything you wanted to know about JavaScript scope.
Have in mind that in javascript almost everything is an object.
So you have it right there:
self = this
So, self is not representing anything, self is the instance.