iterating through a list for PolygonShape:getPoints()

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Post Reply
samahin
Prole
Posts: 3
Joined: Wed Feb 28, 2018 3:50 am

iterating through a list for PolygonShape:getPoints()

Post by samahin »

Hi lovers.
I am a newb to Love2d and Lua, and am trying to make a game.
One aspect that I am currently wrestling with is how to make polygons for my world map.
I want to create polygons, and I also want to visualise them to help with my development/debugging.
[Edit: The reason to make polygons is to change the game depending on which polygon the character is located in. (I.e. if in a forest polygon, set a forest background, increase likelihood of encountering bears). This should also help prevent my character from walking into mountains and into lakes. The purpose of drawing is only to help me debug.]

Specifically, I don't understand how to use PolygonShape:getPoints() for a list of polygons. I can think of work-arounds, but I'd love to learn how to code neatly and efficiently. This seems like a good learning point.

Could someone kindly help me to make this code work? It is a simplified extract of my working main file.
This is my first post to the forums, so apologies if I haven't understood some fundamental things :)

Code: Select all

polygon1 = {434,101, 452,112, 420,138}
polygon2 = {377,84 ,434,101, 420,138, 380,140}
polygon3 = {434,101, 451,112, 420,138}
polygon4 = {420,138, 426,150, 452,112}
polygon5 = {426,150 ,452,112, 459,154, 420,190}
polygon6 = {452,112, 472,87, 459,154}
polygon_table = {polygon1,polygon2,polygon3,polygon4,polygon5,polygon6}
p = table.getn(polygon_table) -- p=number of polygons == 6
  
function love.load()
  -- set window screen: https://love2d.org/wiki/love.window.setMode
  love.window.setMode(800, 450, {resizable=true, vsync=false, minwidth=400, minheight=300})
  for i = 1,p do      -- (i=polygon number)
    print("first two vertices for polygon "..i.." == {"..polygon_table[i][1]..","..polygon_table[i][1]..","..polygon_table[i][1]..","..polygon_table[i][1].."}")
  end
end

function love.update()
end

function love.draw()
	-- Demonstrate that polygon printing works for example Polygon1
	love.graphics.polygon('line',polygon1)
	for i = 1,p do
		polygon={}
		polygon[i] = love.physics.newPolygonShape(polygon_table[i])
		--love.graphics.polygon('line', PolygonShape:getPoints()) -- this part is currently confusing me - how do i specify to get the points for each polygon[i]?
	end
end
Last edited by samahin on Thu Mar 01, 2018 1:12 am, edited 3 times in total.
User avatar
pgimeno
Party member
Posts: 3544
Joined: Sun Oct 18, 2015 2:58 pm

Re: iterating through a list for PolygonShape:getPoints()

Post by pgimeno »

Hello samahin, welcome to the forums!

[Edit: Oops, in a post that was below, PGUp was probably more accurate than I am (I assumed you wanted to create the polygons as collidable physical entities, but that may not be the case). Anyway here's what I posted.]

The shape only has the "canonical" points, and they will be relative to the body. It doesn't know where your body is located or how is oriented. You typically create your shape relative to the body, that is, with (0, 0) roughly being the centre of the body. In order to draw them, you then filter them through Body:getWorldPoints(). For example:

Code: Select all

local lp, lg = love.physics, love.graphics
local triangleShape = {-20,10,  20,10,  0,-10}
local world, body, shape, fixture

function love.load()
  world = lp.newWorld(0, 0)
  body = lp.newBody(world, 400, 300.5)
  shape = lp.newPolygonShape(triangleShape)
  fixture = lp.newFixture(body, shape)
end

function love.draw()
  lg.polygon("line", body:getWorldPoints(shape:getPoints()))
end
If you want to draw multiple polygons, you just call love.graphics.polygon multiple times.

Edit: After reading your code in more detail, I see a few problems within love.draw. 1) You clear the table inside the loop, which means that the values set in previous iterations will be cleared. 2) You call newPolygonShape while you draw. You typically do this in love.load instead. 3) You need at least one body if you want your shapes to be collidable, and also one fixture per shape. And 4) You never use PolygonShape directly, you use the object you got from love.physics.newPolygonShape, in this case polygon[ i], like this:

Code: Select all

  love.graphics.polygon("line", polygon[i]:getPoints())
One note: when adding code to your post, please embed it in [ code] ... [ /code] tags (without the spaces) like I did above, so that it is formatted appropriately. The lack of formatting of your post confused me.
Last edited by pgimeno on Wed Feb 28, 2018 11:07 am, edited 2 times in total.
PGUp
Party member
Posts: 105
Joined: Fri Apr 21, 2017 9:17 am

Re: iterating through a list for PolygonShape:getPoints()

Post by PGUp »

