Page 1 of 2

How would I go about drawing the same object multiple times?

Posted: Sun Aug 27, 2017 1:07 am
by dyl4n130
I mean I am aware I could just copy and paste a `love.image.draw()` function multiple times, but lets say I wanted to draw an image wherever the mouse is clicked at. How would I go about making it so it draw said item every time I clicked. If I only clicked twice it would draw two objects, and if I clicked it 500 times it would draw 500 items, without having to have 500 different draw functions?

Re: How would I go about drawing the same object multiple times?

Posted: Sun Aug 27, 2017 1:44 am
by Sir_Silver
Don't have the time to explain the many ways you could do that at the moment, but here is some example code that you might be able to understand.

Code: Select all

local entity = {
    w = 50,
    h = 50,

    color = {255, 0, 0}
}

entity.__index = entity

function entity:draw()
    love.graphics.setColor(self.color)
    love.graphics.rectangle("fill", self.x, self.y, self.w, self.h)
end

local entities = {}

function love.draw()
    for i = 1, #entities do
        entities[i]:draw()
    end
end

function love.mousepressed(x, y)
    local entity = setmetatable({}, entity)
    entities[#entities + 1] = entity

    entity.x, entity.y = x, y
end
Image

Re: How would I go about drawing the same object multiple times?

Posted: Sun Aug 27, 2017 1:49 am
by dyl4n130
Sir_Silver wrote: Sun Aug 27, 2017 1:44 am Don't have the time to explain the many ways you could do that at the moment, but here is some example code that you might be able to understand.

Code: Select all

local entity = {
    w = 50,
    h = 50,

    color = {255, 0, 0}
}

entity.__index = entity

function entity:draw()
    love.graphics.setColor(self.color)
    love.graphics.rectangle("fill", self.x, self.y, self.w, self.h)
end

local entities = {}

function love.draw()
    for i = 1, #entities do
        entities[i]:draw()
    end
end

function love.mousepressed(x, y)
    local entity = setmetatable({}, entity)
    entities[#entities + 1] = entity

    entity.x, entity.y = x, y
end
Image
I wish I could say I understand what is going on there. I am mostly self taught in Love2d which I hate because I have really weird terrible ways of doing things any pretty much every single line of code you just posted just completely flew over my head. If you have time to explain I would love to see what you have to say

Re: How would I go about drawing the same object multiple times?

Posted: Sun Aug 27, 2017 1:58 am
by Sir_Silver
Yeah, so in the function love.draw, we aren't writing hundreds of lines of code to draw each individual thing we want to draw, instead, we iterate over a table which contains all of the things we want to draw (which could be anywhere from 0 to a million or more things).

The for loop inside of love.draw calls the "draw" function for each one of the entities:

Code: Select all

function entity:draw()
    love.graphics.setColor(self.color)
    love.graphics.rectangle("fill", self.x, self.y, self.w, self.h)
end
Notice that love.graphics.rectangle doesn't take hard coded arguments, instead it uses variables that are stored on the self. The self.x and self.y variables of the entity are given during the love.mousepressed callback:

Code: Select all

function love.mousepressed(x, y)
    local entity = setmetatable({}, entity)
    entities[#entities + 1] = entity

    entity.x, entity.y = x, y
end
This creates an "instance" of an entity, stores the instance of an entity inside of the entities table (which we use for drawing all of the entities in love.draw), and finally gives the entity the necessary x and y variable for determining where to draw it.

I don't have time to proofread this right now, so I'll edit later if it's wrong, let me know if this helps! =)

Re: How would I go about drawing the same object multiple times?

Posted: Sun Aug 27, 2017 6:01 am
by dyl4n130
Sir_Silver wrote: Sun Aug 27, 2017 1:58 am Yeah, so in the function love.draw, we aren't writing hundreds of lines of code to draw each individual thing we want to draw, instead, we iterate over a table which contains all of the things we want to draw (which could be anywhere from 0 to a million or more things).

The for loop inside of love.draw calls the "draw" function for each one of the entities:

Code: Select all

function entity:draw()
    love.graphics.setColor(self.color)
    love.graphics.rectangle("fill", self.x, self.y, self.w, self.h)
end
Notice that love.graphics.rectangle doesn't take hard coded arguments, instead it uses variables that are stored on the self. The self.x and self.y variables of the entity are given during the love.mousepressed callback:

Code: Select all

function love.mousepressed(x, y)
    local entity = setmetatable({}, entity)
    entities[#entities + 1] = entity

    entity.x, entity.y = x, y
end
This creates an "instance" of an entity, stores the instance of an entity inside of the entities table (which we use for drawing all of the entities in love.draw), and finally gives the entity the necessary x and y variable for determining where to draw it.

I don't have time to proofread this right now, so I'll edit later if it's wrong, let me know if this helps! =)
thank you for the explanation. could you explain some of the more specific elements? such as the `#`, `setmetatable` and `.__index`

Re: How would I go about drawing the same object multiple times?

Posted: Sun Aug 27, 2017 6:43 am
by xNick1
With # you calculate the length of the table. When you create a new element you want to create it as the last element in the table. So #table +1.
Metatables are needed for oop.
Like self.x, self.y.
Just check them out!

Re: How would I go about drawing the same object multiple times?

Posted: Sun Aug 27, 2017 10:39 am
by s-ol
You can read about metatables and metamethods (like __index) in the PiL (Programming in Lua) and then revisit the code to see how it works. Being self-taught is not a problem by the way, most people here probably are.

Re: How would I go about drawing the same object multiple times?

Posted: Tue Aug 29, 2017 1:07 am
by dyl4n130
xNick1 wrote: Sun Aug 27, 2017 6:43 am With # you calculate the length of the table. When you create a new element you want to create it as the last element in the table. So #table +1.
Metatables are needed for oop.
Like self.x, self.y.
Just check them out!
thank you for the reply. i appreciate you trying to explain it but if im being honest I just don't understand. I get the "#", that stuff is pretty simple, and I think using "self" just referes to the class of the function that "self" is being referenced in right? I googled a ton on .__index but I'm not sure if I get it. Basically if you attempt to reference an element that doesn't exist its creates it wherever you called __index? I know nothing about classes so sorry if that makes no sense

Re: How would I go about drawing the same object multiple times?

Posted: Tue Aug 29, 2017 1:31 am
by Sir_Silver
When you try to access an index of a table whose value is nil,, if that table has a metatable which has an __index metamethod, it will invoke the __index metamethod. Here's what happens without the use of a metatable:

Code: Select all

local my_table = {}
print(my_table[1])  --prints nil, because there is no value at index 1
However, if we set the metatable of my_table to a table that has an __index metamethod, something different will happen:

Code: Select all

local my_metatable = {
	1
}

function my_metatable.__index(t, k)
	print("You have just used __index metamethod")
	return rawget(my_metatable, k)	
end

local my_table = setmetatable({}, my_metatable)
print(my_table[1])  --[[
	prints out: 
	You have just used __index metamethod	
	1	
]]
In this example, we try to print out the value of my_table[1]. There is no value there - it is nil - so it checks if my_table has a metatable.
It does have a metatable, so it checks if it has a __index metamethod which it does have, and then calls that function.

In this example, the __index metamethod prints out, "You have just used __index metamethod", and then returns whatever value is inside
the my_metatable table at the same index that was nil for the table we originally tried to index.

It is worth noting that

Code: Select all

local my_metatable = {
	1
}

function my_metatable.__index(t, k)
	return rawget(my_metatable, k)	
end
Is functionally the same as

Code: Select all

local my_metatable = {
	1
}

my_metatable.__index = my_metatable
Btw, I admire you for being self taught. I had the luxury of being taught nearly 1-on-1 for nearly two years. I'm here to to answer any more questions or help you out if you need it.

Re: How would I go about drawing the same object multiple times?

Posted: Tue Aug 29, 2017 12:47 pm
by dyl4n130
Sir_Silver wrote: Tue Aug 29, 2017 1:31 am When you try to access an index of a table whose value is nil,, if that table has a metatable which has an __index metamethod, it will invoke the __index metamethod. Here's what happens without the use of a metatable:

Code: Select all

local my_table = {}
print(my_table[1])  --prints nil, because there is no value at index 1
However, if we set the metatable of my_table to a table that has an __index metamethod, something different will happen:

Code: Select all

local my_metatable = {
	1
}

function my_metatable.__index(t, k)
	print("You have just used __index metamethod")
	return rawget(my_metatable, k)	
end

local my_table = setmetatable({}, my_metatable)
print(my_table[1])  --[[
	prints out: 
	You have just used __index metamethod	
	1	
]]
In this example, we try to print out the value of my_table[1]. There is no value there - it is nil - so it checks if my_table has a metatable.
It does have a metatable, so it checks if it has a __index metamethod which it does have, and then calls that function.

In this example, the __index metamethod prints out, "You have just used __index metamethod", and then returns whatever value is inside
the my_metatable table at the same index that was nil for the table we originally tried to index.

It is worth noting that

Code: Select all

local my_metatable = {
	1
}

function my_metatable.__index(t, k)
	return rawget(my_metatable, k)	
end
Is functionally the same as

Code: Select all

local my_metatable = {
	1
}

my_metatable.__index = my_metatable
Btw, I admire you for being self taught. I had the luxury of being taught nearly 1-on-1 for nearly two years. I'm here to to answer any more questions or help you out if you need it.
thank you for the reply, that makes sense. being self taught is kinda fun but it makes reading other peoples code absolute hell. i can barely even understand beginners guides because they normally have a totally different approach of doing everything. i really should "start over" and try to relearn from scratch but i dont have the patience :x