Game Development Community

SideScrolling Gravity

by Jeremy Greiner · in Torque Game Builder · 05/24/2005 (9:25 pm) · 14 replies

I'm playing around with a side scrolling type using all borrowed images for the moment ;) at anyrate I'm having some problems figuring out how to implement falling off the side of a ledge.

Example Video:
www.splice-it.org/video/MegaMan2.wmv

This shows my evil little megaman jumping around the world but not really falling, (except when falling from a jump).

I tried setting a Constant force and he'd pass strait through the tiles.

Any ideas?

PS another video just for fun.
www.splice-it.org/video/MegaMan.wmv

#1
05/26/2005 (6:39 am)
My suggestion for you is to check the bounding box for the two ledges up on top. Those 2 might have introduce bounding box too large on the X axis.
#2
05/26/2005 (8:30 am)
Bounding box?
Hrmm maybe I set it up wrong, I set up collision on all the "land" tiles and set the collision to stop the player from falling.

How does one set up the bounding boxes?
#3
05/26/2005 (6:32 pm)
I've done some searching and reading I know more about bounding boxes now however I didn't see anywhere to set them for a tilemap, which would mean I'd have to create a sprite for each area that I want a bounding box seems a bit much .. I dunno can someone shed some light?

Thanks in advanced
-jeremy
#4
05/28/2005 (4:39 pm)
Hi there,

Usually when you set debug mode on, you should be able to see the bounding boxes.
#5
05/28/2005 (7:03 pm)
Yes I can see the blue box around my tilemap, however I'm unsure how to set up bounding boxes within my tilemap.
-jeremy
#6
05/29/2005 (12:22 am)
If you check the TileEditor.pdf file that comes with T2D, it explains how to draw collision polys for tiles.
#7
05/29/2005 (1:46 am)
Jeremy,

So to be clear; you've setup the players layer/group as well as the tile-layers layer/group and then setup the players collision mask layer/group to collide with the tile-layer? You've then setup your 'ground' tiles with collisions active?

When the game is running (which is starting to look cool BTW) try issuing a "t2dSceneGraph.setDebugOn(BIT(1)|BIT(5))" (obviously use whatever your scene-graph is called). We can then get an idea of what bounding/collision boxes are setup. Could you also post the group/layer as well as the collision group/layer masks for the tilemap and the player.

If you could link to an image with this debug-info running, it'll be helpful.

- Melv.
#8
05/29/2005 (7:54 am)
Ok, here goes.
Screenshot of just bounding box
www.splice-it.org/MegaMan_BoundingBox.jpg
Screenshot of Collision
www.splice-it.org/MegaMan_Collision.jpg
Screenshot of all
www.splice-it.org/MegaMan_All.jpg
Screenshot of All again
www.splice-it.org/MegaMan_All2.jpg
Create Player function:
function Main_CreatePlayer()
{
	$Player = new fxAnimatedSprite2D() { scenegraph = t2dSceneGraph; };
	$Player.setPosition("0 0");
	$Player.setSize( "10 14" );
	$Player.playAnimation(MegaManStandRight);
	$Player.teleportLinkPoint = $Player.addLinkPoint( "0 0" );
	$Player.setVisible( false );
	$Player.setCollisionPhysics(true, true);
	sceneWindow2D.mount($Player, "0 -3.7");
    
	$Player.setGroup( 1 );
	$Player.setLayer( 1 );
	$Player.setCollisionActive( true, true );
	$Player.setCollisionMaterial( standardMaterial );
	$Player.setCollisionPolyCustom( 4, "-0.6 -0.2 0.6 -0.2 0.6 0.8 -0.6 0.8" );
	$Player.setCollisionMasks( BIT(2), BIT(2) );
	$Player.SetCollisionPhysics(false, true);
	$Player.setCollisionCallback( true );
	
}

Create Tilemap
function Main_CreateTileMaps()
{
	// Create tile-map.
	$LevelMap = new fxTileMap2D() { scenegraph = t2dSceneGraph; };
	// Load saved tile-map file.
	
	$LevelMap.loadTileMap("~/client/maps/marioMain.map");
	
	// Load tile layer from tile-map
	$LevelMapMainLayer = $LevelMap.getTileLayer( 0 );
	
	$LevelMapMainLayer.setPosition( "85 -17" );
	$LevelMapMainLayer.setTileSize( "4 4" );
	$LevelMapMainLayer.setWrap( true, false );
	
	$LevelMapMainLayer.setCollisionPhysics(true, true);
	
	$LevelMapMainLayer.SetLayer( 2 );
	$LevelMapMainLayer.SetGroup( 2 );
	$LevelMapMainLayer.SetCollisionActive( false, true );
	$LevelMapMainLayer.SetCollisionMaterial( immovableMaterial );
	$LevelMapMainLayer.SetCollisionMasks( 1, 1 );
	$LevelMapMainLayer.SetCollisionCallback( true );
	
}]/code]

