[PLUGIN] agsbox2d 0.5.0 - realistic physics for 2D worlds

Started by eri0o, Sun 08/09/2019 23:51:42

Previous topic - Next topic

lorenzo

I tried the plugin during the weekend, by modifying the code in the demo, trying to make some new objects, etc. It's really impressive!

Your guide in the first post is pretty useful, but it would be nice to have a demo with comments explaining what the code does. I think it could be beneficial for people like me who aren't good with coding. The demo right now is pretty cool and helped me figure out how to use some of the plugin's functions, but a few more comments would've helped!

Anyway, great job! It's fantastic to see physics in AGS.

eri0o

Hey @Lorenzo, thanks for testing it! I recognize I still need to add a better tutorial somewhere. I also created a task for myself to comment all code that I want to tackle soon.

Cheer @Mehrdad, hopefully we get somewhere.

Added a new Room at the game project and added a new Module script in the demo called Boxify.



The idea of the Boxify Module script is, if the object or character requirements in physics is relatively dull, this module simplifies the linking of the objects with the physics world:

Code: ags

function room_Load()
{
  Boxify.Character(player, AgsBox2D.CreateRectangleShape(12.0, 34.0));
  Boxify.Object(obj_box1);
  Boxify.Object(obj_box2);
  Boxify.Object(obj_box3);
  Boxify.Object(obj_box4);
  Boxify.Object(obj_box5);
  Boxify.Object(obj_box6);
  Boxify.Object(obj_barrel1);
}


More details in the code of the Room script...

I still need to figure more things out and I may conclude that making this module is not practical since it's hard to predict usages for elements in the world, so basic idea it implements is it keep tracks which fixtures and bodies have corresponding room objects or characters, and moves them appropriately after we step a bit of time in the world simulation.

lorenzo

That looks so cool, can't wait to try the new demo!

eri0o

@lorenzo, below is the first example commented. I was going to add to the first post, but it exceeded the character limit for the forum. I actually wanted to add a release today, but I encountered a last minute little bug that I am not sure yet how to tackle.

Let's break down this code now. We will create a world, the world is where all the physics simulation happens.
Nothing in Box2D "exists", it just calculates a bunch of numbers that we can use.
To help visualize these numbers, it also offers a debug image, where the shapes and their movements are drawn, as if these numbers had a meaning. We are going to use this debug image to show these shapes moving on the screen.

Code: ags

World* world; // If the world doesn't exist, everything in it is gone as well, se we make this "global" to our room.
Overlay* ov; // The overlay is merely for showing the debug sprite on screen.

struct Physical {  // This struct will help hold important pointers for us.
  Body* body;      // The body is a point in the simulation world
  Shape* shape;    // A shape can have many forms, for now we will use only Rectangles and Circles.
  Fixture* fixture; // A fixtures attaches a shape to a body, enabling the body the ability to collide with other bodies that have shapes attached to them.
};

Physical ground; // We are going to create just a single platform as ground
Physical ball; // And a ball is going to be our "player" here


The above code is just to be able to receive pointers to the things we are going to simulate. Note that the "Physical" struct was arbitrary . We don't actually need to hold pointers to anything but the world, unless we need them later.

Code: ags

function room_Load()
{
   // this check will prevent recreating this world if we enter again in this room later on.
  if(world == null){
    // The line below says in our world, 32 pixels means 1 meter. So, a 1.8 meter character would have 58 pixels in height.
    AgsBox2D.SetMeter(32.0); // The physics simulation is tuned to work best from 0.1 to 10 meters, so in this world, 3 px to 320 px in size are good.
    // NOTE: 32.0 is the default, so if you don't set any value, 32 pixels will be equal to 1 meter.

    world = AgsBox2D.CreateWorld(0.0, 9.8*AgsBox2D.GetMeter()); //We create the world, and set the gravitational acceleration as we wish.
    // Positive y is down in AGS. Also, since we are talking in pixels, acceleration has to be set in pixels per squared seconds.

    ground.body = AgsBox2D.CreateBody(world, 160.0, 160.0, eBodyStatic); // This creates a static body, at the 160 pixels x and 160 pixels y in the world. It's just a point.
    ground.shape = AgsBox2D.CreateRectangleShape(320.0, 40.0); // This creates a rectangle of 320 pixel width and 40 pixels height, but this rectangle doesn't exist anywhere.
    ground.fixture = AgsBox2D.CreateFixture(ground.body, ground.shape); // This copies the rectangle we created, and attaches this copy center point on to the body. Because the body is static, it's mass is infinite.

    ball.body = AgsBox2D.CreateBody(world, 160.0, 40.0, eBodyDynamic); // This creates a dynamic body at the position 160, 40 in the world. It's a point.
    ball.shape = AgsBox2D.CreateCircleShape(20.0); // This creates a circle of 20 pixels radius, but this circle doesn't exist anywhere.
    ball.fixture = AgsBox2D.CreateFixture(ball.body, ball.shape, 1.0); // This copies the circle we created, and attaches this copy center point on to the body, it's density is 1/(32*32) kg per squared pixels.
    ball.fixture.Restitution = 0.5; // This makes the ball receive half of the force it impacted another body, in the oposing direction. This will make the ball bounce.

    // The below will create a box 30 width and 20 height, that is dynamic, with center at 80, 60 position, with a density of 5/(32*32) kg/sq px.
    // We won't do anything with it outside of the physics, so we don't store pointers to it.
    AgsBox2D.CreateFixture(AgsBox2D.CreateBody(world, 80.0, 60.0, eBodyDynamic),
                           AgsBox2D.CreateRectangleShape(30.0, 20.0), 5.0);
  }
}


