0
\$\begingroup\$

I'm developing a client/server multiplayer game. in server side i need prevent players cross map objects like walls also i need prevent player go inside each others, instead want to slide them along each other (players are circle shape).

i tried few solution (own code and mathematical) i didn't achieve needs so i decide to use a 2d physic engine. as server code is c# language i select Aether.Physics2D (c# port of box2d). (i don't know if i made the right decision because my needs are a little part of a physic engine just character movement part so sounds good if some one lead me in true direction)

by the way in physic engine, map objects are static bodies and players are dynamic bodies. the static bodies part work fine so players can't cross wall, instead they slide along walls but dynamic bodies part.

the problem is when 2 dynamic body collide each other they push (force) each other that i don't want. if i change mask or filter collision groups, they go inside each other, is there any other solution?

what i need (expect) is : i need prevent players (dynamic bodies) go inside each other and prevent they push each other. once a player collide with another player must stop moving and slide (slip-over) like what happen in static walls.

i search it on google there were 2 solutions,first was combine a dynamic body with Kinematic as shield (code below) and second change player collision group. both not work as expected.

** C# test code with unity engine as visual **

public GameObject player1_sprite;
public GameObject player2_sprite;
public GameObject player1k_sprite;
public GameObject player2k_sprite;
public GameObject ground_sprite;
// Start is called before the first frame update
World world;
Body player1;
Body player2;
Body player1_shadow;
Body player2_shadow;
Body ground;
void Start()
{
    //Create a world
    world = new World();
    world.Gravity = tainicom.Aether.Physics2D.Common.Vector2.Zero;
    //-------------------------- player 1
    player1 = world.CreateBody(new tainicom.Aether.Physics2D.Common.Vector2(50, 80), 10, BodyType.Dynamic);
    var player1_fixure = player1.CreateCircle(5, 10f);
    player1.Mass = 10;
    player1_fixure.Friction = 1;
    player1_fixure.Restitution = 0;
    player1_fixure.CollisionCategories = Category.Cat1;
    player1_fixure.CollidesWith = Category.Cat2;
    //-------------------------- player 1 shadow
    player1_shadow = world.CreateBody(new tainicom.Aether.Physics2D.Common.Vector2(50, 80), 0, BodyType.Kinematic);
    var player1_shadow_fixure = player1_shadow.CreateCircle(5, 10f);
    player1_shadow_fixure .Restitution = 0;
    player1_shadow_fixure.CollisionCategories = Category.Cat2;
    world.Add(new tainicom.Aether.Physics2D.Dynamics.Joints.WeldJoint(player1, player1_shadow,
        tainicom.Aether.Physics2D.Common.Vector2.Zero, tainicom.Aether.Physics2D.Common.Vector2.Zero)
    { CollideConnected = false });
    //-------------------------- player 2
    player2 = world.CreateBody(new tainicom.Aether.Physics2D.Common.Vector2(50, 50), 10, BodyType.Dynamic);
    var player2_fixure = player2.CreateCircle(5, 10f);
    player2.Mass = 10;
    player2_fixure.Restitution = 0;
    player2_fixure.Friction = 1;
    player2_fixure.CollisionCategories = Category.Cat1;
    player2_fixure.CollidesWith = Category.Cat2;
    //-------------------------- player 2 shadow
    player2_shadow = world.CreateBody(new tainicom.Aether.Physics2D.Common.Vector2(50, 50), 0, BodyType.Kinematic);
    var player2_shadow_fixure = player2_shadow.CreateCircle(5, 10f);
    player2_shadow_fixure .Restitution = 0;
    player2_shadow_fixure.CollisionCategories = Category.Cat2;
    world.Add(new tainicom.Aether.Physics2D.Dynamics.Joints.WeldJoint(player2, player2_shadow,
        tainicom.Aether.Physics2D.Common.Vector2.Zero, tainicom.Aether.Physics2D.Common.Vector2.Zero)
    { CollideConnected = false });
    //-------------------------- static ground
    ground = world.CreateBody(new tainicom.Aether.Physics2D.Common.Vector2(50, 5), 0, BodyType.Static);
    var gfixture = ground.CreateRectangle(100, 10, 1f, tainicom.Aether.Physics2D.Common.Vector2.Zero);
    gfixture.Restitution = 0f;
    gfixture.Friction = 1f;
    gfixture.CollisionCategories = Category.Cat2;
}

