Using test_move() and finding Transform2D in Godot 3.1 - godot

I've been trying to use KinematicBody2D's test_move() to see if my character is next to a wall, but not touching it, but I'm having a little trouble with it since the actual documentation is just
bool test_move( Transform2D from, Vector2 rel_vec, bool infinite_inertia=true )
Checks for collisions without moving the body. Virtually sets the node's position, scale and rotation to that of the given Transform2D,
then tries to move the body along the vector rel_vec. Returns true if
a collision would occur.
and all of the tutorials I could find just show an older version of the function where the only argument was a Vector2 which is a little more straightforward.
As far as I understand, the Transform2D is the objects initial position to test from, the Vector2 give the direction it should move, and infinite inertia deals with whether or not the object rotates on impact.
My issue right now is with the Transform2D, so far the only function I could find in the documentation that seems like it should return the objects transform in that format is CollisionObject2D's
shape_owner_get_transform( int owner_id ) const
Returns the shape owner's Transform2D.
but no matter what I try I always seem to get an identity matrix out of it, the bit of code I ended up with trying to figure this out looks like
var transform2d = Transform2D(owner.shape_owner_get_transform(owner.get_shape_owners()[0]))
if owner.test_move(transform2d, Vector2(-20, 0), true):
print("on your left").
I'm not sure which function I'm misunderstanding, whether it's test_move(), shape_owner_get_transform(), or get_shape_owners() which I used to get the owner_id but any help would be appreciated.

Gonna answer my own question here since I solved it shortly after posting the question. My issue is that owner.shape_owner_get_transform(owner.get_shape_owners()[0]) is not how one would go about getting a body's transformation. Instead I needed to construct a Transform2D with my character's position and rotation.
in the end my next_to_wall() function looked like:
func next_to_wall(distance):
var transform2d = Transform2D(0.0, owner.position)
if owner.test_move(transform2d, Vector2(distance, 0), true):
return true
else:
return false
Note I entered 0.0 for the first argument because that just worked for my case, otherwise it would be owner.rotation.

Related

Ultimate struggle with a full 3d space controller

