How can I move/animate/translate/tween an Image from position A to position B using C# code in Unity 4.6?
Assuming Image is a GameObject, so it could be a Button or whatever.
There has to be a one-liner for this, right? I've been googling for a while but all I can see out-of-the-box is stuff done in Update, and I firmly believe doing stuff in Update is not a fast way of scripting things.
maZZZu's method will work, however, if you do NOT want to use the Update function, you can use an IEnumerator/Coroutine like so…
//Target object that we want to move to
public Transform target;
//Time you want it to take before it reaches the object
public float moveDuration = 1.0f;
void Start ()
{
//Start a coroutine (needed to call a method that returns an IEnumerator
StartCoroutine (Tween (target.position));
}
//IEnumerator return method that takes in the targets position
IEnumerator Tween (Vector3 targetPosition)
{
//Obtain the previous position (original position) of the gameobject this script is attached to
Vector3 previousPosition = gameObject.transform.position;
//Create a time variable
float time = 0.0f;
do
{
//Add the deltaTime to the time variable
time += Time.deltaTime;
//Lerp the gameobject's position that this script is attached to. Lerp takes in the original position, target position and the time to execute it in
gameObject.transform.position = Vector3.Lerp (previousPosition, targetPosition, time / moveDuration);
yield return 0;
//Do the Lerp function while to time is less than the move duration.
} while (time < moveDuration);
}
This script will need to be attached to the GameObject that you would like to move. You will then need to create another GameObject in the scene that will be your Target…
The code is commented but if you need clarification on something just post a comment here.
If you want to do the movement yourself you can use something like this:
public Vector3 targetPosition = new Vector3(100, 0, 0);
public float speed = 10.0f;
public float threshold = 0.5f;
void Update () {
Vector3 direction = targetPosition - transform.position;
if(direction.magnitude > threshold){
direction.Normalize();
transform.position = transform.position + direction * speed * Time.deltaTime;
}else{
// Without this game object jumps around target and never settles
transform.position = targetPosition;
}
}
Or you can download for example DOTween package and just start the tween:
public Vector3 targetPosition = new Vector3(100, 0, 0);
public float tweenTime = 10.0f;
void Start () {
DOTween.Init(false, false, LogBehaviour.Default);
transform.DOMove(targetPosition, tweenTime);
}
Related
I'm new in Unity development. I have a ball with RigidBody 2D on it and i want it to rotate for 1 second. Does not matter the speed. The speed can be automatically.
I want just : at second 0 to be in initial position and at second 1 to be in final position. The rotation can be : 180, 360, 720.. etc degree.
I tried with angularVelocity but never stops. I tried with add torque but same. I don't know to handle it.
rb.angularVelocity = 180;
or
rb.AddTorque(90);
If you want to reach a precise rotation after a certain amount of time, it means your rotation speed will be computed automatically. To achieve something like this I'd recommend using a Coroutine :
public class TestScript : MonoBehaviour
{
public float targetAngle;
public float rotationDuration;
void Update()
{
//This is only to test the coroutine
if(Input.GetKeyDown(KeyCode.Space))
{
StartCoroutine(RotateBall(targetAngle, rotationDuration));
}
}
private IEnumerator RotateBall(float a_TargetAngle, float a_Duration)
{
Vector3 startLocalEulerAngles = GetComponent<RectTransform>().localEulerAngles;
Vector3 deltaLocalEulerAngles = new Vector3(0.0f, 0.0f, a_TargetAngle - startLocalEulerAngles.z);
float timer = 0.0f;
while(timer < a_Duration)
{
timer += Time.deltaTime;
GetComponent<RectTransform>().localEulerAngles = startLocalEulerAngles + deltaLocalEulerAngles * (timer / a_Duration);
yield return new WaitForEndOfFrame();
}
GetComponent<RectTransform>().localEulerAngles = startLocalEulerAngles + deltaLocalEulerAngles;
}
}
Ok, so I'm making this game where the user can drag a ball around the screen, but it's not supposed to leave the play area. I'm getting the following problem though, when I push it towards the colliders it bounces back, and if I push too hard it simply goes off screen (I need to make it do not go off screen. the user is free to drag it all over the place, but within the screen of course).
any tips on how I could solve this issue?
Here is the code for dragging which I'm using:
using UnityEngine;
using System.Collections;
public class CircleManager : MonoBehaviour {
private bool dragging = false;
private Vector3 screenPoint;
private Vector3 offset;
// Pressionando
void OnMouseDown()
{
dragging = true;
screenPoint = Camera.main.WorldToScreenPoint(gameObject.transform.position);
offset = gameObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z));
}
// Arrastando
void OnMouseDrag()
{
Vector3 cursorPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z);
Vector3 cursorPosition = Camera.main.ScreenToWorldPoint(cursorPoint) + offset;
//i tried with both below.
//transform.position = cursorPosition;
transform.GetComponent<Rigidbody2D>().MovePosition(cursorPosition);
}
// Soltando
void OnMouseUp()
{
dragging = false;
}
}
Thanks!
You could try to do something like,
if( transform.position.x > xMaxPos )
{
transform.position.x = new Vector3( xMaxPos, transform.position.y, transform.position.z );
}
You could set up for each min and max. Then when you create the xMaxPos variables, create them like:
[serializeField]
private float xMaxPos;
That way they will appear in the inspector and you can tweak their values as you please. You could also throw in an offset that's the width of the ball i.e.
transform.position.x = new Vector3( xMaxPos - transform.localscale.x/2, transform.position.y, transform.position.z );
Try using velocity
public class CircleManager : MonoBehaviour {
private bool dragging = false;
private Vector3 screenPoint;
private Vector3 offset;
public float speed = 5.0f;
// Pressionando
void OnMouseDown()
{
dragging = true;
Vector3 cursorPosition = Camera.main.ScreenToWorldPoint(ToDepth(Input.mousePosition, transform.position.z));
offset = gameObject.transform.position - cursorPosition;
}
// Arrastando
void OnMouseDrag()
{
Vector3 cursorPosition = Camera.main.ScreenToWorldPoint(ToDepth(Input.mousePosition, transform.position.z)) + offset;
Vector3 direction = (transform.position - cursorPosition).normalized;
transform.GetComponent<Rigidbody2D>().velocity = direction * speed * Time.deltaTime;
}
// Soltando
void OnMouseUp()
{
dragging = false;
}
Vector3 ToDepth(Vector3 value, float depth)
{
return new Vector3(value.x, value.y, depth);
}
}
Few things to note:
You don't have to write out gameObject.transform.position i see you did that a few times, as well as calling transform... directly. Its both the same thing, so you don't need the gameObject part.
Also your getting the screenPoint of the transform, then using the z value of that later on, which doesn't really make much sense to me.
Anyways, i don't see why this shouldn't work for you, i haven't tested it though.
I'm new to UnityScript and I have the following code that does a forward movement of a gameObject on "Z" axis, but needs some refinement. Let me explain.
The script runs when a GUI.Button is clicked. The gameObject starts moving...till infinity.
I have tried to make it move till a desired pos, (e.g. an empty gameObject pos) but didn't work at all.
How should I refine this code snippet to move the gameObject to a desired position on a first GUI.Button click and return to starting position on back click?
Furthermore, is it possible to have this movement made step by step on same GUI.Button clicks?
Here is the code snippet:
#pragma strict
// member variables (declared outside any function)
var startPos: Vector3;
var endPos : Vector3;
var cachedTransform : Transform;
private static var isforward = false;
// save pos before moving:
startPos = transform.position;
// make the gameObject transform, then restore the initial position when needed:
transform.position = startPos;
function Awake() {
startPos = transform.localPosition;
}
function Start() {
cachedTransform = transform;
startPos = cachedTransform.position;
}
function FixedUpdate() {
if(isforward){
var translation : float;
if (cachedTransform.position.x == endPos)
{
cachedTransform.position = startPos;
}
else
{
translation = Time.deltaTime * 2;
cachedTransform.Translate(0, 0, translation);
cachedTransform.Translate(Vector3.forward * translation);
}
}
}
static function doforward ()
{
isforward = !isforward;
}
Thank you all in advance for your answers.
You can easily move a game object if you attach a script to it, then (in JavaScript)
#pragma strict
var startPosition;
// Record the starting position when the scene loads
function Start () {
startPosition = gameObject.transform.position;
}
// Call this to move you object to wherever
function moveObject () {
var newPos = new Vector3 (10,20,0); //(where ever you need it to go)
gameObject.transform.position = newPos;
}
// Call this to move the object to starting position, using variable we made at start
function moveToStart () {
gameObject.transform.position = startPosition;
}
Then you just call those functions when you need to move the object around.
You might want to look into the Vector3.Lerp method. This takes two vectors (points) and a float as parameters, then gives you back a point that's a fraction of the way between them. So for example, Lerp(from, to, 0.3f) will give you a point 30% of the way between the two points. Then once you have this, all you need to do is set your object's transform.
I have a GameObject that I want to animate along a specific path/curve, but the animation should be controlled by mouse/touch position. So when I touch/click on the GameObject and move the finger/mouse on/near the path (or maybe its easier to just move down) the GameObject should follow its defined path.
I like iTween, but I think it is not possible to find a solution using it here, right?
edit: added image:
It's quite a simpler task than what you might think.
Basically it's a question of remapping a function (that takes the input as parameter) to another function (that express a position along a path).
There are several ways of doing that, depending on the precise effect you want to implement.
The most important choices you have to take are:
How the describe the path/curve
How to handle input
Example
For the path an easy and flexible way is to use some sort of spline curves, such as cubic Bézier curve. It's easy to implement and Unity3D provides built-in functions to draw them. Have a look at Handles.DrawBezier.
Basically a Bézier function takes as input a parameter t in the domain [0,1] and return as a result a point in the space (2D or 3D as you prefer). B(0) gives the point at the begin of the curve, B(1) the end point. (Side note: the function is not linear so in the general case incrementing at a constant rate t doesn't produce a movement at constant speed along the curve. This paper might be useful).
For what concern the input the simpler solution that comes up to my mind is the following:
Accumulate somewhere the vector describing the offset from the position when the touch started to the current touch position. (Here's how to handle touches, have a look at deltaPosition).
Something like:
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
offsetFromStartPos += Input.GetTouch(0).deltaPosition;
}
Let's say you want to swipe up/down your finger for moving forward/back an object along a path.Choose a "travel" distance (the domain of the input function) for your finger in order to complete the movement along the curve and normalize the offset using such distance in order to remap the input into the [0,1] domain.
float t = offsetFromStartPos.y / maxDistanceAlongYAxis;
Vector3 pos = CalculateBezier(t);
transform.position = pos;
It's just an hint to put you in the right direction.
I tried with keyboard and its working fine,
but not with mouse or touch
using System;
using UnityEngine;
public class Collector : MonoBehaviour
{
public Transform startPoint;
public Transform middlePoint;
public Transform endPoint;
public float curveSpeed = 0.5f;
//public float speed = 0f;
private int _direction = 1;
private bool _isObjectSelected;
private Vector3 _mouseLastPosition;
private float _journeyLength;
private Vector3 _offsetPos;
private float _currentTime = 0;
private void Start()
{
_journeyLength = Vector3.Distance(startPoint.position,
endPoint.position);
UpdateJourney(0);
}
private void OnMouseDown()
{
if (_isObjectSelected)
return;
_offsetPos = Vector3.zero;
_mouseLastPosition = Input.mousePosition;
_isObjectSelected = true;
}
private void OnMouseUp()
{
_isObjectSelected = false;
}
private void OnMouseExit()
{
_isObjectSelected = false;
}
private void OnMouseDrag()
{
if (_isObjectSelected)
{
Debug.LogError("Mouse drag");
Vector3 currentPosition = Input.mousePosition;
_offsetPos += currentPosition - _mouseLastPosition;
float distCovered = _offsetPos.y / _journeyLength;
UpdateJourney(distCovered);
_mouseLastPosition = currentPosition;
}
}
private void UpdateJourney(float time)
{
if (time < 0)
time = 0;
else if (time > 1)
time = 1;
_currentTime = time;
transform.position =
QuadraticCurve(startPoint.position,
middlePoint.position,
endPoint.position,
_currentTime);
transform.rotation = Quaternion.Euler(
new Vector3(0, 0,
QuadraticCurve(0, 45, 90, _currentTime)));
}
private void Update()
{
// moving on path using keyboard input
float direction = Input.GetAxisRaw("Horizontal");
if (Math.Abs(direction) > 0.1f)
{
_currentTime += Time.deltaTime * curveSpeed * direction;
UpdateJourney(_currentTime);
}
}
private static Vector3 Lerp(Vector3 start, Vector3 end, float time)
{
return start + (end - start) * time;
}
private static Vector3 QuadraticCurve(Vector3 start, Vector3 middle, Vector3 end, float time)
{
Vector3 point0 = Lerp(start, middle, time);
Vector3 point1 = Lerp(middle, end, time);
return Lerp(point0, point1, time);
}
private static float QuadraticCurve(float start, float middle, float end, float time)
{
float point0 = Mathf.Lerp(start, middle, time);
float point1 = Mathf.Lerp(middle, end, time);
return Mathf.Lerp(point0, point1, time);
}
}
This is a simplified code from what I'm trying to do:
var angle = 1.57;
if ( this.transform.rotation.y > angle ){
this.transform.rotation.y--;
} else if ( this.transform.rotation.y < angle ){
this.transform.rotation.y++;
}
I'm used to code in AS3, and if I do that in flash, it works perfectly, though in Unity3D it doesn't, and I'm having a hard time figuring out why, or how could I get that effect.
Can anybody help me? Thanks!
edit:
my object is a rigidbody car with 2 capsule colliders driving in a "bumpy" floor, and at some point he just loses direction precision, and I think its because of it's heirarchical rotation system.
(thanks to kay for the transform.eulerAngles tip)
transform.rotation retrieves a Quaternion. Try transform.rotation.eulerAngles.y instead.
Transform Rotation is used for setting an angle, not turning an object, so you would need to get the rotation, add your change, and then set the new rotation.
Try using transform.rotate instead.
Check the Unity3d scripting reference here:
http://unity3d.com/support/documentation/ScriptReference/Transform.Rotate.html
I see two problems so far. First the hierarchical rotation of Unity. Based on what you are trying to achieve you should manipulate either
transform.localEulerAngles
or
transform.eulerAngles
The second thing is, you can't modify the euler angles this way, as the Vectors are all passed by value:
transform.localEulerAngles.y--;
You have to do it this way:
Vector3 rotation = transform.localEulerAngles;
rotation.y--;
transform.localEulerAngles = rotation;
You need to create a new Quaternion Object
transform.rotation = Quaternion.Euler ( transform.rotation.x, transform.rotation.y++, transform.rotation.z );
You can also use transform.Rotate function.
The above suggestion to use transform.Rotate( ) is probably what you're going to need to do to actually make it rotate, BUT the variables of transform.Rotate( ) are velocity/speed rather than direction, so transform.Rotate( ) will have to use more than one axis if you want an angled rotation. Ex:
class Unity // Example is in C#
{
void Update( )
{
gameObject.transform.Rotate(0, 1, 0);
}
}
This will rotate the object around its y-axis at a speed of 1.
Let me know if this helps - and if it hinders I can explain it differently.
You should try multiplyng your rotation factor with Time.deltaTime
Hope that helps
Peace
Here is my script for GameObject rotation with touch
//
// RotateController.cs
//
// Created by Ramdhan Choudhary on 12/05/13.
//
using UnityEngine;
using System;
public class RotateController
{
private float RotationSpeed = 9.5f;
private const float mFingerDistanceEpsilon = 1.0f;
public float MinDist = 2.0f;
public float MaxDist = 50.0f;
private Transform mMoveObject = null;
private bool isEnabledMoving = false;
//************** Rotation Controller Constructor **************//
public RotateController (Transform goMove)
{
isEnabledMoving = true;
mMoveObject = goMove;
if (mMoveObject == null) {
Debug.LogWarning ("Error! Cannot find object!");
return;
}
}
//************** Handle Object Rotation **************//
public void Update ()
{
if (!isEnabledMoving && mMoveObject != null) {
return;
}
Vector3 camDir = Camera.main.transform.forward;
Vector3 camLeft = Vector3.Cross (camDir, Vector3.down);
// rotate
if (Input.touchCount == 1) {
mMoveObject.Rotate (camLeft, Input.touches [0].deltaPosition.y * RotationSpeed * Time.deltaTime, Space.World);
mMoveObject.Rotate (Vector3.down, Input.touches [0].deltaPosition.x * RotationSpeed * Time.deltaTime, Space.Self);
}
}
}