Quick Links: Download Gideros Studio | Gideros Documentation | Gideros community chat | DONATE
Box2DEasy: how to update physics properties of child sprites — Gideros Forum

Box2DEasy: how to update physics properties of child sprites

bayopbayop Member
edited July 2013 in Game & application design
I'm working on a game porting project (So much of the assets are inheritted) and we eventually selected Gideros as the tool of choice.
I'm now working on integrating the box2d physics with Box2DEasy (which I think is fantastic by the way). However, I'm having a little trouble with my tileMap implementation. I was unable to use the default tileMap implementation, because I need the ability to add box2d physics properties to individual tiles. My implementation is very simple and is reproduced below;
TileLayer2 = Core.class(Sprite)
 
function TileLayer2:init(name, width, height, texturePack, tilewidth, tileheight, tileMap, physics )
	self.layers = {}
	self.id = name
	local layer1 = Sprite.new() 
	local layer2 = Sprite.new() 
 
	self.layers = {layer1, layer2}	
	self.currLayer = layer1	
 
	loadTileMap(name, self.layers, texturePack, tileMap, width, height, physics)	
 
	layer1:setPosition(0, -layer1:getHeight() + screenH)
	layer2:setPosition(0, screenH)
 
	self:addChild(layer1)
	self:addChild(layer2)	
end
 
local function loadTileMap(name, layers, texturePack, tileMap, width, height, physics) 
	local blank_tile = Texture.new(getImgBase() .. "blank_tile.png")
	for y = 0,height -  1 do
		for x = 0,width - 1 do			
			local gid = tileMap[tonumber(y+1)][tonumber(x+1)]														
			for i = 1,#layers do
				local tile = {}
				if gid == 0 then
					tile = Bitmap.new(blank_tile)
				else 
					tile = Bitmap.new(texturePack:getTextureRegion("t" .. gid))
					local conf = {type="kinematic", width=10, height=10}					
					if physics then
						if physics.isSensor then
							conf.isSensor = physics.isSensor
						end
						if physics.type then
							conf.type = physics.type
						end
						physics.parent:createRectangle(tile, conf)
						--tile.body.id = name .. "-t" .. gid
					end 
				end				
				tile:setAnchorPoint(0.5,0.5)
				tile:setPosition((x+0.5) * tile:getWidth(), (y+0.5) * tile:getHeight())
				layers[i]:addChild(tile)			
			end
		end
	end
end
Quite simply, I create two sprite objects and then add individual tiles and child sprites. As the screen scrolls, I then switch between layers just before the current layer scrolls out of view (endless scrolling type game). However, it appears the position of the tile sprites' physics bodies are not updated whenever I call setPosition.

Essentially, I need to know how to ensure that physics properties of child sprites are updated whenever a change is made on the primary sprite that was added to a scene.

