I am trying to make an Object move to a Cube wich is stored in an Array.
The Array is filled with gameObjects with a tag.
I can get the Object to move instantly to the cube, but not slowly like its walking to it.
This is my script:
var moveTo : GameObject;
function Update(){
print(FindClosestEnemy().name);
}
function FindClosestEnemy():GameObject{
var chasePoints : GameObject[];
chasePoints = GameObject.FindGameObjectsWithTag("chasePoint");
var closest : GameObject;
var distance = Mathf.Infinity;
var position = transform.position;
for(var go: GameObject in chasePoints){
var diff = (go.transform.position-position);
var curDistance = diff.sqrMagnitude;
if(curDistance < distance){
closest = go;
moveTo = closest;
transform.position -= moveTo.transform.position;
distance = curDistance;
}
}
return closest;
}
I also tried the Time.deltaTime thing, but then it teleports far away from the cube.
And just converting it to Transform Array isnt working out either :( Any ideas to make this work?
Help is much appreciated :) Thanks in advance!
It looks like you are doing the whole transformation in one frame. You need to pick a velocity and apply it to the object for each frame. You know the from and to. Pick how long you want it to take and update it incrementally. Remember that you cannot be sure there will be 60 frames a second so take that into account.
You can use
Vector3.MoveTowards
For maxDistanceDelta you choose a velocity and multiply it with Time.deltaTime to be frame-length-independant:
Vector3.MoveTowards(transform.position, moveTo.transform.position, speed * Time.deltaTime);
Related
Stickman
I have this stickman here in unity 2D and i want his arms to always reach out to the direction of the mouse. I have no ideas on where i should start and i'm hoping someone here could help me out. Thanks!
Foremost, you need to determine the mouse position. It can be done with the following method:
public Vector3 GetMouseWorldPosition()
{
Vector3 mouseScreenPosition = UnityEngine.Input.mousePosition;
Vector3 mouseWorldPosition = Camera.main.ScreenToWorldPoint(mouseScreenPosition);
return mouseWorldPosition;
}
I use Camera.main here for demonstration purposes. In sake of performance it will be better to cache it as a field in your class.
Now, when you have the target coordinates, you can rotate the hand. Here is an example method:
public void RotateLimb()
{
Vector3 rotationTargetPosition = GetMouseWorldPosition();
Vector3 directionVector = (rotationTargetPosition - _limb.transform.position).normalized;
float angleInRad = Mathf.Atan2(directionVector.y, directionVector.x);
Vector3 targetAngle = _limb.transform.eulerAngles;
targetAngle.z = angleInRad * Mathf.Rad2Deg;
_limb.rotation = Quaternion.Euler(targetAngle);
}
Method RotateLimb() can be called in Update or a coroutine.
All the variables of this method can also be stored as private fields in your class.
_limb must contain Transform of your hand GameObject and you can assign it as SerializeField
[SerializeField] private Transform _limb;
_limb will rotate around its pivot. Therefore, pivot must be in the center of the shoulder. In order to achieve it, you can place all the graphics of your hand as a child of _limb and adjust it accordingly.
This seems like the most straightforward way to do it.
Good times. How do I implement the NPC rotation towards the selected object?
public GameObject BufferObject;
public float MoveSpeed = 1f;
void Update()
{
float step = MoveSpeed * Time.deltaTime;
transform.position = Vector2.MoveTowards(transform.position, BufferObject.transform.position, step);
}
Here is the script for moving the NPC to the selected object (Buffer Object) and the movement works perfectly, but the implementation of the rotation causes Me difficulties, please advise.
For Unity2D.
Simply get the desired direction
var direction = (BufferObject.transform.position - transform.position).normalized;
and then the desired rotation using Quaternion.LookRotation like e.g.
var targetRotation = Quaternion.LookDirection(direction);
Then either apply it directly if you want it immediately
transform.rotation = targetRotation;
Or if you want it smooth you could use e.g. Quaternion.RotateTowards like
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, anglePerSecond * Time.deltatime);
Have in mind though that it might look awkward if the rotation is too slow since your NPC could move back/sidewards already while still not fully looking towards the target ;)
So you might want to wait until
if(Quaternion.Angle(targetRotation, transform.rotation) <= certainThreshold)
{
... your movement code
}
So the answer and the solution from Me, albeit stupid, but working. In order to reflect the sprite, you need to get a variable, either 1 or -1 (For Scale). This code will show the distance from one NPC to the object:
BufferObject.transform.position.x - transform.position.x
And here I get a lot of values as if to the left of the NPC, then -x... , and if to the right, then x... thereby it is possible to determine which side of the object, so also level the value from here (Optional) to 1 or -1 and apply this result to transform.localScale and thereby solve the problem of how to reflect (Rotate the sprite) towards the object. Use it for your health :)
Complete code:
float localPositionAmount = BufferObject.transform.position.x - transform.position.x;
if (localPositionAmount >= 1)
{
gameObject.transform.localScale = new Vector3(1, transform.localScale.y, transform.localScale.z);
}
if (localPositionAmount <= -1)
{
gameObject.transform.localScale = new Vector3(-1, transform.localScale.y, transform.localScale.z);
}
if (localPositionAmount == 0)
{
gameObject.transform.localScale = new Vector3(transform.localScale.x, transform.localScale.y, transform.localScale.z);
}
Yes, the code is the simplest and without enumerations and other things, but it works perfectly. I still had to figure it out myself...
I have a GameObject that takes position coordinates from a file. This GameObject moves with vibration rather than smoothly. (as if moving back and forth.)
Here is the code that provides the movement:
int counter = 0;
void Update()
{
var maxDistance = speed_* Time.deltaTime;
var oldPosition = transform.position;
var newPosition = Vector3.MoveTowards(transform.position, positions[counter], maxDistance);
var actualDistance = Vector3.Distance(newPosition, oldPosition);
var distanceRemainder = maxDistance - actualDistance;
if (distanceRemainder > 0.0001)
{
newPosition = Vector3.MoveTowards(newPosition, positions[counter], distanceRemainder);
counter++;
}
transform.localPosition = newPosition;
}
NOTE: The data read from the file is in the "positions" array (x,y,z coordinates).
When I lower the 300f value in the variable maxDistance, the vibration stops and the motion becomes more fluid. However, Gameobject speed is also slowing down. How can I ensure a fast and smooth movement?
SOLUTION:
While looking for a solution of the problem, I came across the this topic. It helped me learn the source of the problem.
I have observed that the GameObject is not vibrating in Scene view, it was moving smoothly. But the object seemed to be vibrating in GameView. The problem is not the moving object, it's the camera function I write to follow it.
The camera function that was written to follow the object has been updated and the problem has disappeared.
One can see more of the solution by going to Post #13 in the link above.
Thanks to everyone trying to help.
This is caused cause you are using your distanceRemainder as your maxDistanceDelta, which I think is incorrect, if you want a smooth movement, you should multiply it for the Time.deltaTime, try:
newPosition = Vector3.MoveTowards(newPosition, positions[counter], distanceRemainder*Time.deltaTime);
Or simply declare speed variable and do:
newPosition = Vector3.MoveTowards(newPosition, positions[counter], speed*Time.deltaTime);
I assume what you want is your object moving with a constant speed to the first position. Once it reaches it, move to the next one.
I would do it in a simple Coroutine which is better to understand and maintain than doing stuff in Update:
private void Start()
{
// todo assign positions
StartCoroutine(RunPositions());
}
private IEnumerator RunPositions()
{
foreach(var position in positions)
{
while(!Mathf.Approximately(Vector3.Distance(transform.position, position), 0))
{
var maxDistance = speed_* Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, positions[counter], maxDistance);
// render and continue in the next frame
yield return null;
}
}
}
If you are fine with a precision of 0.00001 you can also simply use
while(transform.position != position)
instead.
this is what i want to achieve
I am currently trying to build a RADAR sensor on unity. I am currently using spherecast. How do i set the view angle of the sphere cast and also how do i read the angle at which an object is present in front of it.
What i have used now is Vector3.angle but this shows 160 degrees if the object is directly infront of the radar instead it should be showing 90 degrees.
Ill paste the code that i have implemented below
Any guidance is appreciated.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class spherecast : MonoBehaviour
{
Rigidbody rb;
public List<GameObject> CurrentHitObjects = new List<GameObject>();
//public GameObject curobject;
public float radius;
public float maxdist;
public LayerMask layermask;
public float velocity;
public Time deltatime;
public Vector3 previous;
private Vector3 origin;
private Vector3 direction;
private float hitdist;
// Use this for initialization
void Start()
{
foreach (GameObject cur in CurrentHitObjects)
{
previous = cur.transform.position;
}
}
// Update is called once per frame
void Update()
{
origin = transform.position;
direction = transform.forward;
hitdist = maxdist;
CurrentHitObjects.Clear();
RaycastHit[] hits = Physics.SphereCastAll(origin, radius, direction, maxdist, layermask, QueryTriggerInteraction.UseGlobal);
foreach (RaycastHit hit in hits)
{
Plane[] planes = GeometryUtility.CalculateFrustumPlanes(Camera.main);
if (GeometryUtility.TestPlanesAABB(planes, hit.collider.bounds))
{
float angle = Vector3.Angle(transform.forward, hit.point.normalized);
float degree = Mathf.Acos(angle) * Mathf.Rad2Deg;
Vector3 pos = hit.point;
Debug.Log(hit.collider.name + "position =" + pos);
CurrentHitObjects.Add(hit.transform.gameObject);
hitdist = hit.distance;
Debug.Log(hit.transform.name + "Distance ="+ hitdist);
Debug.Log(hit.collider.name + "Angle = " + angle);
velocity = ((hit.transform.position - previous).magnitude) / Time.deltaTime;
previous = hit.transform.position;
Debug.Log(hit.transform.name + "Velocity =" + velocity);
}
else
{
return ;
}
}
}
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Debug.DrawLine(origin, origin + direction * hitdist);
Gizmos.DrawWireSphere(origin + direction * hitdist, radius);
}
}
As far as I can tell your code doesn't do anything. My first tip would be to remove all of your commented out code, but after that here is why your code does nothing at all:
You pass an array of objects to your script. Fine so far.
You take this entire array of objects 'CurrentHitObjects' and pass the transform.position of every single object to a single vector3. This means that all the values are overwritten except for the last one. This would be a big problem if you were trying to find the position of every single object. This would instead require vector3[]. But there is another bigger problem.
'previous', which holds transform.position of the objects is not used anywhere. So you are not actually finding the location of anything.
You use start() (which only runs once by the way) to iterate through your object array, but then you clear, CurrentHitObjects.Clear();, right at the beginning of update() (which runs many times per second by the way). The problem here, is that if you hoped to use CurrentHitObjects for anything in your code, you can't because you have wiped it before you even start doing anything with it.
Your raycast[] is shooting towards nothing. Seems to me like it just shoots forward.
You are finding the angle between the forward direction and the forward direction?
Honestly there are a lot of major problems with this code. I don't mean to be harsh, but it looks like you copy and pasted someone else's code and don't know how to use it. This needs a complete rework. If you know how to code I would throw it out and start over again. See my comment on your answer for a better way to do what you want.
If you don't know how to code, you should not be asking for freebie working code on stackoverflow. Try a unity forum instead. If you are trying to get better, see my above comments.
I'm trying to implement a tower defense game in Unity, and I can't figure out how can I assign a velocity or a force to a new instantiated object (in the creator object's script)
I have a tower which is supposed to shoot a bullet towards the enemy which triggered its collider. This is the script of the towers:
function OnTriggerEnter(other:Collider){
if(other.name=="Enemy")
{
ShootBulletTo(other.transform);
}
}
function ShootBulletTo(target:Transform)
{//public var Bullet:Transform
var BulletClone = Instantiate(Bullet,transform.position, Quaternion.identity); // ok
BulletClone.AddForce(target.position); //does not compile since Transform.AddForce() does not exist.
}
I guess the problem is I have to use a Transform variable for instantiate but I need a GameObject variable for velocity, force etc. So how can I instantiate the bullet with initial velocity?
Thanks for help.
You have to acces the rigidbody component of your bullet clone to change the force, not the transform.
Here's how your code should look:
function OnTriggerEnter(other:Collider)
{
if(other.name=="Enemy")
{
ShootBulletTo(other.transform);
}
}
function ShootBulletTo(target:Transform)
{
var Bullet : Rigidbody;
BulletClone = Instantiate(Bullet, transform.position, Quaternion.identity);
BulletClone.AddForce(target.position);
}
There's also a good example in the unity script reference
http://docs.unity3d.com/Documentation/ScriptReference/Object.Instantiate.html
[EDIT] I'm pretty sure, that you don't want to add the enemies position as a force, instead you should add a direction that goes towards the enemies position.
You subtract two positions to gain a direction vector between them, so the ShootBulletTo function should look like this:
function ShootBulletTo(target:Transform)
{
// Calculate shoot direction
var direction : Vector3;
direction = (target.position - transform.position).normalized;
// Instantiate the bullet
var Bullet : Rigidbody;
BulletClone = Instantiate(Bullet, transform.position, Quaternion.identity);
// Add force to our bullet
BulletClone.AddForce(direction);
}