Author Topic: Detailed water physics  (Read 1437 times)

superbany

  • Member
  • **
  • Posts: 53
  • Karma: +0/-0
  • [Please enter text here]
    • View Profile
    • Superbany's games
Detailed water physics
« on: Tue, Jan 4, 2011 »
For my platformer, I'm making some areas that will be filled up with water, so I need some new physics for them. What I'm trying to get is the player to swim on top of the water until down is pressed, which then they will use underwater physics and the air meter will go down (Think of the 3d Mario games like Super Mario Sunshine). I've gotten it to work almost perfectly, except for a few bugs.

Current Code:
Code: [Select]
//PLAYSTATE'S CREATE:
_water.add(new Water_top(144, 1938));
_water.add(new Water_top(96, 1938));
_water.add(new Water_top(48, 1938));
_water.add(new Water_top(0, 1938));
_water.add(new Water(144, 1984));
_water.add(new Water(96, 1984));
_water.add(new Water(48, 1984));
_water.add(new Water(0, 1984));

add(_water);


//PLAYSTATE'S UPDATE:
_curWater=PlayerGroup.inWater;  //Player's location in water previous frame.
super.update();

_playerWater = 0;
FlxU.overlap(_playerBody, _water, waterOverlapped);
_hpBar.setWater(_playerWater);
_player.setWater(_playerWater);


//WATEROVERLAPPED
protected function waterOverlapped(PlayerObject:FlxObject, WaterObject:FlxObject):void
{
if (!_playerEyes.overlaps(WaterObject)) //Eyes are above water, meaning player can breathe.
{
if (FlxG.keys.pressed("S"))
_playerWater = 1;
else
_playerWater = -1;
}
else  //Player's eyes are below water level, but not necessarily because they are swimming underwater.
{
if (_curWater == -1) //If the player was supposed to be on top, sends them back upwards.
{
_playerBody.velocity.y = -10;
_playerWater = -1;
}
else  //Player can continue sinking.
_playerWater = 1;
}
}

For _playerWater and _curWater, -1 is floating on top of water, 0 is out of water, and 1 is underwater.

In the update(), a temporary variable _playerWater is assigned as 0, which is then changed depending on if the player overlaps the _water group, then both the health bar and player are told, so that they know whether or not the player should be losing air.

You can see it here: http://www.newgrounds.com/dump/item/051720a5136a54a27e994162aba51217
The two problems are that:
1) This only works in the top half of the body of water, not the bottom (press B to see the divisions)
2) Crossing a vertical boundary between water tiles going left causes the player to think they should be floating on top.


Problem 1 should be able to be solved by replacing <!_playerEyes.overlaps(WaterObject)> with <!_playerEyes.overlaps(_water)> to check for the entire group, not just one sprite, but this does not ever return true.

I think Problem 2 is related to the order in which the water is added to the state, but I'm not sure.


If anybody has any ideas on how to fix this, that would be great. Please also ask if you need to see other code. Thanks for any help you can give.

zez

  • Active Member
  • ***
  • Posts: 203
  • Karma: +0/-0
    • View Profile
    • Devlog
Re: Detailed water physics
« Reply #1 on: Wed, Jan 5, 2011 »
I could be totally off-base on this, but I think both of them happen because your player is overlapping any given water object before the eyes get a chance (and thus the only instance where _playerWater != -1 is when you press "S"). Too solve problem 1, make the bounding box of the eyes go a pixel or two higher then the top of the player, too solve problem 2, make the bounding box go a pixel or two too the left and right of the player (so tweak height, width, and offset of the eyes.)

If Im right, problem 2 is happening because the eyes arent overlapping THAT WaterObject yet, and problem 1 is just the player hitting the water before his eyes.

Note that even if the Eye object is sized too be as wide / high up as the player, if you have something like eyes.x = x; eyes.y = y; in your players update, there is still a good chance the player will overlap the water before the eyes.

You also may want to play around with putting eyes.x = x; eyes.y = y before or after the update and see if that helps any.

