Having trouble using multiple objects - lua

question about OOP here.
Invader = {PosX = 5, PosY = 5, alive = true}
function Invader:new(x, y)
-- local InvaderImage = paintUtils.loadImage("")
self.__index = self
self.PosX = x
term.setCursorPos(self.PosX, self.PosY)
write("V")
function refreshInvader()
write("moved")
term.setCursorPos(self.PosX, self.PosY)
write(" ")
self.PosX = self.PosX + 3
term.setCursorPos(self.PosX, self.PosY)
write("V")
end
end
If i were to call refreshInvader, only the latest one i created would move. Is there anyway to move all?

You only have one Invader table. All your operations refer to self which is Invader
At no point in your code you create a second table that would serve as a "new object".
You would have to do something like this in order to get multiple objects:
Pet = {}
function Pet:new(name, sound)
self.__index = self
local newObject = setmetatable({}, self)
newObject.name = name or "unnamed"
return newObject
end
local a = Pet:new("Snuggles")
local b = Pet:new("Nibbles")

Related

Adding objects to array on Lua

First of all I'm new on lua, I'm trying to implement a simple shopping cart as an object oriented exercise.
So I defined a Cart Object which stores several items objects
Cart = {
items = {},
discount = 0
}
function Cart:new(discount)
local object = {}
setmetatable(object, {__index = self})
self.discount = discount
return object
end
function Cart:addItem(item)
table.insert(self.items, item)
end
function Cart:GetTotal()
local total = 0
for i = 1, #self.items do
total = total + self.items[i]:GetPrice()
end
return total - self.discount
end
Each Item has the responsibility of calculate their price:
Item = {
units = 0,
pricePerUnit = 5,
name = ""
}
function Item:new(units, pricePerUnit, name)
local object = {}
setmetatable(object, {__index = self})
self.units = units
self.pricePerUnit = pricePerUnit
self.name = name
return object
end
function Item:GetPrice()
return self.units * self.pricePerUnit
end
But when I create the object and add items I get 60 as result, When I debugged the script I found that all the elements of the table are identical as if they were overwritten, could someone explain to me why and how can it be solved? Thanks in advance.
local shoppingCart = Cart:new(0)
shoppingCart:addItem(Item:new(1, 10, "Oranges"))
shoppingCart:addItem(Item:new(1, 15, "lemons"))
shoppingCart:addItem(Item:new(1, 20, "Strawberries"))
print(shoppingCart:GetTotal())
Cart:new and Item:new are meant to create new objects, therefore you call them on the classes themselves rather than on instances. That means the self that gets passed to those methods is those classes.
In both of those methods, you create an object table to become the new object, so you need to set the fields on that object, instead of modifying the class, eg, object.discount = discount.

How can I merge two tables like this? - Lua

I have these tables set like this
local tableone = {["Gold"] = 10, ["Gem"] = 5}
local tabletwo = {["Level"] = 1}
This is the code for merging
local test = {tableone, tabletwo}
print(test)
But if I try to merge the tables then the output is like this
[1] = {
["Gold"] = 10,
["Gem"] = 5
},
[2] = {
["Level"] = 1
}
And I would like to have the output like this
[1] = {
["Gold"] = 10,
["Gem"] = 5,
["Level"] = 1
}
Is this possible?
Sorry if I'm not that good at explaining.
You can do this with a simple nested loop.
local function merge(...)
local result <const> = {}
-- For each source table
for _, t in ipairs{...} do
-- For each pair in t
for k, v in pairs(t) do
result[k] = v
end
end
return result
end
local t <const> = {merge(tableone, tabletwo)}
I put the result in a table constructor due to the [1] in the question.

dictionary help/DataStore

