Quick Links: Download Gideros Studio | Gideros Documentation | Gideros community chat | DONATE
Display Object & Physics Helper Library — Gideros Forum

Display Object & Physics Helper Library

jaywatjaywat Member
edited January 2012 in Code snippets
Hi, everyone.

First post, but a long time lurker - I'm the coding partner of mykyl66.

We've been using... a certain other LUA based SDK up until recently, and gotten used to a certain way of doing things. So in porting some of our existing code to Gideros, I've written some basic helper functions that allow us to set up display objects and physics objects with very similar syntax.

I thought I'd post here in case it's of value to other Gideros users. It should be of particular help to those who have also come from ... that other SDK ... but is hopefully of use generally, since this first draft library allows you to set up a sprite with a physics body in 2 lines of code in a simple way.

So here's a highly commented example main.lua, and the function library itself. Don't forget to add the required 'ball.png' and 'box.png' images (from the original Gideros examples) if you want to see it working as is!

I couldn't see a way to attach the project file to a post, or I'd have done that too.

Lastly, feel free to amend, extend and use as you please, if you find it of use. It's a work in progress, and if I make significant updates (or find any bugs!), I'll post them here.

Cheers,

Jay


main.lua:
-- Demonstrating some basic helper functions to make Gideros behave like ... a certain other LUA based SDK!
 
local myBall = displayImage.new("ball.png")	--  we add a new image, without specifying a group or anything... 
--so by default, it's added to the stage.
 
myBall:setPosition(75,50)	-- so now you can use any of the default Sprite commands to manipulate your image
 
local ballGroup = displayGroup.new()		-- now we define a new display group to hold our sprites/textures.
-- when you define a group, it is assumed that you WANT to immediately add it to the stage. So, by default, you need add no other parameters.
 
ballGroup:addChild(myBall)	-- adds your image to a group. Because the group is already displayed by default, our image is displayed.
 
-- for good measure, I've also made 'addChild' interchangeable with 'insert'! So either will work... 
 
ballGroup:insert(myBall)	-- adds your image to a group.
 
-- now lets do it a slightly different way, that's more like how you tend to work in ... the other SDK:
 
