How to Simulate Radial Gravity Without Using Physics Engine Part 2/2

In the first part of this tutorial we have learned some basics about vectors in 2d and logic of simulating radial gravity. Now it is time to put what we have learned into practice.

I’ve added two planets in my code to give you a good demonstration of radial gravity. If you follow this tutorial, what you will have is below

Radial Gravity

Adding Planets

Now let’s start to write some code by adding planets and their gravitational fields to scene.

local MathSqrt = math.sqrt
local blueCenter = { x = 160,y =320}
local greenCenter = { x = 270, y = 40}

local blueGravField = display.newCircle (blueCenter.x,blueCenter.y,130)
blueGravField:setFillColor(0,0.7,1,0.2) 
blueGravField.strokeWidth = 1 
blueGravField:setStrokeColor(0,0.7,1)
local blueRadius = blueGravField.path.radius

local bluePlanet = display.newCircle (blueCenter.x,blueCenter.y,20)
bluePlanet:setFillColor(0,0.7,1) 
local bluePlanetRadius = bluePlanet.path.radius

local greenGravField = display.newCircle (greenCenter.x,greenCenter.y,220)
greenGravField:setFillColor(0,1,0.7,0.2) 
greenGravField.strokeWidth = 1 
greenGravField:setStrokeColor(0,1,0.7)
local greenRadius = greenGravField.path.radius

local greenPlanet = display.newCircle (greenCenter.x,greenCenter.y,20)
greenPlanet:setFillColor(0,1,0.7)
local greenPlanetRadius = greenPlanet.path.radius

Line 1 : Localize the math.sqrt()  function to acces it faster in your calculations.

Lines 2,3 : Define two table to hold your blue and green planets’¬† center points.

Lines 5-9 : Add a new circle as blue planet’s gravitational field. Define local value “blueRadius” to hold this circle’s radius.

Lines 11-13 : Add a new circle as blue planet and define local value “bluePlanetRadius” to hold planet’s radius.

Lines 15-23 : Do the same things as you did for blue planet and gravitational field.

Now when you run the code in simulator you should see this

adding_planets

Adding Some Functions

Add two functions below at the end of your code to find distance between two points and unit vector from one point to other.


local function findDistance(x1,y1,x2,y2)
	local distance = MathSqrt( (x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1) )
	return distance
end

“findDistance” function above takes x and y coordinates of the points and by using¬†pythagorean theorem returns the distance between the points. Remember finding magnitude of the vector between two points, from the part1 of this tutorial.

local function findUnitVector(x1,y1,x2,y2,distance)
	local unitVector = {}
	unitVector.x = (x2-x1)/distance
	unitVector.y = (y2-y1)/distance
	return unitVector
end

findUnitVector function above takes coordinates of two points and distance between them an returns the unit vector. Order of the coordinates is important here. If you want to find unit vector from P1 to P2 then first parameters have to be x1 and y1. Remember finding the vector from one point to another and finding unit vector from the part 1

Creating Object

Now we need an object that moves in the scene and affected by the radial gravities of planets.

First add a tap event to the runtime

Runtime : addEventListener("tap",createCircle)

Every time we tap on screne “createCircle” function will be called and that’s why we should add a createCircle function to our code.

Ok, below you can see the “createCircle” function. Add this to your code just before the runtime tap event and after the “findUnitVector” function.

local function createCircle(e)
	local redCircle = display.newCircle (e.x,e.y,10)
	redCircle:setFillColor(1,0.2,0)
	redCircle.radius = redCircle.path.radius
	redCircle.velocity = {vx = 0, vy = -3}
	local distanceToGreen
	local distanceToBlue

	function redCircle : enterFrame()
		distanceToGreen = findDistance(self.x,self.y,greenCenter.x,greenCenter.y)
		distanceToBlue = findDistance(self.x,self.y,blueCenter.x,blueCenter.y)

		if(distanceToGreen <= greenRadius + self.radius)then
			local unitVector = findUnitVector(self.x,self.y,greenCenter.x,greenCenter.y,distanceToGreen)
			self.velocity.vx = self.velocity.vx + 0.05*unitVector.x
			self.velocity.vy = self.velocity.vy + 0.05*unitVector.y
		end

		if(distanceToBlue <= blueRadius + self.radius)then
			local unitVector = findUnitVector(self.x,self.y,blueCenter.x,blueCenter.y,distanceToBlue)
			self.velocity.vx = self.velocity.vx + 0.05*unitVector.x
			self.velocity.vy = self.velocity.vy + 0.05*unitVector.y
		end

		self.y = self.y + self.velocity.vy
		self.x = self.x + self.velocity.vx

		if(distanceToGreen <= greenPlanetRadius + self.radius )then
			Runtime : removeEventListener("enterFrame", self)
		elseif(distanceToBlue <= bluePlanetRadius + self.radius )then
			Runtime : removeEventListener("enterFrame", self)
		elseif (self.y <= -10)then
			Runtime : removeEventListener("enterFrame", self)
		end	
	end

	Runtime : addEventListener("enterFrame", redCircle)
