I'm having trouble with planet gravity and player movement?

Hi, I’m new to Defold and I’m trying to do flappy bird game mechanics bird revolving around a planet and jumping similiar to this game https://play.google.com/store/apps/details?id=com.mrflap

I’m stuck with how to do gravity pull and revolving motion around planet at same time.

This is what I have done
Peek%202020-11-29%2013-30

function init(self)
	msg.post(".", "acquire_input_focus")
	
	self.velocity = vmath.vector3()  -- <1>
	self.gravity = vmath.vector3()	--<2>
	self.pos = vmath.vector3()	--<3>
	
	self.direction = nil	--<4>
	self.movement_direction = nil	--<5>
	
	self.ground_contact = false	--<6>

	self.center = go.get_position('/planet') -- <7>
	self.speed = 4 -- <8>
	self.t = 0 -- <9>
end

function final(self)
	-- msg.post(".", "release_input_focus")
end

function update(self, dt)
	self.radius = vmath.length(go.get_position('/planet') - go.get_position())
	
	self.t = self.t + dt 
	local dx = math.sin(self.t * self.speed) * self.radius 
	local dy = math.cos(self.t * self.speed) * self.radius

	local delta = go.get_position('/planet') - go.get_position()
	self.direction = vmath.normalize(delta)
	self.gravity = self.direction * 10

	if not self.ground_contact then
		self.velocity = self.velocity + self.gravity 
		go.set_position(go.get_position() + self.velocity * dt )
	else
		self.pos = go.get_position()
		self.pos.x = self.center.x - dx
		self.pos.y = self.center.y - dy
		self.movement_direction = vmath.normalize(self.pos)
		go.set_position(self.pos)
	end

	-- reset volatile state
	self.correction = vmath.vector3()
	-- self.ground_contact = false
end

-- from the platformer tutorial on defold.com
local function handle_geometry_contact(self, normal, distance)
	local proj = vmath.dot(self.correction, normal)
	local comp = (distance - proj) * normal
	self.correction = self.correction + comp
	go.set_position(go.get_position() + comp)
	if normal.y > 0.7 then
		self.ground_contact = true
	end
	proj = vmath.dot(self.velocity, normal)
	if proj < 0 then
		-- remove that component in that case
		self.velocity = self.velocity - proj * normal
		self.velocity.x = 0
	end
end

function on_message(self, message_id, message, sender)
	if message_id == hash("contact_point_response") then
		if message.group == hash("planets") then
			self.ground_contact = true
			handle_geometry_contact(self, message.normal, message.distance)
		end
	end
end

function on_input(self, action_id, action)
	if action_id then
		-- jump
		if action_id == hash("touch") then
			if action.pressed then
				self.ground_contact = false
				self.velocity = - self.gravity * 30
				-- reset()
			end
		end
	end
end

function on_reload(self)
	
end

Any help would be much appreciated, thank you.

1 Like

Funnily enough, I actually made something similar recently. Here’s the player script I made, modified to fit your game:

local SPEED = 4
local GRAVITY = 10

local DISTANCE = 110

-- Find angle between two vector3's
local function angle(p1, p2)
	local dy = p2.y - p1.y
	local dx = p2.x - p1.x
	return math.atan2(dy, dx)
end

-- Get rotation around the planet
local function get_rotation()
	return vmath.quat_rotation_z(angle(vmath.vector3(), go.get_position()) + 4.7123889803847)
end

-- Simple circle collision detection
local function check_floor(self)
	local pos = go.get_position()
	local distance = vmath.length(pos)
	if distance <= DISTANCE then
		self.ground_contact = true
		self.velocity.y = math.max(self.velocity.y, 0)

		go.set_position(vmath.normalize(pos) * (DISTANCE - distance) + pos)
	else
		self.ground_contact = false
	end
end

function init(self)
  self.velocity = vmath.vector3(SPEED, 0, 0)
  self.ground_contact = false
end

function update(self, dt)
  self.velocity.y = self.velocity.y - GRAVITY

  -- Rotate velocity so it goes around the planet
  local delta = vmath.rotate(get_rotation(), self.velocity)
  go.set_position(go.get_position() + delta * dt)

  check_floor(self)

  -- Rotate player
	go.set_rotation(get_rotation())
end

function on_input(self, action_id, action)
  if action_id == hash("touch") and action.pressed and self.ground_contact then
    self.ground_contact = false
    self.velocity.y = GRAVITY * 30
  end
end

A couple of things to note:

  1. The code assumes the center of the planet is at 0,0,0 (it makes vector math way simpler)
  2. You need to change DISTANCE to the distance between the center of the player to the center of the planet when the player is on the ground (player radius + planet radius)
5 Likes