C#/GDScript - How to move the body through PhysicsServer2D?

Godot Version 4.2 Mono

Question

I have the following billet for the TOP-DOWN genre, but I don’t know how I can move the body along with the collision and still make a collision check.

public override void _Ready()
{
    Rid spriteRID = RenderingServer.CanvasItemCreate();
    RenderingServer.CanvasItemSetParent(spriteRID, GetCanvasItem());
    RenderingServer.CanvasItemAddTextureRect(spriteRID, new Rect2(0, 0, texture.GetWidth(), texture.GetHeight()), texture.GetRid());
    RenderingServer.CanvasItemSetTransform(spriteRID, this.Transform);
    RenderingServer.CanvasItemSetZAsRelativeToParent(spriteRID, true);
    RenderingServer.CanvasItemSetZIndex(spriteRID, 0);

    shapeRID = shape.GetRid();

    bodyRID = PhysicsServer2D.BodyCreate();
    PhysicsServer2D.BodyAddShape(bodyRID, shapeRID);
    PhysicsServer2D.BodySetMode(bodyRID, PhysicsServer2D.BodyMode.Kinematic);
    PhysicsServer2D.BodySetCollisionLayer(bodyRID, collisionLayer);
    PhysicsServer2D.BodySetCollisionMask(bodyRID, collisionMask);
    PhysicsServer2D.BodySetState(bodyRID, PhysicsServer2D.BodyState.Transform, this.Transform);
    PhysicsServer2D.BodySetSpace(bodyRID, GetWorld2D().Space);
}

public override void _PhysicsProcess(double delta)
{
    float _delta = (float)delta;

    Vector2 _moveVector = Input.GetVector("a", "d", "w", "s") * 500 * _delta;
}

Try body_set_state.
I haven’t tried it but looking at the docs you should be able to do something like:

PhysicsServer2D.body_set_state(shapeRID, PhysicsServer2D.BodyState.BODY_STATE_LINEAR_VELOCITY, Vector2(100, 0))

to move it +100 units on the x axis per second

I’ve tried something like this before, specifically through the Transform mode setting. But the error “Parameter body == 0” occurs.

Not sure if this helps, but I should have said bodyRID instead of shapeRID. I don’t see where shape is defined, so there’s a chance shapeRID is empty, which might cause issues

I’ve tried both ways, the server thing is incomprehensible to mere mortals :0
P.S. I have already about 12 hours in total trying to do this, tried a lot of things, reviewed all the guides that approximate my problem, but all in vain

That’s rough.

The only thing that stands out to me is that shapeRID is coming from a shape variable that I don’t see anywhere else. Are you sure it’s not null?

Here, you can check it out

using Godot;

namespace Game.Object.Entitys
{
    public partial class Entity : Node2D
    {
        [ExportCategory("Entity")]

        [ExportGroup("Collision Settings")]
        [Export] public Shape2D shape;
        [Export(PropertyHint.Layers2DPhysics)] public uint collisionLayer;
        [Export(PropertyHint.Layers2DPhysics)] public uint collisionMask;

        public Rid shapeRID;
        public Rid bodyRID;

        public override void _Ready()
        {
            shapeRID = shape.GetRid();

            bodyRID = PhysicsServer2D.BodyCreate();
            PhysicsServer2D.BodyAddShape(bodyRID, shapeRID);
            PhysicsServer2D.BodySetMode(bodyRID, PhysicsServer2D.BodyMode.Kinematic);
            PhysicsServer2D.BodySetCollisionLayer(bodyRID, collisionLayer);
            PhysicsServer2D.BodySetCollisionMask(bodyRID, collisionMask);
            PhysicsServer2D.BodySetState(bodyRID, PhysicsServer2D.BodyState.Transform, this.GlobalTransform);
            PhysicsServer2D.BodySetSpace(bodyRID, GetWorld2D().Space);
            PhysicsServer2D.BodySetContinuousCollisionDetectionMode(bodyRID, PhysicsServer2D.CcdMode.CastShape);
        }

