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

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.
dyl4n130
Prole
Posts: 24
Joined: Sat Jul 29, 2017 6:48 am

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

Post 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?
User avatar
Sir_Silver
Party member
Posts: 286
Joined: Mon Aug 22, 2016 2:25 pm
Contact:

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

Post 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
dyl4n130
Prole
Posts: 24
Joined: Sat Jul 29, 2017 6:48 am

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

Post 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
User avatar
Sir_Silver
Party member
Posts: 286
Joined: Mon Aug 22, 2016 2:25 pm
Contact:

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

Post 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! =)
dyl4n130
Prole
Posts: 24
Joined: Sat Jul 29, 2017 6:48 am

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

Post 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`
User avatar
xNick1
Party member
Posts: 267
Joined: Wed Jun 15, 2016 8:27 am
Location: Rome, Italy

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

Post 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!
User avatar
s-ol
Party member
Posts: 1077
Joined: Mon Sep 15, 2014 7:41 pm
Location: Cologne, Germany
Contact:

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

Post 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.

s-ol.nu /blog  -  p.s-ol.be /st8.lua  -  g.s-ol.be /gtglg /curcur

Code: Select all

print( type(love) )
if false then
  baby:hurt(me)
end
dyl4n130
Prole
Posts: 24
Joined: Sat Jul 29, 2017 6:48 am

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

Post 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
User avatar
Sir_Silver
Party member
Posts: 286
Joined: Mon Aug 22, 2016 2:25 pm
Contact:

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

Post 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.
dyl4n130
Prole
Posts: 24
Joined: Sat Jul 29, 2017 6:48 am

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

Post 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
Post Reply

Who is online

Users browsing this forum: Google [Bot] and 177 guests