Page 1 of 2
Linking Entities
Posted: Mon Sep 25, 2023 3:22 pm
by Bobble68
Hi all!
So I'm trying to make a basic logic system for my game to make puzzles (e.g. press a button entity somewhere, door opens), however I'm realising I need a way to actually link the entities together.
My first instinct was to just have an 'activation' attribute that you would paste the table hex code of the target entity, however I realise that won't work after reloading the game as all the tables would have different codes.
My next thought was to use my ID system that gets saved with the entity, but I realised that as is it would have to iterate through the whole entity table to find the correct ID (I can't use the ID as a table key since things might be loaded in a different order).
Is there a better way of doing this kind of thing?
Re: Linking Entities
Posted: Mon Sep 25, 2023 3:55 pm
by pgimeno
What I do in these cases is build two tables, one for data and one for lookups. As you add ids to one table, you add them as key to another table with the number as data. Then you can use that second table to look up the index of a specific id.
Re: Linking Entities
Posted: Mon Sep 25, 2023 4:12 pm
by Bobble68
pgimeno wrote: ↑Mon Sep 25, 2023 3:55 pm
What I do in these cases is build two tables, one for data and one for lookups. As you add ids to one table, you add them as key to another table with the number as data. Then you can use that second table to look up the index of a specific id.
Ooooh hadn't throught of that - though wouldn't it still need to check for existing IDs when creating a new entity? If an entity is removed, there will be a gap in the ID table that, unless I'm misunderstanding?
Re: Linking Entities
Posted: Mon Sep 25, 2023 4:37 pm
by dusoft
Bobble68 wrote: ↑Mon Sep 25, 2023 4:12 pm
pgimeno wrote: ↑Mon Sep 25, 2023 3:55 pm
What I do in these cases is build two tables, one for data and one for lookups. As you add ids to one table, you add them as key to another table with the number as data. Then you can use that second table to look up the index of a specific id.
Ooooh hadn't throught of that - though wouldn't it still need to check for existing IDs when creating a new entity? If an entity is removed, there will be a gap in the ID table that, unless I'm misunderstanding?
There might be a gap, but if you are using
function, that will close the gap automatically, see:
https://www.lua.org/pil/19.2.html
The table.remove function removes (and returns) an element from a given position in an array, moving down other elements to close space and decrementing the size of the array. When called without a position, it removes the last element of the array.
You can also work with metatables, see:
https://ebens.me/post/lua-metatables-tutorial/
Specifically, check these functions:
and customize them to check e.g. for duplicates or else to suit your needs.
Re: Linking Entities
Posted: Mon Sep 25, 2023 4:50 pm
by Endaris
There's probably a dozen ways to implement that and what works best depends on how you designed the rest of your game.
My instinct would be to simply give the button an onActivation field that is called as a function when the button is pressed. And then assign the opening function for the specific door the button should open/close when your level gets loaded to onActivation. And then instead of a door, onActivation could also activate a trap. Or do anything really because you can assign any function to it.
Whatever you do, try to not overthink and link too much, at the end of the day you'll have to specify explicitly what button does what in your level loader (or something similar) anyway. If you make things too implicit you'll end up with buttons that can only open doors and nothing else and that would be a bit boring in the long run, wouldn't it ;-)
Bobble68 wrote: ↑Mon Sep 25, 2023 4:12 pm
pgimeno wrote: ↑Mon Sep 25, 2023 3:55 pm
What I do in these cases is build two tables, one for data and one for lookups. As you add ids to one table, you add them as key to another table with the number as data. Then you can use that second table to look up the index of a specific id.
Ooooh hadn't throught of that - though wouldn't it still need to check for existing IDs when creating a new entity? If an entity is removed, there will be a gap in the ID table that, unless I'm misunderstanding?
That largely depends on how your IDs are designed. If they are custom text you enter, duplicates would be possible. If you let the code generate the text, then yes, your code should check whether that ID already exists - but then you can just check in the ID table if there is an entry already. If they are numbers? Not really a problem unless you plan to iterate over the data table - which should never be necessary because you can always access the entity you want directly by looking up the correct number via the ID in the ID table.
If an entity is removed, the simple solution to not mess up the indexes of your data table is to not remove it. table.remove would invalidate the indexes the ID table is pointing at by shifting all the elements so that's not an option. You could nil it if you wish so it eventually gets marked for garbage collection but usually that shouldn't be necessary. It will be more than enough to remove it from the ID table because that way you won't be able to find it anymore. As long as your draw / game logic is based around the ID table and only uses the data table for accessing the entities, removing the entity's index from the ID table will be enough to have effectively "removed" it.
If you're worried about entities lingering forever because you're developing something that doesn't have level but rather something like an RTS where a building got demolished, simply add another table that holds the indexes that are free to us for new entities so it gets overwritten and then garbage collected.
Re: Linking Entities
Posted: Mon Sep 25, 2023 6:08 pm
by pgimeno
Bobble68 wrote: ↑Mon Sep 25, 2023 4:12 pm
Ooooh hadn't throught of that - though wouldn't it still need to check for existing IDs when creating a new entity? If an entity is removed, there will be a gap in the ID table that, unless I'm misunderstanding?
If the order of entities is important, then yes, you need to either leave a gap, or to renumber the entities in the lookup table, which is costly.
If the order of entities is not important, then you can just remove the one with the correct index, move the last one to that index, and update its index in the lookup table.
Re: Linking Entities
Posted: Mon Sep 25, 2023 6:30 pm
by BrotSagtMist
Too complicated.
Given the door is an obstacle on the map just have the button remove it directly.
I dont see a need for lookups and links here.
Re: Linking Entities
Posted: Mon Sep 25, 2023 10:04 pm
by Bobble68
BrotSagtMist wrote: ↑Mon Sep 25, 2023 6:30 pm
Too complicated.
Given the door is an obstacle on the map just have the button remove it directly.
I dont see a need for lookups and links here.
The issue is doing it in such a way that my game's building system will be able to use, so I don't have to hard code in specific doors with specific buttons. If I don't find a way of linking specific buttons and doors, all buttons will open all doors.
pgimeno wrote: ↑Mon Sep 25, 2023 6:08 pm
If the order of entities is not important, then you can just remove the one with the correct index, move the last one to that index, and update its index in the lookup table.
The problem is also that I'd need to update all of the buttons which are linked to have the new correct index - ideally I need a way that is done by reference that doesn't need changing.
Endaris wrote: ↑Mon Sep 25, 2023 4:50 pm
If an entity is removed, the simple solution to not mess up the indexes of your data table is to not remove it. table.remove would invalidate the indexes the ID table is pointing at by shifting all the elements so that's not an option. You could nil it if you wish so it eventually gets marked for garbage collection but usually that shouldn't be necessary. It will be more than enough to remove it from the ID table because that way you won't be able to find it anymore. As long as your draw / game logic is based around the ID table and only uses the data table for accessing the entities, removing the entity's index from the ID table will be enough to have effectively "removed" it.
If you're worried about entities lingering forever because you're developing something that doesn't have level but rather something like an RTS where a building got demolished, simply add another table that holds the indexes that are free to us for new entities so it gets overwritten and then garbage collected.
Currently the way it works is that it iterates through the (poorly named) drawTable to update and draw the entities. Part of the problem is that the drawTable constantly changes order since the items get sorted to be in the correct order (I know I know this is probably bad form, maybe working on this could improve it). The ID of the target door needs to be saved with the button, and the ID also needs to get saved with the door.
Re: Linking Entities
Posted: Mon Sep 25, 2023 11:13 pm
by Endaris
Bobble68 wrote: ↑Mon Sep 25, 2023 10:04 pm
Currently the way it works is that it iterates through the (poorly named) drawTable to update and draw the entities. Part of the problem is that the drawTable constantly changes order since the items get sorted to be in the correct order (I know I know this is probably bad form, maybe working on this could improve it). The ID of the target door needs to be saved with the button, and the ID also needs to get saved with the door.
Okay, at this point where you're struggling so much with tables, I'm going to elaborate a bit more on my own suggestion earlier because it would eliminate having even more confusing tables.
I'll quickly write this as untested code but it should be enough to transport the idea.
Code: Select all
-- let's assume there's a class Door that has these functions and a constructor
function Door:open()
-- handle everything around opening the door, like playing an animation, making terrain passable
end
function Door:close()
-- handle everything around opening the door, like playing an animation, making terrain impassable
end
-- and a class Button that has these functions and a constructor
function Button:activate()
-- initiate some animation or whatever
-- we'll be bold and reference a function that is not defined on Button yet
-- it will later be set to specify for that concrete instance of a button what should happen as the result of activation
if self.onActivation then
self:onActivation()
end
end
This would be like the base layout. Button and Door don't know anything of each other yet.
But then in your level editor you can simply do...
Code: Select all
function loadLevel()
-- in reality these would probably take some params like coordinates
local someDoor = Door.new()
local someButton = Button.new()
-- and now we assign specifically for this button in this level what it should do - open that exact door
someButton.onActivation = function() someDoor:open() end
end
So later you'll probably activate that button some mechanism and it will open that door because onActivation is called and it contains a call to someDoor:open().
No tables needed at all. No need to save any IDs. No need for buttons to make personal acquaintance with that door. You could even overwrite the onActivation function later on again to make a second button press do something completely different. Or nothing at all. Or open 5 doors at once. Because onActivation can be anything you want it to be without baking something fixed into the Button or Door class.
Can't really give you tips on the drawing part cause I only ever worked on flat 2D rather than 2.5D games so drawing order was never a concern I had to consider more deeply.
Re: Linking Entities
Posted: Tue Sep 26, 2023 3:01 pm
by Bobble68
Endaris wrote: ↑Mon Sep 25, 2023 11:13 pm
Code: Select all
function loadLevel()
-- in reality these would probably take some params like coordinates
local someDoor = Door.new()
local someButton = Button.new()
-- and now we assign specifically for this button in this level what it should do - open that exact door
someButton.onActivation = function() someDoor:open() end
end
This is still hardcoded though - this method needs to be built manually into the level loader, and can't be changed using the level editor (which looks like this)
- Untitled-1.jpg (976.69 KiB) Viewed 9129 times
I just need a way that I can add a pointer attribute that can be typed in to refer to a different entity, and that won't change when the game is next loaded