Sorry if i'm stupid or something, but i having a deep dread from a work on a "full 3d" space movement.
I'm trying to make a "space ship" KinematicBody controller which using basis vectors as a rotation point and have ability to strafe/move left,right,up,down based on it's facing direction.
The issue is i'm having that i want to use a Vector3 as a storage of all input variables, an input strength in particular, but i can't find a convenient way to orient or use this vector's variables to apply it to velocity.
I got a sort of cheap solution which i don't like with applying a rotation to an input vector so it will "corresponds" to one of the basis, but it's starting to brake at some angels.
Could please somebody suggest what i can change in my logic or maybe there is a way to
use quaternion/matrix related methods/formulas?
I'm not sure I fully understand what you want to do, but I can give you something to work with.
I'll assume that you already have the input as a Vector3. If not, you want to see Input.get_action_strength, Input.get_axis and Input.get_vector.
I'm also assuming that the braking situations you encountered are a case of gimbal lock. But since you are asking about applying velocity not rotation, I'll not go into that topic.
Since you are using a KinematicBody, I suppose you would be using move_and_slide or similar method, which work in global space. But you want the input to have to be based on the current orientation. Thus, you would consider your Vector3 which represents the input to be in local space. And the issue is how to go from that local space to the global space that move_and_slide et.al. need.
Transform
You might be familiar with to_local and to_global. Which would interpret the Vector3 as a position:
var global_input_vector:Vector3 = to_global(input_vector)
And the opposite operation would be:
input_vector = to_local(global_input_vector)
The problem with these is that since these consider the Vector3 to be positions, they will translate the vector depending where the KinematicBody is. We can undo that translation:
var global_vec:Vector3 = to_global(local_vec) - global_transform.orign
And the opposite operation would be:
local_vec = to_local(global_vec + global_transform.orign)
By the way this is another way to write the same code:
var global_vec:Vector3 = (global_transform * local_vec) - global_transform.orign
And the opposite operation would be:
local_vec = global_transform.affine_inverse() * (global_vec + global_transform.orign)
Which I'm mentioning because I want you to see the similarity with the following approach.
Basis
I would rather not consider the Vector3 to be positions. Just free vectors. So, we would transform it with only the Basis, like this:
var global_vec:Vector3 = global_transform.basis * local_vec
And the opposite operation would be:
local_vec = global_transform.affine_inverse().basis * global_vec
This approach will not have the translation problem.
You can think of the Basis as a 3 by 3 matrix, and the Transform is that same matrix augmented with a translation vector (origin).
Quat
However, if you only want rotation, let us se quaternions instead:
var global_vec:Vector3 = global_transform.basis.get_rotation_quat() * local_vec
And the opposite operation would be:
local_vec = global_transform.affine_inverse().basis.get_rotation_quat() * global_vec
Well, actually, let us invert just the quaternion:
local_vec = global_transform.basis.get_rotation_quat().inverse() * global_vec
These will only rotate the vector (no scaling, or any other transformation, just rotation) according to the current orientation of the KinematicBody.
Rotating a Transform
If you are trying to rotate a Transform, either…
Do this (quaternion):
transform = Transform(transform.basis * Basis(quaternion), transform.origin)
Or this (quaternion):
transform = transform * Transform(Basis(quaternion), Vector3.ZERO)
Or this (axis-angle):
transform = Transform(transform.basis.rotated(axis, angle), transform.origin)
Or this (axis-angle):
transform = transform * Transform.Identity.rotated(axis, angle)
Or this (Euler angles):
transform = Transform(transform.basis * Basis(pitch, yaw, roll), transform.origin)
Or this (Euler angles):
transform = transform * Transform(Basis(pitch, yaw, roll), Vector3.ZERO)
Avoid this:
transform = transform.rotated(axis, angle)
The reason is that this rotation is always before translation (i.e. this rotates around the global origin instead of the current position), and you will end up with an undesirable result.
And yes, you could use rotate_x, rotate_y and rotate_z, or set rotation of a Spatial. But sometimes you need to work with a Transform directly.
See also:
Godot/Gdscript rotate + translate from local to world space.
How to LERP between 2 angles going the longest route or path in Godot.

How do I check if two KinematicBody2D's are overlapping in Godot?

I've just gotten into coding, and I'm trying to make a simple duck shooter game in Godot 3.0. I have a crosshair(Kinematicbody2D) and ducks flying across the screen(also KinematicBody2D). Is there a way that I can detect if the duck and crosshair are overlapping? Like an if statement?
In case anyone's curious, this is the code I've got so far (This is the duck script and the comments are what I need to add in on that line).
func _physics_process(delta: float) -> void:
position.x += 4
if (position.x > 1600):
Score -= 1
position.x = rand_range(-250, -1000)
if Input.is_action_just_pressed("shoot"):
#check if overlapping with crosshair
Score += 1
#bird explodes in feathers
position.x = rand_range(-250, -1000)
else:
Score -= 0.25
I don't think it makes sense to make the crosshair into a physics body. Does it collide/push/bounce off obstacles? Much less a KinematicBody2D. Do you need move_and_slide or can you get away with writing the position? So here are some alternatives to go about it, before I answer the question as posted.
Input Pickable
If you want to find out if the pointer interacts with a physics body, you can enable input_pickable, and you will get an "input_event" signal whenever it happens.
Mimic input Pickable
Otherwise you can get the position of the pointing device in an _input event and query what physics objects are there. Something like this:
if (
event is InputEventScreenDrag
or event is InputEventScreenTouch
or event is InputEventMouse
):
var viewport := get_viewport()
var position:Vector2 = viewport.get_canvas_transform().affine_inverse().xform(event.position)
var objects := get_world_2d().direct_space_state.intersect_point(position)
for object in objects:
print(object.collider)
And see if the one you want is there.
Area2D
Another option is to make the crosshair into an Area2D, then you can ask the Area2D for its overlapping_bodies, and see if the one you want is there. Or call overlaps_body passing your physics body as parameter and it returns true or false if it is overlapping the Area2D or not, respectively.
KinematicBody2D collisions
And to answer the question on the title, if you have two kinematic bodies, if you moved them with move_and_* methods (which is how it is intended). You can a lists of what they collided with like this:
for i in get_slide_count():
var collision = get_slide_collision(i)
print("Collided with: ", collision.collider.name)
Otherwise, you can do this:
var parameters := Physics2DShapeQueryParameters.new()
parameters.transform = global_transform
parameters.set_shape($CollisionShape2D.shape)
var results = get_world_2d().direct_space_state.intersect_shape(parameters)
for result in results:
print(result.collider)