The Issue is I have a dictionary that holds all my data and its supposed to be able to turn into a directorys in replicated storage with all the values being strings then turn back into a dictionary with all the keys when the player leave. However, I cant figure out how to turn into a dictionary(With keys).
ive sat for a few hours testing things but after the first layer of values I cant get figure out a way to get the deeper values and keys into the table
local DataTable =
{
["DontSave_Values"] =
{
["Stamina"] = 100;
};
["DontSave_Debounces"] =
{
};
["TestData"] = 1;
["Ship"] =
{
["Hull"] = "Large_Ship";
["Mast"] = "Iron_Tall";
["Crew"] =
{
["Joe One"] =
{
["Shirt"] = "Blue";
["Pants"] = "Green"
};
["Joe Two"] =
{
["Shirt"] = "Silver";
["Pants"] = "Brown";
["Kids"] =
{
["Joe Mama1"] =
{
["Age"] = 5
};
["Joe Mama2"]=
{
["Age"] = 6
};
}
};
}
};
["Level"] =
{
};
["Exp"] =
{
};
}
------Test to see if its an array
function isArray(Variable)
local Test = pcall(function()
local VarBreak = (Variable.." ")
end)
if Test == false then
return true
else
return false
end
end
------TURNS INTO FOLDERS
function CreateGameDirectory(Player, Data)
local mainFolder = Instance.new("Folder")
mainFolder.Parent = game.ReplicatedStorage
mainFolder.Name = Player.UserId
local function IterateDictionary(Array, mainFolder)
local CurrentDirectory = mainFolder
for i,v in pairs(Array) do
if isArray(v) then
CurrentDirectory = Instance.new("Folder", mainFolder)
CurrentDirectory.Name = i
for o,p in pairs(v) do
if isArray(p) then
local TemporaryDir = Instance.new("Folder", CurrentDirectory)
TemporaryDir.Name = o
IterateDictionary(p, TemporaryDir)
else
local NewValue = Instance.new("StringValue", CurrentDirectory)
NewValue.Name = o
NewValue.Value = p
end
end
else
local value = Instance.new("StringValue", mainFolder)
value.Name = i
value.Value = v
end
end
end
IterateDictionary(Data, mainFolder)
end
------To turn it back into a table
function CreateTable(Player)
local NewDataTable = {}
local Data = RS:FindFirstChild(Player.UserId)
local function DigDeep(newData, pData, ...)
local CurrentDir = newData
for i,v in pairs(pData:GetChildren()) do
if string.sub(v.Name,1,8) ~= "DontSave" then
end
end
end
DigDeep(NewDataTable, Data)
return NewDataTable
end
I expected to when the player leaves run createtable function and turn all the instances in replicated storage back into a dictionary with keys.
Why not just store extra information in your data table to help make it easy to convert back and forth. As an example, why not have your data look like this :
local ExampleData = {
-- hold onto your special "DON'T SAVE" values as simple keys in the table.
DONTSAVE_Values = {
Stamina = 0,
},
-- but every element under ReplicatedStorage will be used to represent an actual Instance.
ReplicatedStorage = {
-- store an array of Child elements rather than another map.
-- This is because Roblox allows you to have multiple children with the same name.
Name = "ReplicatedStorage",
Class = "ReplicatedStorage",
Properties = {},
Children = {
{
Name = "Level",
Class = "NumberValue",
Properties = {
Value = 0,
},
Children = {},
},
{
Name = "Ship",
Class = "Model",
Properties = {},
Children = {
{
-- add all of the other instances following the same pattern :
-- Name, Class, Properties, Children
},
},
},
}, -- end list of Children
}, -- end ReplicatedStorage element
};
You can create this table with a simple recursive function :
-- when given a Roblox instance, generate the dataTable for that element
local function getElementData(targetInstance)
local element = {
Name = targetInstance.Name,
Class = targetInstance.ClassName,
Properties = {},
Children = {},
}
-- add special case logic to pull out specific properties for certain classes
local c = targetInstance.ClassName
if c == "StringValue" then
element.Properties = { Value = targetInstance.Value }
-- elseif c == "ADD MORE CASES HERE" then
else
warn(string.format("Not sure how to parse information for %s", c))
end
-- iterate over the children and populate their data
for i, childInstance in ipairs(targetInstance:GetChildren()) do
table.insert( element.Children, getElementData(childInstance))
end
-- give the data back to the caller
return element
end
-- populate the table
local Data = {
ReplicatedStorage = getElementData(game.ReplicatedStorage)
}
Now Data.ReplicatedStorage.Children should have a data representation of the entire folder. You could even save this entire table as a string by passing it to HttpService:JSONEncode() if you wanted to.
When you're ready to convert these back into instances, use the data you've stored to give you enough information on how to recreate the elements :
local function recreateElement(tableData, parent)
-- special case ReplicatedStorage
if tableData.Class == "ReplicatedStorage" then
-- skip right to the children
for i, child in ipairs(tableData.Children) do
recreateElement(child, parent)
end
-- quick escape from this node
return
end
-- otherwise, just create elements from their data
local element = Instance.new(tableData.Class)
element.Name = tableData.Name
-- set all the saved properties
for k, v in pairs(tableData.Properties) do
element[k] = v
end
-- recreate all of the children of this element
for i, child in ipairs(tableData.Children) do
recreateElement(child, element)
end
-- put the element into the workspace
element.Parent = parent
end
-- populate the ReplicatedStorage from the stored data
recreateElement( Data.ReplicatedStorage, game.ReplicatedStorage)
You should be careful about how and when you choose to save this data. If you are playing a multiplayer game, you should be careful that this kind of logic only updates ReplicatedStorage for the first player to join the server. Otherwise, you run the risk of a player joining and overwriting everything that everyone else has been doing.
Since there isn't a way to iterate over properties of Roblox Instances, you'll have to manually update the getElementData function to properly store the information you care about for each type of object. Hopefully this helps!
If anyone else has this problem the solution I used was just to convert the instances strait into JSON format(I used the names as keys). so that way I can save it, and then when the player rejoins I just used JSONDecode to turn it into the dictionary I needed.
function DirToJSON(Player)
local NewData = RS:FindFirstChild(Player.UserId)
local JSONstring="{"
local function Recurse(Data)
for i, v in pairs(Data:GetChildren()) do
if v:IsA("Folder") then
if #v:GetChildren() < 1 then
if i == #Data:GetChildren()then
JSONstring=JSONstring..'"'..v.Name..'":[]'
else
JSONstring=JSONstring..'"'..v.Name..'":[],'
end
else
JSONstring=JSONstring..'"'..v.Name..'":{'
Recurse(v)
if i == #Data:GetChildren()then
JSONstring=JSONstring..'}'
else
JSONstring=JSONstring..'},'
end
end
else
if i == #Data:GetChildren()then
JSONstring=JSONstring..'"'..v.Name..'":"'..v.Value..'"'
else
JSONstring=JSONstring..'"'..v.Name..'":"'..v.Value..'",'
end
end
end
end
Recurse(NewData)
JSONstring = JSONstring.."}"
return(JSONstring)
end

