How to make an SKSpriteNode to walk smoothly on bumpy terrain? - sprite-kit

curious on how I would make a SKSpriteNode walk smoothly across bumpy terrain (Image below evaluating "Bumpy Terrain")
I also want the image to have an SKPhysicsBody. How can I possibly do this?

Having just done that (in Unity) the basic premise is as follows:
cast a ray downwards from the center of the body to its "feet" (ie ray length is equal to half height of the body/node)
if the ray intersects with a body, check if the body is "walkable" (ie somehow defined as a ground body, for simplicity you can just check if the body is non-dynamic, for more fine-grained control compare the category and contact bitmasks of the intersecting bodies)
if you found an intersecting, walkable body, set the body's position to where the ray hit the other body, plus half the body/node's height
In Sprite Kit the only way to get the intersection point from a raycast is to use enumerateBodiesAlongRayStart:end:usingBlock: of the SKPhysicsWorld class. If your character can only walk up straight (ie he won't rotate to adapt to the terrain, and the terrain doesn't have "loops") you only need to check the Y coordinate of the intersection point.
Say your node's position is at Y=340 and the ray intersects at Y=310 and your node's height is 80 then:
(340 - 310) + 80 / 2 = 70
Then 70 is the distance from the floor your player should be positioned at, to be exact it's the Y coordinate where the ray hit the floor (310) plus this 70 which gives you Y=380 as the new height. Keep the X coord and change the Y coord as you walk over the plane.
Of course the ground plane needs to be a physics body, specifically using an edge shaped body. There are tools that let you design those points from shapes, most prominently PhysicsEditor. But for a start you can experiment with a single line segment, sloped at an angle to test if your character is properly walking the plane up or down.
Note that if you are using physics you should probably set the physics body's velocity to 0,0 after you determined a ground hit, otherwise velocity may accumulate and the body eventually falls through the floor, or can't jump, or do other weird stuff.

Related

What's the difference between ScreenToWorldPoint and ScreenPointToWorldPointInRectangle?

What's the difference between ScreenToWorldPoint and ScreenPointToWorldPointInRectangle? And when should we use which one?
Senario:
I'm using UI system creating my card game similar to Hearthstone. I want to transform my mouse drag positions to world position. RectTransformUtility.ScreenPointToWorldPointInRectangle(UIObjectBeingDragged.transform.parent as RectTransform, Input.mousePosition, Camera.main, out resultV3) works fine. But I also tried Camera.main.ScreenToWorldPoint(Input.mousePosition), and it give a different and "wrong" result.
ScreenToWorldPoint
Gives you a world position (the return value) that is along a ray shot through the near plane of the camera (the Camera whose method is being called) at some given point (the x and y components of the position parameter) and a given distance from that near plane (the z component of the position parameter).
You should use this when you:
have a specific distance from the near plane of the camera you are interested in and
don't need to know if it hit inside some rectangle or not
You could think of this as a shortcut for Ray.GetPoint that uses the x and y of position and various info of the Camera to make the Ray, and the z component of position is the distance parameter.
ScreenPointToWorldPointInRectangle
Also gives you a world position (worldPoint) along a ray shot through the near plane of a camera (cam) at a given point (screenPoint). Only this time instead of giving you the point a given distance along the ray, it gives you the intersection point between that ray and a given rectangle (rect) if it exists, and tells you if such an intersection exists or not (the return value).
You should use this when you:
have a specific rectangle you are interested in the intersection with a camera ray,
You don't know the distance between the camera or its near plane and the intersection point
Want to know if that rectangle is hit by the ray or not.
You could think of this as a shortcut for Plane.Raycast which uses cam and screenPoint to make the Ray, and rect to make the Plane, and also gives some more information of if it would intersect outside the boundaries of the rect.

How to search for objects in a specific direction in Unity?

I am new to Unity and created an object, let's say a car. Now I want to know the distance to the next object in a specific direction, for example in front of it or at 45 degrees.
What I want to archieve is comparable to the car sending light rays in the direction measuring the distance to the next collider.
What I can think of is checking for all objects in the scene, but hopefully there is a better solution.
Your looking for Physics.Raycast.
This creates a line from point a (origin) to point b (origin + direction * maxDistance). The documentation has a nice example.
maxDistance would only return object in that range.
You can do multiple ray casts adding rotation to the direction your rays to get a wider scan. Physics.OverlapSphere is also an option, it checks a full sphere around a location for anything that overlapse. You would need to then check if the angle between the car and the object is in your range by calculating the angle between the 2 positions.

Why am I getting an incorrect vector when trying to find HingeJoint2D.anchor in world space?

In the scene, I have a long chain of children that are connected via hinge to their parent. For my code, I need the position of the hinge anchors in world space, so I use:
public Vector2 hingeVector => hinge.anchor + (Vector2)gameObject.transform.position;
For the first hinge, that code gives the correct position. But for the second hinge this happens:
The red point is the vector I get, the blue point is the actual position. As you can see, it's a somewhat small but still problematic difference.
Is there any way I can fix this? I couldn't find anything like this online.
You need to add the object's rotation
The anchor values are axis aligned and aren't affected by rotation, but in order to calculate the anchor point in world space, knowing the transform's position, you need to rotate the anchor point values by the object's rotation then add it to the position:
Vector2 p = hinge.anchor.Rotate(gameObject.transform.rotation.eulerAngles.z)
+ (Vector2)gameObject.transform.position;

Which side of my cube is hitting the plane below the cube

Im working in Unity and I have a simple scene. It consists of a cube which has a box collider on it. Below this cube is a plane
I want to know which side of the cube is hitting the plane at any given instant
One way to do this is to cast a ray from each side of the cube and determine which ray is colliding with the plane
But i fear that it may be performance heavy. Is there a way to do this in an efficient manner?
I used for same need:
1) Place plane for each side of cude;
2) Set clear color for planes;
3) Write script that check plane position (in your option need loop that search plane with lower position.
If you're just looking for a way other than just ray casting then you could create a method that takes in your cube's position and your plane's position and then do some calculations.
Vector3 heading = plane.transform.position - cube.transform.position;
float distance = heading.magnitude;
Vector3 direction = heading / distance;
From here you would just have to check what that direction is.

Unity raycast distance incorrect for plane collisions

I've got a ray cast being created from the 'yellow X' in the pictures below. It is detecting the collision hit, however the distance is way off (~ 21 instead of 7 etc) . The green X shows where the collision is taking place and hence how long the distance should be
The Line Renderer is being drawn from start point along the forward vector for the ray hit distance, so in the second picture you can see where I have a much smaller plane with better tessellation it works fine, but with a larger ground plane in the first picture it is way off. It also works fine with other objects in the scene like small boxes.
I have tried using a box collider which still has the same problem.
Any ideas?