Running time for a shortestP alg in unweighted undirected graph in python3

For this kind of problem I thought it would have been better make some BFS-like implementation. I don't know why, after some running time testing, it came out a plot that resembles an exponential function.
So I began to think of my code's correctness: is it really efficient? Can you help me to make a running time analysis for a good algorithm?
I've plotted the log in base 1.5 for the x-axis (since in the code I use a list of the first 30 powers of 1.5 as number of vertices input in a random graph generetor). Still looks exponential...
def bfs_short(graph, source, target):
visited = set()
queue = collections.deque([source])
d={}
d[source]=0
while queue:
u = queue.pop()
if u==target:
return d[target]
if u not in visited:
visited.add(u)
for w in graph[u]:
if w not in visited:
queue.appendleft(w)
d[w]=d[u]+1
The thing is... I didn't posted also the benching input trials which also may cause problems but first of all I want to be sure that the code works fine... solving the problems related to testing is my final purpose.
A problem in your code is that your queue does not take in account the distance to the origin in order to prioritize the next vertex it will pop.
Also, collections.deque is not a priority queue, and thus will not give you the closest unvisited vertex seen so far when you pop an element from it.
This should do it, using heapq, a built-in heap implementation:
import heapq
def bfs_short(graph, source, target):
visited = set()
queue = [(0, source)]
heapq.heapify(queue)
while not queue:
dist, vertex = heapq.heappop(queue)
if vertex == target:
return dist
if vertex not in visited:
visited.add(vertex)
for neighbor in graph[vertex]:
if neighbor not in visited:
heapq.heappush(queue, (dist + 1, neighbor))
In this version, pairs are pushed in the queue. To evaluate and compare tuples, Python tries to compare their first element, then the second in case of equality, and on and on.
So by pushing dist(vertex, origin) as first member of the tuple, the smallest couple (dist, vertex) in the heap will also be the closest to the origin vertex.

How to find number of Reference Planes passing through a selected wall.

I need to find out the number of Reference planes and their names which are passing through a selected wall. I can get all the reference planes for a particular document but how shall I do this for a particular wall.
You help would be appreciated!
Thanks.
If the ElementIntersectFilter doesn't work for your needs, you'll have to extract the geometry of the wall and reference plane and work with those directly.
Intersecting the reference planes with the wall solids can work, but there's a simpler answer that will work, if I understand your question correctly. I'm assuming you only want the walls where the green line of the ref plane intersects, rather than treating the reference plane object as an infinite geometric plane. In the screenshot below, I assume you want to find the checkmarks, but not the red X's. I'm also assuming you're looking at this as a plan exercise, and not specifically setting the vertical extents of the reference plane (this is just based on how I've seen most people use Revit). The following function takes as inputs a single wall and a list of ref planes (you mentioned you already have the collection of all ref planes) and will return a list of ref planes which intersect the wall.
public static List<ReferencePlane> getRefPlanesIntersectingWall( Wall wal, List<ReferencePlane> refPlanesIn)
{
//simplify this to a 2D problem, using the location curve of the wall
List<ReferencePlane> refPlanesOut = new List<ReferencePlane>();
LocationCurve wallLocation = wal.Location as LocationCurve;
Curve wallCurve = wallLocation.Curve;
Double wallZ = wallLocation.Curve.GetEndPoint(0).Z;
foreach (ReferencePlane rp in refPlanesIn)
{
XYZ startPt = new XYZ(rp.BubbleEnd.X, rp.BubbleEnd.Y, wallZ);
XYZ endPt = new XYZ(rp.FreeEnd.X, rp.FreeEnd.Y, wallZ);
Line rpLine = Line.CreateBound(startPt, endPt);
SetComparisonResult test = wallCurve.Intersect(rpLine);
if (test == SetComparisonResult.Overlap ||
test == SetComparisonResult.Subset ||
test == SetComparisonResult.Superset ||
test == SetComparisonResult.Equal )
{
refPlanesOut.Add(rp);
}
}
return refPlanesOut;
}
I would start by trying the built-in ElementIntersectFilter. The documentation has a nice example, replace "FamilyInstance" with "referencePlane" and that may do it.
http://www.revitapidocs.com/2017/19276b94-fa39-64bb-bfb8-c16967c83485.htm
If that doesn't work, you'll need to extract the solid of the wall and intersect with the reference plane.

