GKObstacleGraph How to Find Closest Valid point? - path-finding

In a scenario where user wants to navigate via mouse or touch to some are of the map that is not passable. When sending the point to GKObstacleGRpah FindPath it just returns an empty array.
I want the unit to go to closest (or close enough) passable point.
What would be an appropriate way to find a closest valid point in GKObstacleGraph.
I understand that I can get the GKObstacle so I can enumerate it's vertices, and I know my unit's position...
But well... what is the next step ?
NOTE: I am not using GKAgengts.

Here was my thinking as I worked through this problem. There may be an easier answer, but I haven’t found it.
1. Figure out if a point is valid or not.
To do this, I actually have a CGPath representation of each obstacle. I export paths from PhysicsEditor and then load them in through a custom script that converts them to CGPath. I always store that CGPath along with the GKObstacle I created from the path. Finally, I can call CGPathContainsPoint to determine the the obstacle contains the point. If true, I know the point is invalid.
2. Once the point is invalid, find out which obstacle was clicked.
With my approach in #1, I already have a handle on the CGPath and obstacle it belongs to.
3. Find closest vertex
Now that I know the obstacle, find the vertex closest to the unit that is moving. I wouldn’t find the closet vertex to the point clicked because that could be around a corner. Instead, figure out the vector between the desired position and the unit. Then, draw an invisible line from the desired position through the vertex. I used this equation to find out where the lines would cross.
// http://stackoverflow.com/questions/1811549/perpendicular-on-a-line-from-a-given-point
let k = ((end.y - start.y) * (hitPoint.x - start.x) - (end.x - start.x) * (hitPoint.y - start.y)) / ((end.y - start.y) * (end.y - start.y) + (end.x - start.x) * (end.x - start.x))
let x4 = hitPoint.x - k * (end.y - start.y)
let y4 = hitPoint.y + k * (end.x - start.x)
let ret = float2(x: x4, y: y4)
4. Offset intersection by unit size towards moving unit
Knowing where the paths intersect along with the vector towards the unit, we can just move to intersection point + (the vector * unit size).
5. Edge cases
This gets tricky when you have two obstacles touching each other, or if you have very large obstacles. The user may think they are moving to the far side of the map, but this script will follow back to the closet valid point which could be nearby. Because of that, I scrapped all of the code and I just don’t allow you to move to invalid positions. A red X and a buzz sound happens prompting the user to select a new, valid position on the map.
6. DemoBots
I could be wrong, but I vaguely recall DemoBots from Apple having similar logic — they may be a good reference too.
7. Debug Layer
This took forever for me to get a proof of concept together. I’d highly recommend drawing lines on a debug layer to verify your logic.

Related

How to code a pathfinding player in godot using A*?

