The Godot Q&A is currently undergoing maintenance!

Your ability to ask and answer questions is temporarily disabled. You can browse existing threads in read-only mode.

We are working on bringing this community platform back to its full functionality, stay tuned for updates. | Twitter

+1 vote

I use RigitBody2D for bullets. I want bullets to have physics, that is, they ricocheted and repelled opponents. But at high speed, they fly through walls and enemies. I added RayCast2D and now I can know if the bullet will collide with the object, but I do not know the function in which you can handle collisions. Is it possible to make Godot handle collisions if RayCast2D sees an object? Perhaps there are other ways of implementation? But it is important that the bullet had physics.

I'm new to Godot, please give a detailed explanation. And if you can, articles where this topic is revealed.

Godot v2.1.4

in Engine by (15 points)

3 Answers

+3 votes

You don't need a RayCast2D for this. RigidBody2D has methods for dealing with the fast motion issue.

Use set_continuous_collision_detection_mode(). You have three options:

CCDMODEDISABLED = 0 — Disables continuous collision detection. This is the fastest way to detect body collisions, but can miss small, fast-moving objects.
CCDMODECASTRAY = 1 — Enables continuous collision detection by raycasting. It is faster than shapecasting, but less precise.
MODECASTSHAPE = 2 — Enables continuous collision detection by shapecasting. It is the slowest CCD method, and the most precise.

Mode 1 is probably going to work fine for you. Give it a try and see the docs for more details:

by (22,191 points)

I did so, but bullets still fly through the walls, nothing has changed.

Does the bullet perform as expected if the speed is lower? What about your code? How are you moving the bullet?

I give a bullet when creating an impulse.
var i = bullet.instance ()
i.setpos ()
impulse ()

Yes, at low speeds, the bullet behaves correctly.

If possible, could you make an example?
I have Godot 3.0 and Godot 2.1.4.
I can compare your and my decision and find the error.

I was just playing around with it, and it seems to get the bullet to tunnel through the walls when using CCD (ray mode), I have to apply such a large impulse that the bullet's velocity becomes huge, and I can barely see it anyway, except as a "dotted" line.

In the past, when I've wanted fast/instant bullets I've found that ray-casting makes for a better solution, especially if you want really small bullets as well. Cast rays from collision point to collision point as desired and you can ricochet, etc. (Note this can be done very efficiently using the DirectPhysics2DState rather than RayCast2D nodes). Add a Line2D/particles/shader for a "tracer" style visual effect. Most shooters typically do this.

I'm afraid I don't have any other solutions to suggest for you. High-speed + small-size is exactly where most physics engines hit their limit.

Sorry, but since I'm new, I did not understand what was being said. What is DirectPhysics2DState, Line2D, Shader? It would be much easier for me to see the project. I already wrote a small crutch, which works for me by 50-70%:

rc - RayCast2D
This code is executed in bullet.

func _fixed_process(delta): 
if rc.is_colliding():
    var dot = rc.get_collision_point()
    var i = get_pos().distance_to(dot)
    if i < 34:

Of course, I would like to find a more precise solution.

There's a doc on it here:

Or the 3.0 version:

As for the rest, Line2D/shader/particles are different approaches you could take for creating visuals. It all depends on what visual effect you're going for.

I read these articles, it seems that I have already read all the articles related to the clashes ... I do not understand yet what decision you proposed to me, but I'll try to carefully read the article again, I can understand what you meant.

As I understood from the article Physics2DDirectSpaceState.intersect_ray() only helps to detect a collision. I do the same with RayCast2D. Sorry, but I still could not understand what you were offering as a solution.

0 votes

Another suggestion I see often is to make your walls thicker. Thicker hitboxes on your walls give it more time to detect the collision.

by (141 points)

Now the bullet flew through the wall, and then it was drawn to her from the other side. The speed at which the bullet moves in my project 2000, and its size is 3 pixels. The thickness of the wall itself is 2 pixels. Your bullet is very big and moves very slowly. When I made your bullet smaller and faster, it did as I described above.

