Linking Entities

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
Bobble68
Party member
Posts: 160
Joined: Wed Nov 30, 2022 9:16 pm
Contact:

Linking Entities

Post 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?
Dragon
User avatar
pgimeno
Party member
Posts: 3567
Joined: Sun Oct 18, 2015 2:58 pm

Re: Linking Entities

Post 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.
User avatar
Bobble68
Party member
Posts: 160
Joined: Wed Nov 30, 2022 9:16 pm
Contact:

Re: Linking Entities

Post 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?
Dragon
User avatar
dusoft
Party member
Posts: 517
Joined: Fri Nov 08, 2013 12:07 am
Location: Europe usually
Contact:

Re: Linking Entities

Post 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

Code: Select all

table.remove
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:

Code: Select all

__newindex
__index
and customize them to check e.g. for duplicates or else to suit your needs.
User avatar
Endaris
Prole
Posts: 12
Joined: Sun Oct 09, 2022 11:55 pm

Re: Linking Entities

Post 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.
User avatar
pgimeno
Party member
Posts: 3567
Joined: Sun Oct 18, 2015 2:58 pm

Re: Linking Entities

Post 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.
User avatar
BrotSagtMist
Party member
Posts: 627
Joined: Fri Aug 06, 2021 10:30 pm

Re: Linking Entities

Post 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.
obey
User avatar
Bobble68
Party member
Posts: 160
Joined: Wed Nov 30, 2022 9:16 pm
Contact:

Re: Linking Entities

Post 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.
Last edited by Bobble68 on Mon Sep 25, 2023 11:50 pm, edited 1 time in total.
Dragon
User avatar
Endaris
Prole
Posts: 12
Joined: Sun Oct 09, 2022 11:55 pm

Re: Linking Entities

Post 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.
User avatar
Bobble68
Party member
Posts: 160
Joined: Wed Nov 30, 2022 9:16 pm
Contact:

Re: Linking Entities

Post 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
Untitled-1.jpg (976.69 KiB) Viewed 8187 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
Dragon
Post Reply

Who is online

Users browsing this forum: Google [Bot], Majestic-12 [Bot] and 2 guests