Iam nooby in godot, I have to use A* to traslate the player to the goal position, but I do not know how to start, pls help!! basically I have just 2 tiles in the tilemap, 1 of them is allowed to pass over it, I have to extract I guess the allowed tile and calculate the distance between the position player with the position goal, getting the real distance and then check cell per cell which has the lowest cost, but I do not know how to do that :c
func get_player_init_pos():
var pos = map_to_world(Vector2(54,1))pos.y += half_cell_size.y
return pos
func is_tile_vacant(pos, direction):
var curr_tile = world_to_map(pos)
var next_tile = get_cellv(curr_tile + direction)
var next_tile_pos = Vector2()
if(next_tile == 0):
next_tile_pos = map_to_world(curr_tile + direction)
else:next_tile_pos = pos
return next_tile_pos
I have this, the first part of the code is to locate the player in the map and the second is for check the tile walls in the map
You could roll your own path finding algorithm. However, there is little point in doing so, since Godot has a AStar class you can use. However, you probably don't need to use that either, because Godot has a navigation system. And that is what I'm going to suggest you to use.
First of all, you can specify both navigation and collision polygons on your tiles. You need to have the navigation polygons. Go ahead and do them.
Second you want to have a Navigation2D in the scene tree and have your TileMap as a child.
And third, you can ask the Navigation2D for a path with get_simple_path, you pass the start and end positions as arguments and you get an array of points that make up the path.
Since you mention A*, I'll briefly explain using the AStar too anyway.
First, you need to add the cells with add_point. It requires ids. It is a good idea to be clever with the ids so you can compute the id for a given position. For example x * width + y if you know the size.
So you can iterate over the tiles in your TileMap and call add_point for each one (You don't need to add cell that are not passable).
Then you need to specify the connections with connect_points (it takes the ids of the points as parameters).
And finally you can call get_point_path passing the start and end ids. Again it gives you a array of points.

Trying to make a circle in Minecraft using coordinates and Sin & Cos

I am trying to write a Minecraft Datapack, which will plot a full armorstand circle around whatever runs the particular command. I am using a 3rd party mathematics datapack to use Sin and Cos. However, when running the command, the resulting plot was... not good. As you can see here: 1. Broken Circle., rather than have each vertex evenly placed in a circular line, I find a strange mess instead.
I would have thought loosing precision in Cos and Sin would simply make the circle more angular, I didn't expect it to spiral. What confuses me, is that +z (the red square) and -x (the purple one) are all alone. You can see on the blue ring (Which was made with a smaller radius) the gap between them persists.
My main issue is; How did my maths go from making a circle to a shredded mushroom, and is there a way to calculate the vertices with a greater precision?
Going into the project I knew I could simply spin the centre entity, and summon an armorstand x blocks in front using ^5 ^ ^, however I wanted to avoid this, due to my desire to be able to change the radius without needing to edit the datapack. To solve this, I used the Sin and Cos components to plot a new point, using a radius defined with scoreboards.
I first tested this using Scratch, in order to check my maths. You can see my code here: 2. Scratch code.
With an addition of the pen blocks, I was able to produce a perfect circle, which you can see here:
. Scratch visual proof.
With my proof of concept working, I looked online and found a Mathematical Functions datapack by yosho27, since the Cos and Sin functions are not built into the game. However, due to how Minecraft scoreboards are only Integers, Yosho27 multiplied the result of Cos and Sin by 100 to preserve 2 decimal places.
To start with, I am using a central armorstand with the tag center, which is at x: 8.5 z: 8.5. The scoreboards built into yosho's datapack that I am using is math_in for the values I want converted and math_out, which is where the final value is dumped.
Using signs, I keep track of the important values I am working with, as seen here: 4. Sign maths.
As I was writing this, I decided to actually compare both numbers to find this: 5. Image comparison, which shows me that somewhere in this calculation process, the maths has gone wrong. I modified the scratch side to match the minecraft conditions as much as possible, such as x100 and adding 850 to the result. From this result, I can see a disparity between x and z, even though they should be equal. Where Minecraft says 1: x= 864 z= 1487, Scratch says 1: x= 862.21668448: z= 1549.89338664. I assume this means the datapack's Cos and Sin are not accurate enough?
In light of this , I looked in yosho's datapack, I found this: 6. Yosho's code., which I just modified to be *= 10 instead of divide, in the hope of getting more precision. Modifying the rest of my code to match, I couldn't see any improvement in the numbers, although the armorstand vertices were a few pixels off the original circle, although I couldn't find a discernible pattern to this shift.
While this doesn't answer your full question, I'd like to point out two different ways you can solve the original issue at hand, no need to rely on some foreign math library:
^ ^ ^
Use Math, but let the game do it for you.
You can use the fact that the game is doing those rotational conversions for you already when using local coordinates. So, if you (or any entity) go to 0 0 0 and look / rotate in the angle that you want to calculate, then move forward by ^ ^ ^1, the position you're at now is basically <sin> 0 <cos>.
You can now take those numbers with your desired precision using data get and continue using them in whatever way you see fit.
Use recursive functions to move in incremenets
You point out in your question that
Going into the project I knew I could simply spin the centre entity, and summon an armorstand x blocks in front using ^5 ^ ^, however I wanted to avoid this, due to my desire to be able to change the radius without needing to edit the datapack. To solve this, I used the Sin and Cos components to plot a new point, using a radius defined with scoreboards.
So, to go back to that original idea, you could fairly easily (at least easier than trying to calculate the SIN/COS manually) find a solution that works for (almost) arbitrary radii and steps: By making the datapack configurable through e.g. scores, you can set it up to for example move forward by ^^^0.1 blocks for every point in a score, that way you can change that score to 50 to get a distance of ^^^5 and to 15 to get a distance of ^^^1.5.
Similarly you could set the "minimum" rotation between summons to be 0.1 degrees, then repeating said rotation for however many times you desire.
Both of these things can be achieved with recursive functions. Here is a quick example where you can control the rotational angle using the #rot steps score and the distance using the #dist steps score as described above (you might want to limit how often this runs with a score, too, like 360/rotation or whatever if you want to do one full circle). This example technically recurses twice, as I'm not using an entity to store the rotation. If there is an entity, you don't need to call the forward function from the rotate function but can call it from step (at the entity).
step.mcfunction
# copy scores over so we can use them
scoreboard players operation #rot_steps steps = #rot steps
scoreboard players operation #dist_steps steps = #dist steps
execute rotated ~ ~0.1 function foo:rotate
rotate.mcfunction
scoreboard players remove #rot_steps steps 1
execute if score #rot_steps matches ..0 positioned ^ ^ ^.1 run function foo:forward
execute if score #rot_steps matches 1.. rotated ~ ~0.1 run function foo:rotate
forward.mcfunction
scoreboard players remove #dist_steps steps 1
execute if score #dist_steps matches ..0 run summon armor_stand
execute if score #dist_steps matches 1.. positioned ^ ^ ^.1 run function foo:forward

Moving object from point a to b (in 2D) that can only move forward and rotate itself

So I have a ship, that has thrusters at the bottom and that can only use these to move forward. It can also rotate itself around its center. Its thrusters gives it acceleration, so it doesn't move at a constant velocity. What I want to do is to tell it "move to point B".
I have come up with a solution but it doesn't work very well and it doesn't rotate smoothly, it moves jerkily and it doesn't end up exactly where it should be, so I have to have a big margin of error.
Is this a normal problem, and if so is there a "standard" way of doing it? Is this an easy problem? I want to make it look like the ship is steering itself to that point, using the constraints (thrusters, rotation) the player has. This excludes just lerping it from point A to B. Or does it?
I'd love some help in solving this problem. Positions are stored in vectors, and it's a 2D problem. Just for reference I'm including my solution, which basically is accelerating the ship until and rotating it to point to the point. I think my implementation of this idea is the problem:
Vector diff = vector_sub(to_point, pos);
float angle = vector_getangle(diff);
float current_angle = vector_getangle(dir);
float angle_diff = rightrange(angle) - rightrange(current_angle);
float len = vector_getlength(diff);
// "Margin of error"
float margin = 15.0;
// Adjust direction, only if we're not stopping the next thing we do (len <= margin)
if ( len > margin && fabs(angle_diff) > 2.0 )
{
dir = vector_setangle(dir, current_angle + (angle_diff)*delta*(MY_PI) - MY_PI/2);
}
else if ( len > margin )
{
dir = vector_normalize(diff);
}
// accelerate ship (if needed)
acc.x = acc.y = speed;
acc = vector_setangle(acc, vector_getangle(dir));
if ( len <= margin )
{
// Player is within margin of error
}
If you are not looking for a very general solution that works online, then there is a simple solution. What I mean by online is continuously re-calculating the actions along the complete trajectory.
Assuming the ship is at rest at start, simply rotate it towards your target point (while still at rest). Now, your ship can reach the target by accelerating for t seconds, rotating back while in motion (for 0.5 seconds as per your constraint), and decelerating for another t seconds. If the distance between current point and destination is d, then the equation you need to solve is:
d = 0.5*a*t^2 + 0.5*a*t + 0.5*a*t^2
The first term is distance traveled while accelerating. The second term is distance traveled while rotating (v*t_rot, v=a*t, t_rot=0.5). The final term is the distance traveled while decelerating. Solve the above for t, and you have your trajectory.
If the ship is moving at start, I would first stop it (just rotate in opposite direction of its speed vector, and decelerate until at rest). Now we know how to reach destination.
The problem with offline trajectory calculation is that it is not very accurate. There is a good chance that you will end up in the vicinity of the target, but not exactly on top of it.
Let's make the problem a little more interesting: the ship cannot rotate without acceleration. Let's call this acceleration vector a_r, a vector that is at a certain angle against the ship's direction (somewhat like having a thruster at an angle at the back). Your task now is to rotate the ship and accelerate in such a direction that the speed component perpendicular to the vector connecting the current position to the target is canceled out. Instead of trying to calculate the vectors offline, I would go with an online approach with this.
The easiest thing to do would be to add the following algorithm calculated at every time interval:
Calculate the vector pointing from ship to destination.
Split your current speed vector into two components: towards the destination, and perpendicular to it.
If perpendicular speed is zero, skip 4
Start rotating towards the negative of the perpendicular vector's direction. If already looking away from it (not exact opposite, but just looking away), also fire main thruster.
This will oscillate a bit, I suspect it will also stabilize after a while. I must admit, I don't know how I would make it stop at destination.
And the final approach is to model the ship's dynamics, and try to linearize it. It will be a non-linear system, so the second step will be necessary. Then convert the model to a discrete time system. And finally apply a control rule to make it reach target point. For this, you can change your state-space from position and speed to error in position and (maybe) error in speed, and finally add a regulation control (a control loop that takes the current state, and generates an input such that the state variables will approach zero).
This last one is fairly difficult in the maths compartment, and you'd probably need to study control engineering a bit to do it. However, you'll get much better results than the above simplistic algorithm - which admittedly might not even work. In addition, you can now apply various optimization rules to it: minimize time to reach target, minimize fuel consumption, minimize distance traveled, etc.

Calculating rotation along a path

I am trying to animate an object, let's say its a car. I want it go from point
x1,y1,z1
to point x2,y2,z2 . It moves to those points, but it appears to be drifting rather than pointing in the direction of motion. So my question is: how can I solve this issue in my updateframe() event? Could you point me in the direction of some good resources?
Thanks.
First off how do you represent the road?
I recently done exactly this thing and I used Catmull-Rom splines for the road. To orient an object and make it follow the spline path you need to interpolate the current x,y,z position from a t that walks along the spline, then orient it along the Frenet Coordinates System or Frenet Frame for that particular position.
Basically for each point you need 3 vectors: the Tangent, the Normal, and the Binormal. The Tangent will be the actual direction you will like your object (car) to point at.
I choose Catmull-Rom because they are easy to deduct the tangents at any point - just make the (vector) difference between 2 other near points to the current one. (Say you are at t, pick t-epsilon and t+epsilon - with epsilon being a small enough constant).
For the other 2 vectors, you can use this iterative method - that is you start with a known set of vectors on one end, and you work a new set based on the previous one each updateframe() ).
You need to work out the initial orientation of the car, and the final orientation of the car at its destination, then interpolate between them to determine the orientation in between for the current timestep.
This article describes the mathematics behind doing the interpolation, as well as some other things to do with rotating objects that may be of use to you. gamasutra.com in general is an excellent resource for this sort of thing.
I think interpolating is giving the drift you are seeing.
You need to model the way steering works .. your update function should 1) move the car always in the direction of where it is pointing and 2) turn the car toward the current target .. one should not affect the other so that the turning will happen and complete more rapidly than the arriving.
In general terms, the direction the car is pointing is along its velocity vector, which is the first derivative of its position vector.
For example, if the car is going in a circle (of radius r) around the origin every n seconds then the x component of the car's position is given by:
x = r.sin(2πt/n)
and the x component of its velocity vector will be:
vx = dx/dt = r.(2π/n)cos(2πt/n)
Do this for all of the x, y and z components, normalize the resulting vector and you have your direction.
Always pointing the car toward the destination point is simple and cheap, but it won't work if the car is following a curved path. In which case you need to point the car along the tangent line at its current location (see other answers, above).
going from one position to another gives an object a velocity, a velocity is a vector, and normalising that vector will give you the direction vector of the motion that you can plug into a "look at" matrix, do the cross of the up with this vector to get the side and hey presto you have a full matrix for the direction control of the object in motion.