I made the extents on the bullet on the left 1.5, which would make the hitbox 3px x 3px. The sprite is just there so I can see where the bullet is. I updated the speed to 2000 and it doesn't go through the wall (the node FastFromLeft).

Did you change the size of the hitboxes on the wall? That will for sure break it. You can see in the demo that both "bullets" stop at the wall.

You can make the boxes Area2D instead of on a rigid body. You can set the precedence for the collision to make sure that things collide with the wall before they collide with anything else. Then you destroy the bullet when it hits the wall. Yes, the bullets will technically go through the wall but they won't hit anything else.
*edit change right to left.

If I change the speed to 20 000, then the bullet still will not fly through the wall? I need a bullet to bounce off the wall, have a mass and behave like RigidBody2D, but did not pass through walls at very high speeds. Try changing the frame rate in the physics section to 1-2. You can see step by step how your bullet moves. At the collision, a bullet of the crowd bounce off the wall, how would she do in reality. First set the speed to 100, then try to increase it by 50-100, every try.

I'm out of ideas. You might have to find some special way of treating your bullets once they get too fast. I think you are going to run into the same problems with other objects once they get moving too quick.

I marked the correct answer to the solution that suited me. Using this code, I can get my bullets to recoill, even if their speed is more than 20,000. Thank you for taking your time. Look at the code above, maybe you will find something interesting for yourself.

+2 votes

I'm obviously super-late, but this might help out others in the future. I had a similar problem and, for what's probably the first time in my life, I came up with my own solution!

It shares a little with avencherus's answer, but I admit I don't fully understand his code, so I can't point out the differences, other than that this is almost painfully simple.

Godot version 3.1.1 stable official.

Note: this is for when you aren't using a RigidBody(2D) or even move_and_slide()/move_and_collide(), though who knows, you might be able to adapt it to fit those cases.

I use a vector, velocity, and add it to position after checking that it won't put the object inside another collider.

The idea is that you cast a ray the length, and in the direction, of the velocity vector. If it hits something, it means you'll be colliding in the next frame, so instead of position += velocity, you get_collision_point() and set position = that (accounting for the object's size, since position is in its center; this is crucial, because raycasts also usually start from the center, and if you fail to do this it won't work properly; if you've moved raycast origin, take that as the center).

Note 2: I've only tested this for gravity so far. This means I've only cast 1 ray, vertically. I'll update the answer once I've done more work on my character controller.

Here's the basic code. It's what I got so far. I avoided putting in a lot of variable definitions, as they're obvious and I wanted to it to be uncluttered.

extends KinematicBody2D

func _physics_process(delta):
    # adding gravity
    velocity.y += GRAVITY

    # adding input movement
    # ...

    # raycasting
    raycast.cast_to.y = height + velocity.y * delta

    if raycast.is_colliding():
        position = raycast.get_collision_point() - Vector2(0, height)
        velocity.y -= GRAVITY
        position += velocity * delta

height is $CollisionShape2D.shape.extents.y, set in _ready(). My sprite (and collision shape) is a square.
velocity.y -= GRAVITY is to stop velocity.y from increasing unceasingly, or else it will interfere with input movement later. Outright setting it to 0 messes things up, since our raycast depends on it.

For accuracy's sake, you'll need more than one ray, but the underlying code should be the same.

From my tests so far, this works when I've jacked GRAVITY all the way up to 18000 — normally, it's only 50 — but fails at 19000 and onward. Do keep in mind this is gravity, so it's acceleration, meaning it boosts velocity.y to ridiculous values in just milliseconds, as it increases by that amount every frame.
I don't know what breaks things at this point, but I probably won't investigate either, because I can't see any use-case scenarios for it; except for space sims, I guess, but those are way above my level.

by (18 points)

Was having the same problem and the same idea as you did (allthough I use an Area2D and use translate instead of directly editing position), maybe not as cleanly coded as you did :P but well done!

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.