// Update is called once per frame
void Update()
{
    tainicom.Aether.Physics2D.Common.Vector2 vel = new tainicom.Aether.Physics2D.Common.Vector2(0, 0);
    if (Input.GetKeyDown(KeyCode.UpArrow))
    {
        vel += new tainicom.Aether.Physics2D.Common.Vector2(0, 1);
    }
    if (Input.GetKeyDown(KeyCode.DownArrow))
    {
        vel += new tainicom.Aether.Physics2D.Common.Vector2(0, -1);
    }
    if (Input.GetKeyDown(KeyCode.RightArrow))
    {
        vel += new tainicom.Aether.Physics2D.Common.Vector2(1, 0);
    }
    if (Input.GetKeyDown(KeyCode.LeftArrow))
    {
        vel += new tainicom.Aether.Physics2D.Common.Vector2(-1, 0);
    }
    if (Input.GetKeyDown(KeyCode.Space))
    {
        player1.Position = new tainicom.Aether.Physics2D.Common.Vector2(30, 90);
    }
    player1.ApplyLinearImpulse (vel * 200);
   //force and linear velocity checked too
    world.Step(Time.deltaTime);

    player1_sprite.transform.position = new UnityEngine.Vector3(player1.Position.X, 0, player1.Position.Y);
    player2_sprite.transform.position = new UnityEngine.Vector3(player2.Position.X, 0, player2.Position.Y);
    player1k_sprite.transform.position = new UnityEngine.Vector3(player1_shadow .Position.X, 0, player1_shadow.Position.Y);
    player2k_sprite.transform.position = new UnityEngine.Vector3(player2_shadow .Position.X, 0, player2_shadow.Position.Y);
    ground_sprite.transform.position = new UnityEngine.Vector3(ground.Position.X, 0, ground.Position.Y);
}

if i delete weld joint and correct update code so set shadow body position equal to it's parent, again not success they push each other because before shadow follow the parent we call step function and dynamic collide each other but they are in mask group so nothing happen but in next step shadow bodies move then they push dynamics.

    player1.LinearVelocity= (vel * 200);
    world.Step(Time.deltaTime);
    player1_shadow.Position = player1.Position;
    player2_shadow.Position = player2.Position;
\$\endgroup\$
8
  • \$\begingroup\$ Just to make sure: you're creating a top-down game with no gravity, right? \$\endgroup\$
    – Vaillancourt
    Dec 7, 2021 at 12:47
  • \$\begingroup\$ You may be interested in the approach used here: Nestling into contact with a group of physics objects without exerting forces on them. The trick is to not have player objects "collide" per say. Rather, each player, when moving, casts out a query for other player objects between itself and its intended destination, and then reduces/redirects its movement to not-quite-touch those players, rather than overlapping them or passing through to the other side. \$\endgroup\$
    – DMGregory
    Dec 7, 2021 at 13:44
  • \$\begingroup\$ @Vaillancourt yes exactly. but we have 3d game but as we don't care about height (Y) in server we decide to choose a top down approach. we have a polygon shape as our outline (border). players can't exit this polygon outline and in map some where we have wall. \$\endgroup\$
    – Mamad R
    Dec 7, 2021 at 14:03
  • \$\begingroup\$ @DMGregory thanks. nice post but they have unity engine with sphere cast functionality but i have box2d like engine. can you show me few line of code to help? \$\endgroup\$
    – Mamad R
    Dec 7, 2021 at 14:30
  • 1
    \$\begingroup\$ Box2D has had a b2ShapeCast function since 2.4.0, and its output includes the collision point and normal. But of course, for circles it's easy enough to compute this analytically. A collision between a swept circle and a stationary one (or equivalently, two swept circles, as viewed in the inertial frame of one of them) is equivalent to a ray intersection with a circle having the sum of their radii. So you might find it easier to just write your own swept check \$\endgroup\$
    – DMGregory
    Dec 7, 2021 at 14:41

0

You must log in to answer this question.

Browse other questions tagged .