Collision Code:
[code]function fxSceneObject2D::onCollision( %srcObj, %dstObj, %srcRef, %dstRef, %time, %normal, %contactCount, %contacts )
{
	if(%srcObj == $Player)
	{
		%srcObj.setAtRest();
		if(%srcObj.getAnimationName() $= "MegaManDropIn")
		{
			%srcObj.playAnimation(MegaManRightMorph);
			
		}
		else if(%srcObj.getAnimationName() $= "MegaManFallRight")
		{
			$Player.playAnimation(MegaManStandRight);
		}
	}
}

Relevant Datablocks:
datablock fxCollisionMaterialDatablock2D(immovableMaterial)
{
	friction = 0.0;
	restitution = 0.0;
	relaxation = 0.5;
	density = 0.0;
	forceScale = 0;
	damping = 0.0;
};

datablock fxCollisionMaterialDatablock2D(standardMaterial)
{
	friction = 0.3;
	restitution = 0.0;
	relaxation = 0.5;
	density = 0.01;
	forceScale = 1;
	damping = 0.1;
};


That should pretty much cover all the questions and give much more insight to what is going on.
-jeremy
#9
05/29/2005 (8:57 am)
Your player is only receiving collisions but nothing in the scene is sending them. Tile-Layers do not send collisions (there's typically too many elements to do that kind of processing), they receive them only. This means that tile-layers are essentially passive and you always configure objects to collide with them, not the other way around. If the tile-layer moves (pans) then it will seem like the tile-layer collides because the tile-layers typically move "in the way" of other objects.

Your scene comprises of two objects which are receiving only. Try configuring your player to send collisions instead, using something like...
$Player.SetCollisionPhysics(true, false);
You'll also need to apply some kind of constant force for gravity. You'll definately encounter problems with the physics on your platforms with the player slightly overlapping the tiles. This is something I can fix when my current work is complete on the new file-format.

Good Luck,

- Melv.
#10
05/29/2005 (12:32 pm)
I changed the Set Collision and added a constant force, but now I have a problem of him not being able to move, IE the collision seems to be continueing to fire since the object is stopped right on the tiles.

If I remove the SetAtRest .. from the OnCollission, he can move fine but passes through the tiles as if its nothing.

-jeremy
#11
05/29/2005 (8:57 pm)
I basicly solved this problem by
(a) scanning the tiles below a players feet every fxSceneGraph2D::onUpdateScene
(b) if there are no tiles, I consider the player to be airborn and apply a constant force to mimic gravity
(c) as soon as a collisions with the ground occurs , I set the vertical speed to zero and remove the constant force
(d) I also snap the player into a grid position as I noticed that the player is not always exactly on the platform

Good Luck!
#12
05/29/2005 (10:13 pm)
Edo, sounds great!
I figured out how to get the tile at a certian location, but I'm unsure how to get the players' location on the given tilemap.

Also how do you snap into a grid position?

-jeremy
#13
05/30/2005 (3:30 am)
I'll just add to this that platformers will be much easier to put together in the future with the different stock collision-models and the improved physics that are planned. There are several key problems with interpenetration of objects due partly to the simple euler integrator but there are other, more basic problems as well.

In the meantime, I'm sorry for any problems you'll encounter getting this stuff running. It'll all get much better. :)

- Melv.
#14
05/31/2005 (7:59 am)
@Jeremy You need to write a little routine that transforms the player=world coordinates into a tile position XY. As an example, I use the code below - but it only works with my type of tilemap which is 25x32 with tiles of 4x2 units and positioned at ("0 0").

Of course the player coordinates are in the center of your sprite, so you need to add something to get the coordinates at the player's feet. Besides that, I scan two points, left and right, to know on what kind of material is at both the front and the back of his shoe since I want some materials/ledge types to take priority in determining how he should react.

function worldToTileX( %x )
{
	return mFloor((%x + 50) / 4);
}

function worldToTileY( %y )
{
	return mFloor((%y + 32) / 2);
}

function worldToTileXY ( %xy )
{
	return ( worldToTileX(getWord(%xy,0)) SPC worldToTileY(getWord(%xy,1)) );
}

*edit: The snapping back works like this, and ill just paste my code again:

%player.setPositionY ( tileToWorldY( worldToTileY (%player.getPositionY()+1) ) );

It essentially rounds of the players Y coordinate to the grid determined by the Tiles. The +1 is there because my tiles are 2 units high... you can optimize this of course (which reminds me..:).