Lua, is this possible?

I am working on a game using love2d and i haven't quite programmed in lua. Not sure on technical wording so i'll post my code and explain what i'm trying to do:
item = {}
item.stat = {}
player.x = 100
player.y = 100
--
item[0].stat.damage = 10
What i'm trying to do is make an inventory system and an item database. I want to be able to make the item database with the code above so i could add an item like so:
item[1].stat.damage = 10
item[1].stat.speed = 10
item[2].stat.damage = 20
item[2].stat.speed = 5
--
player.inventory[0] = item[1]
player.inventory[1] = item[2]
can someone tell me what coding principle this may so i can research it? I basically want to make a matrix that i can access like above while having the convenience of named arrays instead of saying item[1,"damage"] = 10
Edit:
I realise now i can do item.stat.damage[1] = 10 but i have to setup an array for each one, is there an easier way?
Simply use tables:
player = {}
player.x = 100
print(player.x) -- prints 100
Note that player.x is simply syntactic sugar for player["x"], so the following lines are equivalent:
print(player.x) -- prints 100
print(player["x"]) -- also prints 100
With that in mind, you could construct your game data like this for example:
item = {}
item[1] = {}
item[1].stat = {}
item[1].stat.damage = 10
item[1].stat.speed = 10
item[2] = {}
item[2].stat = {}
item[2].stat.damage = 20
item[2].stat.speed = 5
player = {}
player.x = 100
player.y = 100
player.inventory = {}
player.inventory[1] = item[1]
player.inventory[2] = item[2]
print(player.inventory[2].stat.damage) -- prints 20
print(player["inventory"][2]["stat"]["damage"]) -- equivalent, also prints 20
It is probably a good idea to define functions that create items or players and automatically set all the required fields.
Eventually, you may want to use actual classes and objects (for example, if you want to define methods on your objects).
EDIT:
Here is the example from above with functions create_item, create_player to create items or players. I've used named parameters for these functions so one doesn't have to remember the order of the function parameters (note the curly braces when calling the functions).
function create_item(arg)
local item = {}
item.stat = {}
item.stat.damage = arg.damage
item.stat.speed = arg.speed
return item
end
function create_player(arg)
local player = {}
player.x = arg.x
player.y = arg.y
player.inventory = {}
return player
end
item = {}
item[1] = create_item{damage=10, speed=10}
item[2] = create_item{damage=20, speed=5}
player = create_player{x=100, y=100}
player.inventory[1] = item[1]
player.inventory[2] = item[2]
print(player.inventory[2].stat.damage) -- prints 20
print(player["inventory"][2]["stat"]["damage"]) -- equivalent, also prints 20
You can always shorten your code:
item = {
stat = {},
[0] = { stat = { damage = 10 } },
[1] = { stat = { damage = 10, speed = 10 } },
[2] = { stat = { damage = 20, speed = 5 } },
}
player = { x = 100, y = 100, inventory = { [0] = item[1], [1] = item[2] } }
You can access that code in matrix way like
function item:getstat(index, param)
return self[index] and self[index].stat and self[index].stat[param];
end
function item:setstat(index, param, value)
local t1 = self[index]
if (t1 == nil) then
t1 = {}
self[index] = t1
end
local t2 = t1.stat
if (t2 == nil) then
t2 = {}
t1.stat = t2
end
t2[param] = value
end
print(item:getstat(0, "damage"))
item:setstat(1, "speed", 20)