The above code sets up the world, this is pretty much the most part of what we have to do at first.
OK, let's make the physics happen.

Code: ags

// Remember, for this function to execute you need to link it in the room repeatedly execute event in the Editor
function room_RepExec()
{
  // In AGS coordinates, position increases as we go to the right, so positive values in the x coordinate pushes to the right.
  if(IsKeyPressed(eKeyLeftArrow)) ball.body.ApplyForce(-500.0, 0.0); // We are going to check if left key is pressed, and if it's, apply a force pushing the ball left.
  if(IsKeyPressed(eKeyRightArrow)) ball.body.ApplyForce(500.0, 0.0); // This does the same, but to the right direction.
  if(IsKeyPressed(eKeyUpArrow) && ball.body.IsTouching(ground.body)){ // We want the ball to jump if we press up, but only if it's touching the ground.
    ball.body.ApplyForce(0.0, -6000.0); // A negative vector in y points upwards, remember the positive gravity points downwards?
    ball.body.SetLinearVelocity(0.0, 0.0); // This resets the linear velocity, so that when you press up, the ball initially moves upwards and dismiss previous side momentum it had.
  }

  if(ov!=null && ov.Valid) ov.Remove();  // This is just to reset the overlay at every frame, so we are erasing it.
  ov = Overlay.CreateGraphical(0, 0, world.GetDebugSprite(), true); // The overlay here is used to show the debug sprite, to help us visualize what's happening.

  world.Step(1.0/IntToFloat(GetGameSpeed()), 8, 3); //This advances a time instant in the simulation. Nothing will happen unless the world advances a step. The calculation here yields 16 ms.
  // The value 8 and 3 passed along are used for simulation convergence, if you omit then, they are the default values. You should not change them unless you know what you are doing.
}


With this we have a very simplistic example working. You can explore the examples shipped along.

There is a very very simple wall creator here which you can use to start playing with making a level. I intend to figure out later on how to make an Editor to help using this plugin.

This code is for demonstration purposes, in a game, usually you want at least four walls outside of the screen enclosing your bodies, otherwise once they fall the platform, the simulation will need to calculate the body falling through eternity, which is an extra effort to the simulation for no reason.
If a body falls in a bigger cage outside the screen limit, the body will reach rest state eventually, which is much cheaper to calculate, or you can even detect it so you can destroy it.

lorenzo

That's fantastic, thanks a lot eri0o! The comments are really well made and understandable. It's a great way to learn how it works.

The wall creator is pretty cool as well. I was making boundaries with rectangles "manually" when trying out the plugin and it took me forever, this should make everything much easier!

eri0o

This "editor" is only temporary, I actually plan to add Tiled integration at some point (despite the name, it packs a vector Editor too, with polygons, circles, rectangles, ... ), but I am still unsure how to do it (a new plug-in for tiled only and do the wrap in script module is where I am leaning towards to, so people could use it for other stuff, like, drawing tiled maps). This can be done in a weekend once the design is figured.

Alternatively people suggested me some Box2D editors, but they all seem unmaintained so I am not so keen on using them.

The long term plan is writing an Editor plugin, so one could draw these directly in the AGS Editor, but this requires me learning C# and coding in Windows, so I am postponing this a bit.

eri0o

New small release! Should fix most random segmentation faults people could get. This release adds Contacts! Contacts are the last concept to add to AgsBox2D, they represent two fixtures with their AABBs touching!

You can see below the result of querying the World for the current contact list and each contact point being marked with a pink circle.



There are some more things I want to add to AgsBox2D, but these will suffice for this year. This release also adds the possibility of changing the world gravity after it's creation, which can enable some interesting puzzles.

SMF spam blocked by CleanTalk