My platformer code isnt working (SOLVED)

local input_jump = hash("jump")

function init(self)
	msg.post(".","acquire_input_focus")
	self.runSpeed = 350
	self.curAnim = "idle"
	msg.post("#sprite", "play_animation", { id=hash("idle") })
	self.speed = vmath.vector3()
	msg.post(".", "acquire_input_focus")
	self.speed = vmath.vector3(0, 0, 0)
	self.correction = vmath.vector3()
	self.ground_contact = false
	self.move_input = 0
	self.anim = nil
	self.touch_jump_timer = 0
end

local function update_animations(self)
	-- make sure the player character faces the right way
	sprite.set_hflip("#sprite", self.move_input < 0)
	-- make sure the right animation is playing
	if self.ground_contact then
		if self.speed.x == 0 then
			play_animation(self, anim_idle)
		end
	end
end
function update(self, dt)
	local pos = go.get_position()
	if self.speed.y >= -100 then
		self.speed.y = self.speed.y - 25
	end
	if self.speed.x ~= 0 then    
		pos = pos + self.speed * dt
		go.set_position(pos)
		if self.curAnim ~= "run" then
			msg.post("#sprite", "play_animation", { id=hash("run") })
			self.curAnim = "run"
		end
	end
end
--local function jump(self)
--	if self.contact_point_response then
--		self.speed.y = 300
--	end
--end

function on_input(self, action_id, action, message_id)
	if action_id == hash("MOVE_RIGHT") then
		self.speed.x = self.runSpeed
		sprite.set_hflip("#sprite", false)
	end    
	if action_id == hash("MOVE_LEFT") then
		self.speed.x = self.runSpeed * -1 
		sprite.set_hflip("#sprite", true)
	end        
	if action_id == hash("JUMP") and self.ground_contact then
		self.speed.y = self.speed.y + 300
	end
end

function on_message(self, message_id, message, sender)
	-- Handle collision
	if message_id == hash("contact_point_response") then
		local newpos = go.get_position() + message.normal * message.distance
		go.set_position(newpos)
	end
end

this is the code, the problematic section is the movement function and jump, it works fine without self.ground_contact but as soon as that is added the character can no longer jump, i need it there so my character cannot fly. Is there any alternatives or fixes to my code to sort this out?

Hi @PremiumRice, welcome to the forum!

Just two side notes, not directly related to the issue you are facing.

  1. I would guess that the line
    self.speed.y = (self.speed.y - 25)
    is used to limit the y velocity. However, in this way, your update code is heavily dependent on the refresh rate. You should avoid using formula for cinematic variables without using dt! I would suggest something similar to
    self.speed.y = (1.0 - K*dt) * self.speed.y
    where K is a (small!) constant you should adjust to your need. In this way the code is (somehow) independent of the refresh rate since it is using dt.

  2. It is not good to compare floating numbers. Instead of the line
    if self.speed.x ~= 0 then
    I would advice something like
    if math.abs(self.speed.x) > 0.1 then
    where 0.1 is a constant you may adjust.

Ciao!

3 Likes

Hi and welcome @PremiumRice.

First of all, it’s easier to read your code if you copy and paste it in here. If you highlight it and then hit this button it should look nicely formatted:

--like this!

Are there parts of your code that haven’t been posted? It looks like self.ground_contact isn’t defined anywhere, which would make it nil. If it’s nil, then you will indeed never be able to jump. Nil is equivalent to false in conditionals, so even if the action_id is hash(“jump”) then the other part of the conditional will still always fail.

What you need is to set self.ground_contact to true whenever you’re in contact with the ground, and false if you’re not.

4 Likes

what im struggling with is how i would do that, im fairly new to defold and cant code in lua although i know other languages, i just dont know if theres a built in command for contact with another collision object or something like that?

Yes, there is. Check out this part of the manual on Physics. The physics API reference will be generally useful as well.

I haven’t made a platformer in Defold myself but I suspect a simple way would be to set self.ground_contact to true when the player character collides with the ground. If you jump, you can set self.ground_contact to false. You could also set a timer so that self.ground_contact is set to false x frames after last contact (to handle cases where you’re not on the ground but didn’t jump, e.g. if you walked off a ledge).

2 Likes
function on_message(self, message_id, message, sender)
	if message_id == hash("contact_point_response") then
		self.ground_contact = true
	end
end
function on_input(self, action_id, action, message_id)
	if action_id == hash("MOVE_RIGHT") then
		self.speed.x = self.runSpeed
		sprite.set_hflip("#sprite", false)
	end    
	if action_id == hash("MOVE_LEFT") then
		self.speed.x = self.runSpeed * -1 
		sprite.set_hflip("#sprite", true)
	end        
	if action_id == hash("JUMP") and self.ground_contact == true then
		self.speed.y = self.speed.y + 750
		self.ground_contact = false
	end
end

Ok so i’ve got the change for ground_contact at the top and the jumping code at the bottom, theres nothing wrong with the jump code its just the collision at the top isnt changing the boolean, I know the code for registering the collision is right because it works elsewhere in the code and the boolean change code also works elsewhere in the code so im really not sure where im going wrong here

Code looks fine to me, so that makes me think your collision objects might not be set up properly. I tend to pepper my code with prints to try and gain a clue about what’s going wrong. For example, I might change your on_message to this:

function on_message(self, message_id, message, sender)
        print(message_id, sender)
        pprint(message)
	if message_id == hash("contact_point_response") then
                print("ground contact registered")
		self.ground_contact = true
	end
end

This will only be slightly useful if my suspicion is right, which is that your collision objects aren’t set up correctly. For that, I recommend you review the Group and mask section of the Physics manual.

I also recommend you tick Debug under Physics in game.project, which will allow you to see your collision objects and their collisions.

Figured it out, apparently defold doesnt like multiple functions responding to collisions so i just had to put it all into one function and it worked!!! Thank you very much

1 Like

What do you mean by this?

I couldnt make multiple function on_message(self, message_id, message, sender) because the second one i made didnt work for some reason so i just kind of assumed it didnt like multiple being there, its probably because of the first one being a collision correction function for a player character messing with the collision recognition

Exactly. The on_message() function is one of the Defold lifecycle functions and there can be only one of each in a script file.