Comments

  • john26john26 Maintainer
    In Gideros, physics bodies are completely separate from sprites. It's up to you to "paint" the sprite on top of the physics body. In the update loop, you should setPosition the sprite at the (x,y) coord of the physics body every frame. Think of box2d as an engine for generating (x,y) coordinates (and rotations).

    Also, there is no hierarchy of physics bodies: bodies do not have children (except that they can have multiple fixtures, but these must be fixed relative to each other)
  • ar2rsawseenar2rsawseen Maintainer
    edited July 2013
    Yes basically @john26 is right. Box2dEasy is what made bodies move when sprites are changed and vice versa.
    In reality it all happens like this:
    http://appcodingeasy.com/Gideros-Mobile/Gideros-Box2D-basics

    But since you are using Box2DEasy, they should have been updated. I think there reason here might be that box2d body positions are absolute, while Sprite child positions are relative to the layer.

    The fix would be, in the same code, where you applied your fix from previous post, to use sprites global coordinates, like this:
    if self._offX then
    	value = value + self._offX
    end
    value = math.round(value)
    if self.body then
    	local x,y = self.body:getPosition()
    	local globalX, globalY = self:localToGlobal(value, y)
    	self.body:setPosition(globalX, y)
    end
    Similar thing should be done with y value provided in Sprite:setPosition inside GCE :)
    As I'm now my ears deep in something else, I can't really try it, but will experiment more with GCE and B2DE when will have more time ;)
  • bayopbayop Member
    @ar2rsawseen, thanks for the tip, unfortunately it didn't work, I'll keep trying to figure it out though.

    Cheers
  • bayopbayop Member
    @ar2rsawseen

    Have you had some time to look into this? You were right about the cause, but I'm at a loss as to how to fix it, all the stuff I've tried keep messing things up.

    I'm also trying to avoid breaking functionality within the GiderosCodingEasy library due to naive modifications
  • ar2rsawseenar2rsawseen Maintainer
    Unfortunately GCE and B2DE have been a free time projects, and my weekends are currently booked with other project almost till the end of summer.

    Still I will try to find some time to check it out. And if you want, you can help by preparing a small Gideros project that demonstrates the flaw and attaching to this thread.
  • bayopbayop Member
    @ar2rsawseen thanks for the assist, it's amazing the value both GCE and B2DE offer considering the fact that it is a side project. Looking forward to when it will be fully integrated.

    This is the simplest demo I could come up with. At it's bare essence, I manually create a Tile Map using a two directional array and lots of individual sprites, all contained in a parent sprite (the TiledLayer class). Some of the layers need to be able to interact with the player and NPCs, so I added physics properties to them.

    At initialization, I update the layer position at line 53, TiledLayer2.lua and this works normally. However, the attached physics bodies are not updated relative to their parent sprite.

    You can try to comment the line to see the tiles properly aligned to their respective parents.

    Hope this helps to lead to a resolution.
    zip
    zip
    Box2dBugDemo.zip
    125K
  • ar2rsawseenar2rsawseen Maintainer
    @bayop wow this will actually be kind of pretty hard thing to achieve.

    You see Box2DEasy is defined to take bodies position, and change sprites position to match bodies. Since bodies position is always in global coordinate, but sprites can have offsets, because of layers and local coordinates, there can be problems. But actually those problems would be quite easy to fix.

    On the other hand what you have is something completely different. You move layers, thus sprites move, changing their global coordinates, while local stays the same. And then what you need is to take sprites global coordinates, and match bodies coordinates to them. Which is completely reverse process and would probably break any underlying physics simulations.

    Now what you want to achieve is probably not impossible, but needs another approach.

    So can you elaborate a little more, what do you use physics for, so I could try suggest a better approach? Like is it needed only for collisions, or you will also be emulation physics and gravity, etc.
  • john26john26 Maintainer
    @bayop, I think the problem you are facing is due to trying to use an "easy" high level system to do something really complicated. The "easy" system is designed to make life easier for new programmers doing standard stuff but you always trade ease of use for flexibility. In your case (as often happens) it's actually making life harder! You would be better engaging with the fundamental properties of Box2D: bodies, fixtures and joints. Read the C++ Box2D manual to see how it really works. Gideros implements Box2D just as it appears in the original C++ library.
  • ar2rsawseenar2rsawseen Maintainer
    @john26 also true, but the easy system can also be somewhat extensible.

    For example, it might be possible to implement additional option when creating body, with which it would be possible to specify weather sprite should follow body, or body should follow sprite.

    But again that won't cover all the cases, and in some misuse might break the whole physics emulation, thus I wanted to see what exactly @bayop is up to :)
  • bayopbayop Member
    I'm just trying to create an endless scrolling car racing game and have box2d handle physics for sprite/background and sprite/sprite collisions (to achieve a more realistic effect). Essentially, the screen position is constantly updated to keep the primary character centered on screen (y axis only). Then the position of the custom tiled layers (which are duplicated) are constantly checked to see if the view is running out of background and if so, the duplicate layer is then positioned in-front or behind the layer in the view (depending on direction the player is heading in).

    The reason why I implemented the tiled layer as seen in the attached sample is because we are attempting to port the app from a different platform (J2ME) and we are trying to re-use the existing assets and algorithms.

    I guess my question would then be... How should can we implement an endless scroller (with updating background positions) and also include physics? I know it's possible I guess I just may not be using the best approach.

    Here's a short clip of the game in play
  • bayopbayop Member
    @john26

    I agree with your comment on Box2DEasy being an easy system, I am a Gideros newbie albeit with some game development experience. I have read through a tutorial on the C++ library, and some of the samples using Gideros' vanilla box2d implementation and there were a few things I felt were missing which I felt B2DE would help fix such as anchorPoints on sprites, verbose code for setting up physics bodies etc.

    Right now there's no guarantee that switching to the plain unmodified version will solve this issue, but I'm open to suggestions.

  • bayopbayop Member
    Small update!!!

    I reverted to the vanilla box2d implementation and the issues persist (I suspected it would). I believe there must be a straight forward way around this cos I've applied this approach with Corona and it worked.
  • ar2rsawseenar2rsawseen Maintainer
    From the looks it seems you won't be using gravity, velocities etc, so it should be possible to set it reversely to follow the sprite.
    I will try a little experiment tomorrow and try to provide you with a possible solution ;)
  • I'm just trying to create an endless scrolling car racing game and have box2d handle physics for sprite/background and sprite/sprite collisions (to achieve a more realistic effect). Essentially, the screen position is constantly updated to keep the primary character centered on screen (y axis only). Then the position of the custom tiled layers (which are duplicated) are constantly checked to see if the view is running out of background and if so, the duplicate layer is then positioned in-front or behind the layer in the view (depending on direction the player is heading in).
    You do not need Physics for this,
    the background scrolls at the rate of the speed your bus is going at,
    the other vehicles scroll at their own speed
    the collisions are simply a function to check two overlapping rectangles

    even if you want to implement friction in your code, to simulate gradual slowing or speeding up, try multiplying or dividing the speed by 0.9 (adjust accordingly)

    This is just advice, I am sure you love and want to use Physics; knock yourself out but if you want something simple and that works avoid all the fancy stuff.
    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
  • bayopbayop Member
    Thanks @OZApps

    I understand what you mean about us not absolutely needing physics for this game. However, during the time I was developing the J2ME implementation, a lot of time was wasted trying to get the vehicle collisions to work right i.e. rebound properly after a collision, not having two items perpetually stuck together; that kind of stuff. I really felt that moving to a box2d implementation would save us some time in implementation, but I guess that I might have been wrong.

    @ar2rsawseen

    I do appreciate all you help and will look forward to a possible work around. You are partially right about the game though, I was planning to use velocities (and forces), but yes there will be no need for gravity in the game.

    I must say though that I am overwhelmed by the responsiveness of the community and very impressed by what Gideros has to offer. Hopefully, I'll be getting the hang of it sooner riather than later...
  • john26john26 Maintainer
    @bayop you should NOT update the box2D body positions using body:setPosition() in order to position the cars on screen. Instead, just let the car bodies move according to what box2D says and scale the positions of the sprites so the player car is in the center of the screen (so that we "follow" the car body). So if the player car is at y0, position each sprite at y-y0+yc (yc: centre of screen). This will work! Of course you will eventually have to move the bodies when they get to the end of the track, you will need to reposition at the beginning but that's just one body move not one per frame!

    In Gideros, remember, there is a separation between sprites and physics bodies allowing you to do the trick just described. Corona does not allow this making scrolling physics games "difficult".
  • bayopbayop Member
    Thanks @john,

    That's what I'm doing for the car sprites; their positions are based on the position of the player car.

    The problem is that my tiled map implementation (composed of many sprites, some of which have physics bodies attached ) has to be updated as the game screen scrolls so that the player never runs out of background, so I have to call setPosition() on my TiledLayer to reposition it just as it is about to be exhausted. I'm not calling body:setPosition() for car placements.
  • john26john26 Maintainer
    You will need to call body:setPosition() when you run out of road. Resetting sprites will not reset bodies (in the vanilla approach). Did you try this?
  • ar2rsawseenar2rsawseen Maintainer
    @bayop actually what @john26 says makes sense.
    What he tries to tell you, that you should not move the tilemap layer yourself, but rather let box2d body move it.
    It might be tricky to add new layers, but it should work.
    I'll try to implement something similar now :)
  • ar2rsawseenar2rsawseen Maintainer
    Here s an example project of never ending scroller with box2d objects added to each layer :)

    zip
    zip
    Box2D_camera_move_with_layers.zip
    68K
Sign In or Register to comment.