rayPlaneIntersection (like) exemple or similar function

I'm working with bots in Call Of Duty and their vision is calculated with a bulletTracePassed  function, there's no other way to calculate that, since there's not really bot functions, so this will return true if a bullet can pass from point A to point B returning true/false, which works great MOST of the times, but causes a chaos in those 2 cases mainly:
When the mapper didn't put any kind iDFLAGS_PENETRATION on the walls (means the wall have no resistance to bullets, so there's not contact/hit, and the bullets pass through like was nothing.
When we have Trees, Plants, etc in the middle
In those 2 cases the bots will see the other players when shoudn't, and in jungle like maps it's a complete hell to play.
Ok, the right way to do these fixes are just fix the maps, adding the right penetration in those walls and dense vegetation, but is not possible do that because are SEVERAL maps by SEVERAL modders, and even official releases with the same problems, and of course, we don't have their sources to apply these fixes.
So the only way to do that is via script, and I'm thinking in doing something like this:
I have the position of the eye of the attacker bot in 3D like (x,y,z) for exemple (1000,500,22), and also the position which hit the other players like (2000,1200,60), which is returned by the function bulletTracePassed.
But for exemple, in a wall I have part of it without any collision, so the bots can see through them, so would like to set the middle of the wall with position (1600,800,50) and angles (10,-40,-90) and a square radius of the size to of the square/plane, for exemple, 500.
So I want to test if the ray passed through this square/plane, then returning false/true to let me use it to make the bots decide to aim to shoot or not this player behind the "bad" wall.
Looking around I found the function rayPlaneIntersection, which by the name seams what I want, but didn't get right yet how it works in my solution, since I can't see any kind of angles of even a square radius to determine their size... or are doing to a single point only?
rayPlaneIntersectionrayPlaneIntersection(ray0: vec3, ray1: vec3, origin?: vec3 | number[], normal?: vec3 | number[]): vec3 | undefined
Defined in raymath.ts:130
Computes the intersection point of a given ray and a given plane (rooted at [ 0, 0, 0 ]). t = -(dot(plane.xyz, origin) + plane.w) / dot(plane.xyz, ray); The ray intersects when (t > 0.0) && (t < tm) is true.
Parameters
ray0: vec3 Start point of a ray.
ray1: vec3Far point of a ray, used to derive the ray direction.
Default value origin: vec3 | number[] = [0.0, 0.0, 0.0]
Point on a plane with origin [ 0, 0, 0 ].
Default value normal: vec3 | number[] = [0.0, 1.0, 0.0]
Normal of the plane with origin [ 0, 0, 0 ].
Returns vec3 | undefined
If ray intersects, the intersection point on the plane if the plane was hit.
Anyone could point an exemple of this use in my exemple? Or any other function that might give me the same (or even similar) result to let me at least start to fix this problem?
I know it's not an easy task, that's why I'm posting here, after many lost hours trying to do it alone without success yet.
thank you very much.

Resources