why doesnt my lua class implementation work?

I have implemented OOP in my lua environment but it doesnt seem to be working.
I think it has something to do with how i am handling the __index and my improper use of require and module but I'm not 100% sure.
Here is the code:
Class = function( prototype )
local derived = {}
local derivedMT = {
--When indexing into a derived class, check the base class as well
__index = prototype,
--When invoking a class, return an instance
__call = function( proto, ... )
local instance = {}
local instanceMT = {
--When indexing into an instance, check the class hierarchy as well.
__index = derived,
--Calling instances is a no-no!
__call = function()
print( "WARNING! Attempt to invoke an instance of a class!" )
print( debug.traceback() )
return instance
end,
}
setmetatable( instance, instanceMT )
if ( instance.__constructor ) then
instance:__constructor( ... )
end
return instance
end,
}
setmetatable( derived, derivedMT )
return derived
end
And here is how I use it, the nil reference is a call to a base class function, that is the error/problem im having is it seems like the base class isn't being referenced.
require "Core.Camera.FreeCamera"
local T = Core.Camera.FreeCamera.FreeCamera(0,0,-35)
c = T:getObjectType() -- nil reference
print(c .." --Type" )
and here is Camera.lua the base class
local _G = _G
module(...)
local M = _G.Class()
Camera = M
function M:__constructor(x,y,z) --This never gets called.
--self.Active = false
--self.x = x
--self.y = y
--self.z = z
--self.ID = EngineManager:getCamera()
print("InCameraInstance_-_-_-_-_-__-_--_-__-_-_-_--_-_-_-_-_--_-_-_--_--__-_---_--_---__-")
end
function M:getObjectType()
return "camera"
end
And Finally Free Camera which attempts to inherit Camera.
local require = require
local _G = _G
module(...)
require "Core.Camera.Camera"
local M = _G.Class( _G.Core.Camera.Camera ) --Gross, lame might be the culprit
FreeCamera = M
function M:__constructor(x,y,z) ---WHOOPS, this does get called... the other one doesnt
self.Active = false
self.x = x
self.y = y
self.z = z
self.ID = _G.EngineManager:getCamera()
--_G.print("got Id of:" .. self.ID)
self:setCameraPosition(x, y, z, self.ID)
_G.print("<<<Camera in lua>>>")
end
I'm running out of ideas. any help would be appreciated.
Instead of:
local M = _G.Class( _G.Core.Camera.Camera )
you need to have:
local M = _G.Class( _G.Core.Camera.Camera.Camera )
First Camera is the directory name, second is the module name, third is the class name.
Edit: You can clean it up a bit like this:
local CameraModule = require "Core.Camera.Camera"
local M = _G.Class( CameraModule.Camera )

Resources