superbany

  • Member
  • **
  • Posts: 53
  • Karma: +0/-0
  • [Please enter text here]
    • View Profile
    • Superbany's games
Re: Detailed water physics
« Reply #2 on: Wed, Jan 5, 2011 »
Figured out how to fix problem 2. My custom command _player.resetEyes() [puts the eyes in the correct place relative to the body] was taking place after the overlaps, when it should have been placed after the tile collisions but before the overlaps. I also fixed it so that pressing S anytime sets the swim type to underwater.
See it again here: http://www.newgrounds.com/dump/item/051720a5136a54a27e994162aba51217

Newer code:
Code: [Select]
//UPDATE
_player.collide(tiles)
_player.resetEyes();
_playerWater = 0;
FlxU.overlap(_playerBody, _water, waterOverlapped);  //Skips if player is not in water at all
_hpBar.setWater(_playerWater);
_player.setWater(_playerWater);


//WATEROVERLAPPED
if (!_playerEyes.overlaps(WaterObject))
{
_playerWater = -1;
}
else
{
if (_curWater == -1)
{
_playerBody.velocity.y = -10;
_playerWater = -1;
}
else
_playerWater = 1;
}

if (FlxG.keys.pressed("S"))
_playerWater = 1;

I'm not really sure how to fix problem 1, but I don't think your suggestion will work. I'll try it out and see if it fixes it.

superbany

  • Member
  • **
  • Posts: 53
  • Karma: +0/-0
  • [Please enter text here]
    • View Profile
    • Superbany's games
Re: Detailed water physics
« Reply #3 on: Thu, Jan 13, 2011 »
What I'm thinking of doing is to have all that programming in WaterOverlapped only activate if the overlapped water object is the highest one in the group overlapping the player, so that if the player is between two, they will only overlap with the higher one, keeping them with underwater physics.

What I need to know though, is if I need to create a whole new variable for the state. Will I have to put a <protected var _highWaterY> and do the code only if WaterObject.y < _highWater (resetting _highWater to a really high value like 9999 every frame, and updating it if WaterObject.y is less than it), or can I just put a <var highWaterY> at the beginning of WaterOverlapped, since its overlapping with a single FlxGroup?

Or is there a better way to do what I'm trying to do? Thanks for any help.

superbany

  • Member
  • **
  • Posts: 53
  • Karma: +0/-0
  • [Please enter text here]
    • View Profile
    • Superbany's games
Re: Detailed water physics
« Reply #4 on: Tue, Jan 18, 2011 »
Well, I finally got it to work. I have to have a separate variable for the state called <highWaterY>, but that's not that big of a deal.

Here's the new code.
PlayState's update:
Code: [Select]
highWaterY = 9999;
_playerWater = 0;
FlxU.overlap(_playerBody, _water, waterOverlapped);
_hpBar.setWater(_playerWater);
_player.setWater(_playerWater);
PlayState's waterOverlapped function (with parameters PlayerObject and WaterObject):
Code: [Select]
if (WaterObject.y <= highWaterY)
{
WaterObject.flicker(.1);  //Just for debugging
highWaterY = WaterObject.y;

if (!_playerEyes.overlaps(WaterObject))
{
_playerWater = -1;
}
else
{
if (_curWater == -1)
{
_playerBody.velocity.y = -10;
_playerWater = -1;
}
else
_playerWater = 1;
}
}

if (FlxG.keys.pressed("S"))
_playerWater = 1;
And see it again here: http://www.newgrounds.com/dump/item/051720a5136a54a27e994162aba51217 (the flickering is just to show which water block the physics are being taken from)


What its doing is constantly resetting highWaterY to 9999 (or any really large number), then changing it whenever the overlapped water block's y is less than or equal to it. This is also the only time that the physics are redone, meaning the player will only be swimming in the higher up block(s). This way, the player will only float on the very top of the water, not in-between the sections.

I'll probably want to move the button control for sinking below the surface into the player's coding and make it not need to be held down, but that won't take much work. I'll also probably want to use the level height (about 2500) instead of 9999.
Unless anybody has any suggestions on how to improve this, problem solved.