True Object Instantiation

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.
Post Reply
FatalMarshmallow
Prole
Posts: 17
Joined: Mon Jul 30, 2012 9:15 pm

True Object Instantiation

Post by FatalMarshmallow »

Basically trying to have the .love file linked below as is but with the squares that make up the "map" all being able to be "jumped" on, rather than merely the last/ most recently created. I'm certain that this will already have been asked about and solved somewhere but I can't find anything after an hour of searching. :?

Also there seems to be a collision thing while walking along the squares that decides to detect a collision sometimes at the border between two, is there a simple fix for this or is this a consequence of how it's built? Most controls are in the window title but holding space pauses the game until released also. :huh:

And if I'm just being a dope noob as usual about all this feel free to ignore. :roll:
Attachments
Swing Game.love
(3.86 KiB) Downloaded 53 times
User avatar
pgimeno
Party member
Posts: 3656
Joined: Sun Oct 18, 2015 2:58 pm

Re: True Object Instantiation

Post by pgimeno »

Here's how I've made it. I've set the jumpable bodies' user data to "jumpable", to indicate which bodies can be jumped on. On second thought, maybe I could have used the fixtures, but it's OK like this if you have just one fixture per body.

Code: Select all

	objects.ground.body:setUserData("jumpable")
I also got rid of objects.square which isn't very helpful. The loop for the platform shapes now looks like this:

Code: Select all

 	for y=1, #map do
 		for x=1, #map[y] do
 			if map[y][x] == 1 then
				local body = love.physics.newBody(world,(x * 64) - 32 , (y * 64) - 32) --Creates the square body objects to create the map
				body:setUserData("jumpable")
				local shape = love.physics.newRectangleShape(64, 64) --Creates the square shape of size X=64, Y=64
				love.physics.newFixture(body, shape, 1)  --Fixes the square body and shape together
 			end
 		end
 	end
Note the body:setUserData("jumpable").

And this is how the jump key handler ended up looking like:

Code: Select all

 	if love.keyboard.isDown("w") then
		local canJump = false
		if objects.rectangle.body:isTouching(objects.ground.body) then
			-- TODO: check normal
			canJump = true
		else
			local contacts = objects.rectangle.body:getContacts()
			for k,v in pairs(contacts) do
				if v:isTouching() then
					local f1, f2 = v:getFixtures()
					local nx, ny = v:getNormal()
					local groundCheck = ny < 0
					local b = f1:getBody()
					if b == objects.rectangle.body then
						b = f2:getBody()
						groundCheck = ny > 0
					end
					if b:getUserData() == "jumpable" then
						if groundCheck and nx == 0 then
							canJump = true
							break
						end
					end
				end
			end
		end
		if canJump then
			objects.rectangle.body:applyForce(0, -800)
 		end
 	end
Basically, go through all the contacts to see if one of the contacts is with a fixture whose body is marked as jumpable, and has a normal that makes sense for a ground jump. Note that this check disables the ability to jump on walls; if you want that, you'll have to change the normal check.

The getting stuck on borders is a common problem, even more with Box2D. I've tried making a capsule-shaped player, but then you get small bounces:

Code: Select all

	objects.rectangle.shape1 = love.physics.newRectangleShape(14, 16) --Creates the rectangle shape of size X=20, Y=50
	objects.rectangle.shape2 = love.physics.newCircleShape(0, -8, 8) --Creates the circle shape of radius 8
	objects.rectangle.shape3 = love.physics.newCircleShape(0, 8, 8) --Creates the circle shape of radius 8
	objects.rectangle.fixt1 = love.physics.newFixture(objects.rectangle.body, objects.rectangle.shape1, 1)  --Fixes the rectangle body and shape together
	objects.rectangle.fixt2 = love.physics.newFixture(objects.rectangle.body, objects.rectangle.shape2, 1)  --Fixes the circle shape and body together
	objects.rectangle.fixt3 = love.physics.newFixture(objects.rectangle.body, objects.rectangle.shape3, 1)  --Fixes the circle shape and body together
FatalMarshmallow
Prole
Posts: 17
Joined: Mon Jul 30, 2012 9:15 pm

Re: True Object Instantiation

Post by FatalMarshmallow »

This is all wicked, and solves more problems than I had even asked for help with! :awesome: I had thought to just cap the sides of anything I didn't want walljumpable, but this solves that without any caveat, and wouldn't leave some horrible jump blocking zone at the side of any platform.

I'm just going over everything now since obviously draw functions won't work if this was all just Ctrl+C, Ctrl+V'd in, and I'm intent on understanding how it all works to write better code in future. :oops:

The assist is super appreciated, really can't thank you enough. :ultrahappy:
User avatar
pgimeno
Party member
Posts: 3656
Joined: Sun Oct 18, 2015 2:58 pm

Re: True Object Instantiation

Post by pgimeno »

Sorry, I wasn't too careful. The first check (the check for the platform) is unnecessary. I started with that but then decided to go with UserData to detect jumpable fixtures, and didn't remove that part.

This is how it looks like after fixing that:

Code: Select all

 	if love.keyboard.isDown("w") then
		local canJump = false
		local contacts = objects.rectangle.body:getContacts()
		for k,v in pairs(contacts) do
			if v:isTouching() then
				local f1, f2 = v:getFixtures()
				local nx, ny = v:getNormal()
				local groundCheck = ny < 0
				local b = f1:getBody()
				if b == objects.rectangle.body then
					b = f2:getBody()
					groundCheck = ny > 0
				end
				if b:getUserData() == "jumpable" then
					if groundCheck and nx == 0 then
						canJump = true
						break
					end
				end
			end
		end
		if canJump then
			objects.rectangle.body:applyForce(0, -800)
 		end
 	end
And yes, by all means, try to understand the code. I outlined the intent already, but since there aren't any comments, you might have a bit more difficulty following it. Hopefully it will be straightforward.

One problem that is taken care of, and that may be obfuscating the code a bit, is that you don't know which of the two returned fixtures belongs to the player. You want to check the fixture that isn't the player, to see if it's jumpable.

Then there's the normal, which always points from the first fixture to the second one, therefore if we get the player as the first fixture, the normal must point down (y > 0) in order to be able to jump, and if the player is the second, the first fixture will be the ground and it needs to point up (y < 0), towards the player, to allow jumping.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot] and 9 guests