Can you make Ray Sensor more consistent?

I’ve created an example Blend to show you how fickle the Ray sensor is.

http://pasteall.org/blend/index.php?id=47020

I have the Cube setup to collide with the Ghost floor at the predetermined speed and height (when you press spacebar) and the Cube will stop at a different spot every time. This is so annoying. Is there anything that I can do to make the Ray sensor more consistent?

I really need to make it more so that I can create a platform that the player can jump through from the bottom and land on top, but it’s so wonky.

Is the cube marked to use cube bound or triangle mesh?

I am afk*

I’ve tried both and same result

The ray sensor is behaving consistently in the file you provided. The issue is that you’re not taking into account that game engines run in discreet time steps rather than a continuous flow.

The cube moves down 0.4 units each frame, but you move it up 10.3 units when space is pressed. Since 10.3 isn’t evenly divisible by 0.4, the ray sensor will be in range of the floor at a different height each time you move the cube.

A quick fix would be to make the amount you move the cube up be evenly divisible by the amount it moves down each frame (e.g. 8.0 and 0.4). A proper fix would be to just move the cube to the ray’s hit position instead of just stopping it in place.

My question is:

  • What are you hoping to gain by writing your own physics engine?

The Problems:
When you move the cube “back to it’s starting position”, you move it upwards by 10.3 units. Depending on where it stops, this likely isn’t it’s original position.

The other thing to understand is that you have no restitution. So once the cube has penetrated the ground, there is nothing moving it to back on the surface. Coupled with the fact that your motion is “teleport it by 0.4 units”, your system will always provide a deviation in landing position by … up to 0.4 units.

Some solutions:
Implement some sort of restitution: ie move the cube to where the ray hits. This can’t be done in logic bricks, but it can in python. For example, if you change stop gravity to:


import bge




def main():


    cont = bge.logic.getCurrentController()
    own = cont.owner


    sens = cont.sensors['Ray']


    if sens.positive:
        own.worldPosition[2] = sens.hitPosition[2] + 0.99
        own['Gravity'] = False
    else:
        own['Gravity'] = True


main()

then voila, it will stop in the right place, because the added line restores the cube to the surface it it has entered into the ground.

Incredible. I wonder if there is a way to get the location of the top-most edge/face of the hitObject instead automatically so that I don’t have to manually do the calculations/guesswork for the offset, which I assume took you a few moments to figure out “+ 0.99” in this scenario. I didn’t think to do an offset myself. In my head, I kept thinking that Raying to a surface should be identical to Collision to the surface, where the Collision automatically places you on the surface. As it has for me, anyways.

I like the control I have over my own physics and how I can customize it to my heart’s content. My gravity script actually more complicated than simply -0.4 on the z-axis constantly, there is a ramp up. I simply chose 0.4 and from the indivisible 10.3 location because it simulated a problem I was having when my character would clash with the surface like that.

Thank you both.

The 0.99 is because the cube is 2bu size, and half of that is 1bu. There was no guess and check to find the right number. The missing 0.01 is to prevent it from oscillating as gravity switches back on (because the ray stops hitting the ground if the cube is 1bu).
If you know the bounding box of the object in question, then calculating the offset is relatively easy.

Or if you place the object’s origin at the bottom, then there is no offset.

A physics engine made in py from scratch could only work with batched raycasts, calling callbacks.

Like
A single Cast = [end, start, dist, prop, norm, xray, poly, layer_bitmask, trueFunc, falseFunc]

own.scene.batchCast([list of raycasts])