Rotating/Turning Groups of Ellipses

I'm working on a project where I create mini galaxies using ellipses, rotate, radians, etc. on mouseX and mouseY. However, I'd love it if each mini galaxy could rotate left or right, so that it looks like a galaxy turning slowly in space. Not sure how I'd do this, though, and would love some guidance. Do I have to create an array that holds the ellipses for each galaxy, and then somehow rotate that? Can I simply set a rotate() for each individual ellipse as it draws to the screen? Thanks for any help!
var bgimg;
function preload(){
//for (var i = 0; i < planetArray.length; i++) {
bgimg = loadImage('Assets/galaxy_background.jpg');
}
function setup(){
createCanvas(1301, 822);
background(bgimg, 100);
//background(25,25,22);
}
function draw() {
//background(0);
fill(255);
noStroke();
textSize(19);
text("Create mini-galaxies by holding your mouse in a location. Move to create another.", 20, 40);
star()
//function mousepressed(){
}
function star(){
//angle = map(mouseX, 0,width, 0,360);
//rotate(radians(angle*100));
noStroke();
//translate(width/2, height/2);
translate(mouseX,mouseY);
fill(0);
rotate(radians(frameCount%360)); //rotates output of ellipses
rotate(radians(1000*frameCount%360));
for(var i =0; i < 20; i++){
push();
noStroke();
tint(255, 127);
fill(random(230),5,random(210),random(230));
// fill(random(125),random(250),random(100));
ellipse(10*frameCount % (width/20),0,5,5);
rotate(radians(mouseX, mouseY));
//image(stars, 10*frameCount % (width/2),0,10,10)
//image((10*frameCount % (width/2),0,10,10)
//
pop();
}
}
You'll have better luck with your questions if you try to narrow them down to an MCVE instead of posting your full sketch. It's hard to answer general "how do I do this" type questions. It's much easier to answer specific "I tried X, expected Y, but got Z instead" type question. That being said, I'll try to answer in a general sense:
You're having trouble because of the fact that you're letting your drawing accumulate by only calling the background() function once instead of clearing it every frame. There's nothing wrong with this, but it does make it impossible to apply transforms and rotations to stuff you've already drawn.
Like I said in your other question, most Processing sketches do this:
Store everything you need to draw in a data structure.
You might store an array of PVectors. Or you might create a Galaxy class that contains variables and functions that allow it to draw itself, which you call from your draw() function. The data structure you use is entirely up to you.
This page and this page contain discussions on creating objects in p5.js, or you might just try a google search. Here is an example that uses a class that knows how to draw itself, and then creates an instance of that class to create a sketch.
Clear previous frames every time draw() is called.
Most sketches call the background() function every frame. That might seem annoying because then you have to redraw everything, but that's what the data structures are for.
Redraw everything you want to be drawn every frame.
Iterate over those data structures and redraw your scene. This might be as simple as iterating over an array of PVectors, or maybe you'll want to create objects that know how to draw themselves.
Like I said, this is very general, and exactly what you do depends on how you think about all of the above. There isn't a single best way to do this, so it's hard to be more specific.

Resources