        public override void _PhysicsProcess(double delta)
        {
            float _delta = (float)delta;

            Vector2 _moveVector = Input.GetVector("a", "d", "w", "s") * 500 * _delta;

            PhysicsTestMotionParameters2D physicsTest = new PhysicsTestMotionParameters2D();
            physicsTest.From = GlobalTransform;
            physicsTest.Motion = _moveVector;
            if (!PhysicsServer2D.BodyTestMotion(bodyRID, physicsTest))
            {
                this.Translate(_moveVector);
            }
            GD.Print(PhysicsServer2D.BodyTestMotion(bodyRID, physicsTest));
        }

        public override void _ExitTree()
        {
            PhysicsServer2D.FreeRid(shapeRID);
            PhysicsServer2D.FreeRid(bodyRID);
        }
    }
}

It works for the moment, but it doesn’t slide, which is my situation:
I came to StaticBody, I can’t go any further, that’s cool, but if I press not just towards StaticBody, but also up/down let’s say, I still don’t go

You’re only moving if PhysicsServer2D.BodyTestMotion returns false, in other words, if there’s no collision. If you want it to still move I think you have to do something with velocity. The only way I see to do that is what I suggested before. It seems like you got the PhysicsServer2D.body_set_state function to work with BODY_STATE_TRANSFORM, so I would try setting the velocity as I mentioned (now that other issues are fixed). After all, when using CharacterBody2D, you move_and_slide based on velocity.

I changed it:

if (!PhysicsServer2D.BodyTestMotion(bodyRID, physicsTest))
            {
                this.Translate(_moveVector);
            }

On this:

if (!PhysicsServer2D.BodyTestMotion(bodyRID, physicsTest))
            {
                this.Translate(physicsTest.Motion);
            }
            else
            {
                PhysicsTestMotionParameters2D physicsTest1 = new PhysicsTestMotionParameters2D();
                physicsTest1.From = GlobalTransform;
                physicsTest1.Motion = new Vector2(_moveVector.X, 0);
                if (!PhysicsServer2D.BodyTestMotion(bodyRID, physicsTest1))
                {
                    this.Translate(physicsTest1.Motion);
                }
                else
                {
                    PhysicsTestMotionParameters2D physicsTest2 = new PhysicsTestMotionParameters2D();
                    physicsTest2.From = GlobalTransform;
                    physicsTest2.Motion = new Vector2(0, _moveVector.Y);
                    if (!PhysicsServer2D.BodyTestMotion(bodyRID, physicsTest2))
                    {
                        this.Translate(physicsTest2.Motion);
                    }
                }
            }

It worked, it does look terrible though, I’m sure there is a way to do it differently but I don’t know

Try something like this:

this.GlobalTransform = PhysicsServer2D.body_get_state(bodyRID, PhysicsServer2D.BodyState.BODY_STATE_TRANSFORM);
PhysicsServer2D.body_set_state(bodyRID, PhysicsServer2D.BodyState.BODY_STATE_LINEAR_VELOCITY, _moveVector)

and remove all the motion checks.

He’s not moving, not at all

public override void _PhysicsProcess(double delta)
{
    float _delta = (float)delta;

    Vector2 _moveVector = Input.GetVector("a", "d", "w", "s") * 500 * _delta;

    /* PhysicsTestMotionParameters2D physicsTest = new PhysicsTestMotionParameters2D();
    PhysicsTestMotionResult2D physicsResult = new PhysicsTestMotionResult2D();

    physicsTest.From = GlobalTransform;
    physicsTest.Motion = _moveVector; */

    this.GlobalTransform = (Transform2D)PhysicsServer2D.BodyGetState(bodyRID, PhysicsServer2D.BodyState.Transform);
    PhysicsServer2D.BodySetState(bodyRID, PhysicsServer2D.BodyState.LinearVelocity, _moveVector);
}

Shoot, man sorry I don’t know

That’s okay, thanks for your help.