local obstacleGroup = displayGroup.new(false)	-- we define a new display group (but this time add 'false' so that it is 
-- explicitly NOT added to the stage until we want to... this is just to demonstrate that I've added that option!)
 
local myObstacle = displayImage.new("box.png", obstacleGroup)	-- define our image, but, this time, tell it what its parent group is right in the command.
 
stage:insert(obstacleGroup)	-- since I've made insert for 'stage' ALSO interchangeable with 'addchild', we can now display the group at will, 
-- and our sprite will be displayed, since it's a member of this group
 
myObstacle:setPosition(150,250)
 
-- now lets do some physics!
 
-- the necessary stuff:
 
 
require "box2d"
b2.setScale(10)
myworld = b2.World.new(0, 9.8, true)	-- set up a world...
 
local debugDraw = b2.DebugDraw.new()	-- set up debug, if you like...
myworld:setDebugDraw(debugDraw)
stage:addChild(debugDraw)
 
-- 'physicsAddBody' syntax:
-- physicsAddBody(physicsWorld, displayObject, {physicsParameters})
 
-- NOTE: because Gideros can handle multiple physics world, as well as passing in the object to add physics to, you need to pass in
-- the world for which you wish to add it. This is the very first, and mandatory, parameter to pass in.
-- the second mandatory parameter is the object you want to attach the body to, as set up using displayImage.new.
-- The rest of the parameters, like ... the other SDK ... are the physics parameters themselves, as an array. This allows for parameters to be optional,
-- and if not supplied, a 'sensible default' is substituted.
-- you can do this...
 
physicsAddBody(myworld, myBall, {type = "dynamic", density = 1.0, friction = 0.3, bounce = 0.9, radius = 40}) -- create a physical, dynamic circle for our ball.
 
physicsAddBody(myworld, myObstacle, {type = "static", density = 1.0, friction = 0.3, bounce = 0.2}) -- create a static square for our box. note that I don't even supply a size. By default it uses the image width and height.
 
-- or, of course, this, if its easier...
--myParameters = {type = "static", density = 1.0, friction = 0.3, bounce = 0.2}
--physicsAddBody(myworld, myObstacle, myParameters)
 
-- 'physicsAddBody' parameters:
-- These are all optional, and defaults are supplied if you don't explicitly define their values:
-- type. One of "dynamic", "kinetic" or "static". If not supplied, is assumed to be dynamic.
-- width. The default is the width of the texture of the object you're defining a physics body for, but can be overridden, in which case, the object is positioned centred over the sprite
-- height. The default is the height of the texture of the object you're defining a physics body for, but can be overridden, in which case, the object is positioned centred over the sprite
-- radius. If supplied, the physics shape will be defined as a circle, rather than a box. radius OVERRIDES, and therefore ignores, width and height.
-- density. If not supplied, defaults to 1.0
-- friction. If not supplied, defaults to 0.0
-- bounce. ie, restitution, as far as Gideros is concerned. you can actually supply it as either... but don't supply both! ok. if you do, restitution trumps bounce. 
-- isSensor. true/false. If not supplied, assumed false.
 
-- you can now use the normal physics functions to get or set parameters by referring to object.body or object.fixture
--e.g.
 
local sx, sy = myBall.body:getPosition()
print ("sx,sy: " .. sx,sy)
 
-- or
print (myBall.fixture:isSensor())
 
-- or 
--myBall.fixture:setSensor(true)
 
 
--so, putting it all together, you could do something like:
 
local anotherBallGroup = displayGroup.new()
 
for b = 1, 5 do
	local myBall = displayImage.new("ball.png", anotherBallGroup)	
	myBall:setPosition(math.random(320),math.random(100))
end
 
for p = 1, anotherBallGroup:getNumChildren() do
	physicsAddBody(myworld, anotherBallGroup:getChildAt(p), {type = "dynamic", density = 1.0, friction = 0.3, bounce = 0.9, radius = 40}) -- create a physical, dynamic circle for our ball.
end
 
-- et voila! 5 dynamic, physical bouncy balls!
 
-- if you're not explicitly naming your objects, remember you can refer to them like:
 
print(anotherBallGroup:getChildAt(4).fixture:isSensor())
 
-- also, if you want the debug draw on top of your objects, remember to make it the final call to the stage!
 
stage:addChild(debugDraw)
 
-- lastly, you need the enterframe event to update the physics. You need to call 'updatePhysicsObjects' with a parameter of the physics world to update.
-- In order to pass in a parameter, the call itself needs to be a function, like so:
 
stage:addEventListener(Event.ENTER_FRAME, function() updatePhysicsObjects(myworld); end)


Likes: mykyl66, MikeHart, atilim, bravcm

Dislikes: vovanich

+1 -1 (+4 / -1 )Share on Facebook

Comments

  • jaywatjaywat Member
    edited January 2012
    and here's the sss-functionlib.lua:
    --[[ 
     
    This is a helper library class created by Shark Soup Studios
    <a href="http://www.sharksoupstudios.com" rel="nofollow">http://www.sharksoupstudios.com</a>
     
    Feel free to use, amend, extend as needed!
     
    ]]
     
    displayGroup = gideros.class(Sprite)
    displayImage = gideros.class(Sprite)
     
    function displayGroup:init(addToStage)
    	if addToStage == nil then addToStage = true; end
    	if addToStage then
    		stage:addChild(self)
    	end
    	self.group = true
    end
     
    function displayImage:init(texture, displaygroup)
    	local thisImage = Bitmap.new(Texture.new(texture))
    	self:addChild(thisImage)
    	self.image = thisImage
    	if displaygroup then
    		displaygroup:addChild(self)
    	else
    		stage:addChild(self)
    	end
    end
     
    function displayGroup:insert(sprite)
    	self:addChild(sprite)
    end
     
     
    function stage:insert(sprite)
    	self:addChild(sprite)
    end
     
    function physicsAddBody(b2world, object, args)
    	local bodyDef = {}
    	if args.type then
    		if args.type == "static" then
    			bodyDef.type = b2.STATIC_BODY
    		elseif args.type == "kinematic" then
    			bodyDef.type = b2.KINEMATIC_BODY
    		elseif args.type == "dynamic" then
    			bodyDef.type = b2.DYNAMIC_BODY
    		else
    			bodyDef.type = b2.DYNAMIC_BODY
    		end
    	end
     
    	bodyDef.density = args.density or 1.0
    	bodyDef.restitution = args.bounce or 0.0
    	if args.restitution then
    		bodyDef.restitution = args.restitution
    	end
    	bodyDef.friction = args.friction or 0.0
    	bodyDef.isSensor = args.isSensor or false
     
    	if args.width then
    		bodyDef.width = args.width
    	else
    		bodyDef.width = object:getWidth()
    	end
     
    	if args.height then 
    		bodyDef.height = args.height
    	else
    		bodyDef.height = object:getHeight()
    	end
     
    	if args.radius then
    		bodyDef.radius = args.radius
    	end
     
    	local thisShape
    	local thisBody = b2world:createBody({type = bodyDef.type})
     
    	bodyDef.x = math.floor(object:getX() + bodyDef.width/2)
    	bodyDef.y = math.floor(object:getY() + bodyDef.height/2)	
     
    	if args.radius then
    		bodyDef.width = object:getWidth()
    		bodyDef.height = object:getHeight()
    		bodyDef.x = math.floor(object:getX() + (bodyDef.width/2))
    		bodyDef.y = math.floor(object:getY() + (bodyDef.height/2))
    		thisShape = b2.CircleShape.new(0, 0, bodyDef.radius)
    	else
    		thisShape = b2.PolygonShape.new()
    		thisShape:setAsBox(bodyDef.width/2, bodyDef.height/2)
    	end
     
    	local thisFixture = thisBody:createFixture{shape = thisShape, density = bodyDef.density, restitution = bodyDef.restitution, friction = bodyDef.friction, isSensor = bodyDef.isSensor}
    	thisBody:setPosition(bodyDef.x, bodyDef.y)
     
    	object.image:setAnchorPoint(0.5, 0.5)
    	object:setPosition(bodyDef.x, bodyDef.y)
     
    	object.body = thisBody
    	object.fixture = thisFixture
    end
     
     
     
    local function updatePosition(object)
    	local body = object.body
    	local bodyX, bodyY = body:getPosition()
    	object:setPosition(bodyX, bodyY)
    	object:setRotation(body:getAngle() * 180 / math.pi)
    end
     
    function updatePhysicsObjects(physWorld)
    	physWorld:step(1/60, 8, 3)	-- edit the step values if required. These are good defaults!
    	for i = 1, stage:getNumChildren() do
    		local sprite = stage:getChildAt(i)
    		-- determine if this is a sprite, or a group
    		if sprite.group == nil then
    			local body = sprite.body
    			-- if it's not a group, but HAS a body (ie, it's a physical object directly on the stage)
    			if body then
    				updatePosition(sprite)
    			else 
     
    			end
    		elseif sprite.group == true then
    			-- if it IS a group, then iterate through the groups children
    			for j = 1, sprite:getNumChildren() do
    				local childSprite = sprite:getChildAt(j)
    				local body = childSprite.body
    				if body then
    					updatePosition(childSprite)
    				end				
    			end
    		end
    	end
    end

    Likes: atilim, bravcm

    +1 -1 (+2 / -0 )Share on Facebook
  • mykyl66mykyl66 Member
    edited January 2012
    The main purpose of this is to allow easy concepting of physics based games very quickly (which we liked in the other language) but have the freedom of total control over your physics that gideros gives you when you find a concept you want to continue with.

    The major commenting was for my benefit, not to teach you guys to suck eggs. ;)

    Cheers

    Mike R
    What would you do for your other half?

    http://www.sharksoupstudios.com
    +1 -1 (+3 / -0 )Share on Facebook
  • Awesome, I will point people to your lib which ask me sometimes about switching from the mexican beer SDK over to gideros. Thanks a ton!

    That deserves a twitter post. :)
  • gorkemgorkem Maintainer

    That deserves a twitter post. :)
    Fired :)
  • gorkemgorkem Maintainer
    Hehe - I meant "armed" - it's queued for 3:21 PM CST (I use timely.is service). ;-)
  • I think I've guessed the "other" SDK. I've also had half finished game there, which I wanted to port to Gideros.

    So you're a life saver. ;)
  • OZAppsOZApps Guru
    edited January 2012
    I have a little tidier version of the same that I can work on as I get some time, with that library, you can just compile your code without any changes, in fact you can have some more features.


    image

    cheers,

    ?:)
    twitter: @ozapps | http://www.oz-apps.com | http://howto.oz-apps.com | http://reviewme.oz-apps.com
    Author of Learn Lua for iOS Game Development from Apress ( http://www.apress.com/9781430246626 )
    Cool Vizify Profile at https://www.vizify.com/oz-apps
    +1 -1 (+3 / -0 )Share on Facebook
  • mykyl66mykyl66 Member
    edited January 2012
    Perfect. Where can we get it? We were wary of getting too close as it seems to imply that the other is the better... if you get what I mean. However anything that can work is perfect in my opinion.

    Mike
    What would you do for your other half?

    http://www.sharksoupstudios.com
  • gorkemgorkem Maintainer
    @mykyl66 may or may not be true, depending on how you look at the things. There are several times in business where a migration processes, documentation and tool are provided, like:

    - Migration from KVM to VMware
    - Migration from Solaris to Red Hat
    - Migration from Exchange to Zimbra
    - Migration from PC to Mac

    In these examples, I cannot fully say "one is superior to another", as it's mostly related to perception management. I cannot also claim that this Lua based framework is better than that framework, but I can WHOLEHEARTEDLY say that we LOVE Gideros Studio :x

    But I also got your point.

    Gorkem
  • Absolutely. If you want/need more control Gideros Studio is the ONLY way to go.

    Mike
    What would you do for your other half?

    http://www.sharksoupstudios.com
  • @Mykyl66, I am not sure about one being better or not. You can use Gideros the way it was meant to be, however, if for whatever reason, the alternative beer framework makes is difficult to continue with your subscription or whatever, you will not loose your work, all of that can be ported over and compiled, so you can continue to use that framework, or mix and match and use native gideros APIs. It is for not being held hostage at one framework.

    How to get it? This was a sample/proof of concept to prove that a 1:1 port for many of the API's can be made, the same can be made but might be at a cost, after all it is time and effort put into creating and testing. So will inform of the costs soon as I figure out when I can get this completed.

    cheers,

    ?:)
    twitter: @ozapps | http://www.oz-apps.com | http://howto.oz-apps.com | http://reviewme.oz-apps.com
    Author of Learn Lua for iOS Game Development from Apress ( http://www.apress.com/9781430246626 )
    Cool Vizify Profile at https://www.vizify.com/oz-apps
  • Just wanted to point out for clarity again.
    This library is purely to help do quick physics concepts within gideros studio.
    Basically the beer framework markets itself based on create this game in 8 minutes and another in 30 minutes etc.
    The real truth is you can concept a game in that amount of time. In Gideros its not quite so straight forward and these tools are to speed up physics based concepts within Gideros.

    I will say it again. The beer framework is perfect for fast concepting of ideas but not so good at giving us the developers total control if and when you hit upon a solid concept.

    Mike

    Likes: gorkem

    What would you do for your other half?

    http://www.sharksoupstudios.com
    +1 -1 (+1 / -0 )Share on Facebook
Sign In or Register to comment.