end

Lines 38,39 : Create a circle and fill it with red.

Lines 40,41 : Add two variables to your circle. “redCircle.radius” will hold the radius value of circle. “redCircle.velocity” is table that holds the velocity of circle in x and y directions. We can think of “redCircle.velocity” as vector V(0,-3).

Lines 42,43 : Define two variable to hold distances to planets.

Lines 45-73 : Add enterFrame event to runtime, make “redCircle” as listener and add method to redCircle with the name “enterFrame” because “redCircle” is the listener of enterFrame event.

Lines 46,47 : Find distances from “redCircle” to center of gravitational fields of planets buy using “findDistance” function.

Lines 49-53 : Check if “redCircle” is in the gravitational field of “greenPlanet” or not. If it is then find the unit vector from “redCircle” to “greenPlanet”. Multiply unit vector whatever value you want. I think in this case 0.05 is very well working. Add x component of unit vector to x component of velocity of “redCircle” and do the same for the y component to find the final velocity of “redCircle”

Lines 55-59 : Do the same for the “bluePlanet”

Lines 61,62 : Move “redCircle” with the final velocity by adding x component of velocity to x coordinate and y component of the velocity to y coordinate of “redCircle”

Lines 64-70 : Check if “redCircle” has reached the planets or gone too far. If it has then remove the enterFrame event.

That’s all to have a radial gravity without physics engine.You can see the full code below. Please don’t hesitate to ask me questions in your comments. See you in the next tutorial.

local MathSqrt = math.sqrt 
local blueCenter = { x = 160,y =320}
local greenCenter = { x = 270, y = 40}

local blueGravField = display.newCircle (blueCenter.x,blueCenter.y,130)
blueGravField:setFillColor(0,0.7,1,0.2) 
blueGravField.strokeWidth = 1 
blueGravField:setStrokeColor(0,0.7,1)
local blueRadius = blueGravField.path.radius

local bluePlanet = display.newCircle (blueCenter.x,blueCenter.y,20)
bluePlanet:setFillColor(0,0.7,1) 
local bluePlanetRadius = bluePlanet.path.radius

local greenGravField = display.newCircle (greenCenter.x,greenCenter.y,220)
greenGravField:setFillColor(0,1,0.7,0.2) 
greenGravField.strokeWidth = 1 
greenGravField:setStrokeColor(0,1,0.7)
local greenRadius = greenGravField.path.radius

local greenPlanet = display.newCircle (greenCenter.x,greenCenter.y,20)
greenPlanet:setFillColor(0,1,0.7)
local greenPlanetRadius = greenPlanet.path.radius

local function findDistance(x1,y1,x2,y2)
	local distance = MathSqrt( (x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1) )
	return distance
end

local function findUnitVector(x1,y1,x2,y2,distance)
	local unitVector = {}
	unitVector.x = (x2-x1)/distance
	unitVector.y = (y2-y1)/distance
	return unitVector
end

local function createCircle(e)
	local redCircle = display.newCircle (e.x,e.y,10)
	redCircle:setFillColor(1,0.2,0)
	redCircle.radius = redCircle.path.radius
	redCircle.velocity = {vx = 0, vy = -3}
	local distanceToGreen
	local distanceToBlue

	function redCircle : enterFrame()
		distanceToGreen = findDistance(self.x,self.y,greenCenter.x,greenCenter.y)
		distanceToBlue = findDistance(self.x,self.y,blueCenter.x,blueCenter.y)

		if(distanceToGreen < greenRadius + self.radius)then
			local unitVector = findUnitVector(self.x,self.y,greenCenter.x,greenCenter.y,distanceToGreen)
			self.velocity.vx = self.velocity.vx + 0.05*unitVector.x
			self.velocity.vy = self.velocity.vy + 0.05*unitVector.y
		end

		if(distanceToBlue < blueRadius + self.radius)then
			local unitVector = findUnitVector(self.x,self.y,blueCenter.x,blueCenter.y,distanceToBlue)
			self.velocity.vx = self.velocity.vx + 0.05*unitVector.x
			self.velocity.vy = self.velocity.vy + 0.05*unitVector.y
		end

		self.y = self.y + self.velocity.vy
		self.x = self.x + self.velocity.vx

		if(distanceToGreen <= greenPlanetRadius + self.radius )then
			Runtime : removeEventListener("enterFrame", self)
		elseif(distanceToBlue <= bluePlanetRadius + self.radius )then
			Runtime : removeEventListener("enterFrame", self)
		elseif (self.y < -10)then
			Runtime : removeEventListener("enterFrame", self)
		end	
	end

	Runtime : addEventListener("enterFrame", redCircle)
end

Runtime : addEventListener("tap",createCircle)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s