it seems like you are not trying to make a physics polygon, PolygonShape:getPoints() is for physics polygon only.. using it on a table like that wont work

Code: Select all

function love.draw()
local points = {0, 0, 250, 250, 0, 500}
love.graphics.polygon("line", points)
end
-
samahin
Prole
Posts: 3
Joined: Wed Feb 28, 2018 3:50 am

Re: iterating through a list for PolygonShape:getPoints()

Post by samahin »

Thanks PGUp, I hadn't been clear enough - I've edited the original post for the reason I'm making polygons. There may be another way to do what I wish to do outside of creating a physics polygon (some complicated if then else statement according to the Cartesian coordinates, maybe?) but the primary purpose is not for drawing.

pgimeno - You've made a couple of nice points. I'll make sure to put the right things in love.load (I was just being lazy there). The whole newWorld, newBody, newFixture stuff is something that I haven't seen before and will need some experimenting and reading to get my head around it. Your code is pretty logical though, so I think that you've saved me some confusion there. From your code it seems that I can make a table of world, body, shape, fixture which corresponds to my list of [6] polygons (I have 56 in total). And then from there I'll try drawing specific shapes like this (in a loop, eventually):

Code: Select all

function love.draw()
  lg.polygon("line", body:getWorldPoints(shape[1]:getPoints()))
  lg.polygon("line", body:getWorldPoints(shape[2]:getPoints()))
end
^^ I learnt how to embed code on the forum too. Thanks!!

I'll keep you updated when I try out these changes.
(If anybody has a solution to my aim of creating defined spaces on the map outside of this way of thinking, please chime in!)
User avatar
pgimeno
Party member
Posts: 3544
Joined: Sun Oct 18, 2015 2:58 pm

Re: iterating through a list for PolygonShape:getPoints()

Post by pgimeno »

Now that I've read your purpose, whether you need fixtures and bodies depends on how accurate you want the intersection.

If you just want to test whether a point is inside the polygon, you only need the polygon shape without any fixtures or bodies. The function Shape:testPoint is what you need. Note that "Shape" is a placeholder for your actual object, just like PolygonShape, and you would need to use shape[ i]:testPoint(...) instead. Alternatively, you can make your own point-in-polygon function and forget about love.physics; you can do a web search for the algorithms, they aren't too complex, and that may spare you from struggling with the goriest details of love.physics.

If you want to test whether a shape intersects with another because you want your player to have "volume", I think you also need one fixture per shape and one body for all (or one body for each, your choice), and to set the fixture to sensor with Fixture:setSensor. Then your player would be another body with another fixture/shape.

Keep in mind that love.physics doesn't allow concave polygons (i.e. polygons with at least one angle > 180°) See PolygonShape:validate.
samahin
Prole
Posts: 3
Joined: Wed Feb 28, 2018 3:50 am

Re: iterating through a list for PolygonShape:getPoints()

Post by samahin »

Thanks for the comments. I've followed through the logic and successfully set up my polygons.
For those interested, this is what I've accomplished: https://love2d.org/imgmirrur/o22cUGl.png
(The red dot represents the character location)

pgimeno - in your example, I'm intrigued by the use of 'world' and 'body.' They seem like objects that would be useful for creating a scrollable 'camera' view of the world.

The next job for me is to figure out collision detection.

PS. Is this how most of you learn to use Love/Lua? I keep getting lost in tutorials about making platformers, which really isn't my thing... Does anybody have a magic RPG or clicker tutorial that they've found useful?
User avatar
pgimeno
Party member
Posts: 3544
Joined: Sun Oct 18, 2015 2:58 pm

Re: iterating through a list for PolygonShape:getPoints()

Post by pgimeno »

samahin wrote: Thu Mar 01, 2018 8:40 am pgimeno - in your example, I'm intrigued by the use of 'world' and 'body.' They seem like objects that would be useful for creating a scrollable 'camera' view of the world.
Not quite. It refers to the physical world, the one containing all bodies, but it doesn't handle cameras. See World. The crucial function is World:update(), which applies the laws of physics to all bodies every timestep.

For cameras there are some libraries including gamera, stalker-x, hump and others I'm probably forgetting.
samahin wrote: Thu Mar 01, 2018 8:40 am The next job for me is to figure out collision detection.
love.physics can help you, but if you don't need complex collisions, it may be overkill. For axis-aligned boxes, I suggest bump.lua.
samahin wrote: Thu Mar 01, 2018 8:40 amPS. Is this how most of you learn to use Love/Lua? I keep getting lost in tutorials about making platformers, which really isn't my thing... Does anybody have a magic RPG or clicker tutorial that they've found useful?
Someone else can probably answer that better than me. I have been a programmer for many years and I learned Lua basically from the manual and PIL, and Löve from the wiki. I rarely use tutorials.
Post Reply

Who is online

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