- Home /
How to make an object follow along the shape of another?
I have a large sprite which acts as a terrain, and a rectangle that should travel along the sprite's border. I want the rectangle to be able to follow this path even if at some point the angle of the terrain is higher than ninety degrees and I want it to follow the terrain/sprite smoothly. I have try many things but nothing seems to work. Does anyone have an idea what can I do? Thanks!
Also constantForce don't seem to work with 2D physics and in any case that is not what I'm looking for. It should work almost like a rail, but the object needs to be able to jump.
I don't know the nature of your game, but I would approach this problem without physics. I'd create a spline for the object to follow. There has been spline code posted to UA, or iTween (which is free), can create splines and also has a path editor that makes the creation process easy. I would send an empty game object down the spline with the visible object as a child. I'd handle jumping by using Transform.localPosition to allow the visible object to move away from the empty game object.
Hi robertbu! Thanks for your answer! That is a good idea, I will look into the spline solution. I'm also trying locking the relative (x,y) position of the object with raycast. If I manage to solve it I will post it here. In the meantime here is a picture of the rough proyect. The rectangle should advance forward over the terrain, but I agree that rigidbody is not optimal.][1]
Answer by josessito · Feb 22, 2014 at 04:26 AM
I'm failing miserably with this. This code kind of work, but because of the irregularity of the 2D polygonal Mesh, it is very jittery.
Here is the code.`enter code here
#pragma strict
var distancer : float;
var speed : float;
function Update () {
//more functionality will came here
move();
}
function move(){
var hit : RaycastHit2D;
var up = transform.TransformDirection(Vector2.up); // A vector pointing up locally
//the recatugle doesnt have a collier, so there is no conflict with ray
hit = Physics2D.Raycast(transform.position, -up);
Debug.DrawLine(transform.position, hit.point);
//Vectorial sum of the vector origin to hit point + hit.normal vector (multiplied becouse the normal vector is unitary)
// this should place the rectangle above the curve of the terrain
transform.position = hit.point + hit.normal*distancer;
// this is so the rectangle face follows the terrains, it basically aligns the y axis of the object with the normal of
// the ground
transform.up = hit.normal;
// this is to make it move
transform.Translate(Vector3.right*speed*Time.deltaTime);
}
Here is an Image
Is there a way to smooth this kind of things, maybe by some crazy interpolation or something? I'm kind of new to programming, I'm learning to program along with learning unity. I've watch some courses on youtube about Java but that's kind of it, so maybe there is some other approach to this. Thanks!
EDIT: Sorry for my clunky English, this is not my first language.
I changed it to a comment because you wrote:
I'm failing miserably with this. This code kind of work, but because of the irregularity of the 2D polygonal $$anonymous$$esh, it is very jittery.
And you followed that with additional questions.
I've converted it back to an 'Answer'. If you consider your question Answered, please click on the checkmark next to your answer to close the question out.
I finally did it! The code I use is the same as the one i posted, and even though the object movement is not smooth, it seems reliable. In the end I didn't attached that code to the actual rectangle(sprite), I attached it to an empty square collider and I made the rectangle sprite a child of it. Then I used the following code to make the sprite follow the square collider smoothly. I also replaced the 2D poligin collider for an edge collider. I even use Quaternions although I'm not sure if it is entirely necessary given the 2D nature of the project. Thank good for internet, youtube and unity answers!! I'll soon be back with more problems and maybe eventually, with some answers. Thanks also to robertbu for his answers.
#pragma strict
var damping : float;
var rotationDamping : float;
var carrierTransform : Transform; // the transform of the object to mimnic smoothly
private var velocity = Vector3.zero;
function Start () {
// this is to be able to move the object (sprite) independatly from the parent
// but it is still a child so if you move the the parent in the editor, this object will follow
transform.parent = null;
}
function Update () {
// copies the x,y of the carrierTransform but appling some damping to romeve horizontal and
// vertical jerkkinnes
transform.position = Vector3.SmoothDamp(transform.position, carrierTransform.position , velocity, damping);
// copies the rotation carrierTransform interpolating and damping so it rotates smoothly
transform.rotation = Quaternion.Slerp(transform.rotation, carrierTransform.rotation, Time.deltaTime*rotationDamping);
}
If your question is now answered, click on the checkmark next to your answer to close it out. Thanks.
Answer by robertbu · Feb 22, 2014 at 03:58 AM
Here is a simple demonstration project (Unity package) using iTween for using a spline solution, and moving a character on the spline. A LineRenderer is used to display the spline, though it could just as easily be a graphic like the one you posted in your comment.
The core issue is keeping the object oriented correctly. Here is the movement code:
using UnityEngine;
using System.Collections;
public class CharacterMover : MonoBehaviour {
private Vector3[] path;
public float speed = 0.06f;
private float fraction = 0.0f;
private Transform trans;
void Start () {
path = iTweenPath.GetPath ("Main");
trans = transform;
}
void Update () {
fraction += Input.GetAxis("Horizontal") * Time.deltaTime * speed;
fraction = Mathf.Clamp01(fraction);
Vector3 pos = iTween.PointOnPath (path, fraction);
transform.position = pos;
if (fraction + .02f <= 1.0f) {
Vector3 futurePos = iTween.PointOnPath (path, fraction + 0.02f);
Vector3 dir = futurePos - pos;
Vector3 up = Vector3.Cross(Vector3.forward, dir);
transform.up = up;
transform.rotation = Quaternion.LookRotation(dir, up);
}
}
}
It uses iTween for the spline, which may not be ideal for a production project. But you can play and see if a spline solution is the right answer for yoru app. I've been involved in several questions similar to yours (though 3D not 2D), where the author was attempting to solve movement on arbitrary terrains using raycasting. There are some fundamental issues with raycasting and arbitrary terrains, and none of the questions that used raycasting had a satisfactory conclusion.
Oh, and a jump using an AnimationCurve is implement in a separate script and uses 'localPosition' to make the jump.
Thanks again robertbu! I've just finish posting my answer when I saw yours. I will try with splines, the reason why I was trying to avoid them is that I'm not sure if I'll be able to manipulate them correctly. $$anonymous$$ainly because I barely know JavaScript, C# is completly alien to me. But there is always youtube I guess.
Answer by Mynameisbec · Jan 28, 2021 at 09:30 PM
This is my script for chasing in unity
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Octopus : MonoBehaviour
{
public Transform player;
private Rigidbody2D rb;
private Vector2 movement;
public float moveSpeed;
// Use this for initialization
void Start()
{
rb = this.GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
Vector3 direction = player.position - transform.position;
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
rb.rotation = angle;
direction.Normalize();
movement = direction;
Debug.Log(direction);
}
void FixedUpdate()
{
MoveCharacter(movement);
}
void MoveCharacter(Vector2 direction)
{
rb.MovePosition((Vector2)transform.position + (direction * moveSpeed * Time.deltaTime));
}
}