How to make animation position start from last position - unity3d

How to implement an animation in Unity relative to the last position. Normally when an animation is implemented in Unity each loop starts from the same position. I want to implement an animation relative to the last position of the animated object to avoid using forces or math calculations.

How I figured it out:
Unity Animation relative to last position without looping
This code solves the problem regarding animations based on last relative position. In this example, each time we press Fire1 a box will be animated to move from X = 0 to X = 10 Using the animation will help us to provide richer transitions and smooth movements based on curves without the problem of looping.
The idea is to have the animated object inside an empty parent so the animation of the object will be based into local position.
When the animation is finished we update the object and its parent location to match in the last position.
If you have any doubts please ask.
#pragma strict
/**
* Animation in Unity Relative to last position without looping
* #autor Knskank3
* http://stackoverflow.com/users/1287772/knskan3
* 04/09/2014
**/
/*
This code solves the problem regarding animations based on last relative ImagePosition
In this example, each time we press Fire1 a box will be animated to move from X = 0 to X = 10
Using the animation will help us to provide richer transitions and smooth movements based on curves
without the problem of looping
*/
// This var will determine if the animation is started
public var animation_started : boolean = false;
// This var will determine if the animation is finished
public var animation_finished : boolean = true;
function Update () {
// if user triggers Fire1
if( Input.GetButtonUp('Fire1')){
// initialize the flags
animation_started = true;
animation_finished = false;
// Start the animation
// this animation moves the box from local X = 0 to X = 10 using a curve to deaccelerate
animation.Play("boxanim");
}
}
/* This function is trigger at the end of the animation */
public function animationFinished() : void {
animation_finished = true;
}
/*
At the end of the frame if the animation is finished
we update the position of the parent to the last position of the child
and set the position of the child to zero inside the parent.
*/
function LateUpdate () {
// if the animation is finished and it was started
if(animation_finished && animation_started) {
// set the flag
animation_started = false;
// update the parent position
transform.parent.position = transform.position;
// update the box position to zero inside the parent
transform.localPosition = Vector3.zero;
}
}

Related

Distance moved by XR-controller in Unity

I have been making a script in Unity that measures how far a player has moved in the real world using XRNodes like this for example with the right hand:
InputTracking.GetLocalPosition(XRNode.RightHand)
at the start of the movement and then comparing it to the end position
Now I would like to get the distance moved, even if the player moved around in a circle.
Is the a method to do this with XRNodes? Measuring total distance moved during play?
Yes, well, you could just simply sum it up every frame like
// Stores the overall moved distance
private float totalMovedDistance;
// flag to start and stop tracking
// Could also use a Coroutine if that fits you better
private bool track;
// Store position of last frame
private Vector3 lastPos;
public void BeginTrack()
{
// reset total value
totalMovedDistance = 0;
// store first position
lastPos = InputTracking.GetLocalPosition(XRNode.RightHand);
// start tracking
track = true;
}
public void EndTrack()
{
// stop tracking
track = false;
// whatever you want to do with the total distance now
Debug.Log($"Total moved distance in local space: {totalMovedDistance}", this);
}
private void Update()
{
// If not tracking do nothing
if(!track) return;
// get current controller position
var currentPos = InputTracking.GetLocalPosition(XRNode.RightHand);
// Get distance moved since last frame
var thisFrameDistance = Vector3.Distance(currentPos, lastPos);
// sum it up to the total value
totalMovedDistance += thisFrameDistance;
// update the last position
lastPos = currentPos;
}

Get position of object in Grid Layout

How can I get the actual position of an object in a grid layout? In my current iteration symbolPosition keeps returning 0,0,0.
public void OnPointerClick (PointerEventData eventData)
{
// Instantiate an object on click and parent to grid
symbolCharacter = Instantiate(Resources.Load ("Prefabs/Symbols/SymbolImage1")) as GameObject;
symbolCharacter.transform.SetParent(GameObject.FindGameObjectWithTag("MessagePanel").transform);
// Set scale of all objects added
symbolCharacter.transform.localScale = symbolScale;
// Find position of objects in grid
symbolPosition = symbolCharacter.transform.position;
Debug.Log(symbolPosition);
}
The position value wont be updated until the next frame. In order to allow you to make a lot of changes without each one of them causing an entire recalculation of those elements it stores the items that need to be calculated and then updates them at the beginning of the next frame.
so an option is to use a Coroutine to wait a frame and then get the position
public void OnPointerClick (PointerEventData eventData)
{
// Instantiate an object on click and parent to grid
symbolCharacter = Instantiate(Resources.Load ("Prefabs/Symbols/SymbolImage1")) as GameObject;
symbolCharacter.transform.SetParent(GameObject.FindGameObjectWithTag("MessagePanel").transform);
// Set scale of all objects added
symbolCharacter.transform.localScale = symbolScale;
StartCoroutine(CoWaitForPosition());
}
IEnumerator CoWaitForPosition()
{
yield return new WaitForEndOfFrame();
// Find position of objects in grid
symbolPosition = symbolCharacter.transform.position;
Debug.Log(symbolPosition);
}
This may not have been in the API when this question was asked/answered several years ago, but this appears to work to force the GridLayoutGroup to place child objects on the frame in which child objects are added, thus removing then need for a coroutine.
for(int i = 0; i < 25; i++){
GameObject gridCell = Instantiate(_gridCellPrefab);
gridCell.transform.SetParent(_gridLayoutTransform,false);
}
_gridLayoutGroup.CalculateLayoutInputHorizontal();
_gridLayoutGroup.CalculateLayoutInputVertical();
_gridLayoutGroup.SetLayoutHorizontal();
_gridLayoutGroup.SetLayoutVertical();
From here, you can get the positions of the 'gridCells' same frame.
There is another function, which seems like it should fulfill this purpose, but it isn't working for me. The API is pretty quiet on what exactly is going on internally:
LayoutRebuilder.ForceRebuildLayoutImmediate(_gridLayoutTransform);

In Unity3d using the FPS Controller, how can I keep a constant player speed when auto-walk forward using transform.forward?

Using Unity3d First Person Controller, I want the player to move forward automatically in the direction the camera is looking at. It should behave the same as using the arrow keys, except I keep the arrow up key "pressed". I have this working in the script below, however the player slows down as he rotates the first-person camera away from the 0 degrees on the y-axis. When looking towards the 0 degrees on the y-axis, player speed is normal again.
How can I modify the script below so that the player always moves at a constant speed, no matter the camera rotation?
I set this script on the First Person Controller parent node:
public var head : GameObject;
private var motor : CharacterMotor;
// Use this for initialization
function Awake () {
motor = GetComponent(CharacterMotor);
}
// Update is called once per frame
function Update () {
// Retrieve a forward direction based on camera rotation
var directionVector = transform.forward;
directionVector.y = 0;
directionVector.Normalize();
// Apply the direction to the CharacterMotor
motor.inputMoveDirection = transform.rotation * directionVector;
motor.inputJump = Input.GetButton("Jump");
}
// Require a character controller to be attached to the same game object
#script RequireComponent (CharacterMotor)
#script AddComponentMenu ("Character/FPS Input Controller")
Multiply your movement for Time.deltaTime This time is the time between frames.
Example copy from http://docs.unity3d.com/ScriptReference/Time-deltaTime.html
function Update () {
// Move the object 10 meters per second!
var translation : float = Time.deltaTime * 10;
transform.Translate (0, 0, translation);
}

Stage scaling affecting AS3

I have some code that controls a serious of images to produce and 360 spin when dragging mouseX axis. This all worked fine with the code I have used.
I have since had to design for different platform and enlarge the size of the stage i did this by scale to stage check box in the document settings.
While the mouse down is in action the spin works fine dragging through the images as intended but when you you release and start to drag again it doesn't remember the last frame and jumps to another frame before dragging fine again? Why is it jumping like this when all I have done is change the scale of everything?
please see code use to
//ROTATION OF CONTROL BODY X
spinX_mc.stop();
var spinX_mc:MovieClip;
var offsetFrame:int = spinX_mc.currentFrame;
var offsetX:Number = 0;
var percent:Number = 0;
//Listeners
spinX_mc.addEventListener(MouseEvent.MOUSE_DOWN, startDragging);
spinX_mc.addEventListener(MouseEvent.MOUSE_UP, stopDragging);
function startDragging(e:MouseEvent):void
{
// start listening for mouse movement
spinX_mc.addEventListener(MouseEvent.MOUSE_MOVE,drag);
offsetX = stage.mouseX;
}
function stopDragging(e:MouseEvent):void
{
("stopDrag")
// STOP listening for mouse movement
spinX_mc.removeEventListener(MouseEvent.MOUSE_MOVE,drag);
// save the current frame number;
offsetFrame = spinX_mc.currentFrame;
removeEventListener(MouseEvent.MOUSE_DOWN, startDragging);
}
// this function is called continuously while the mouse is being dragged
function drag(e:MouseEvent):void
{
trace ("Drag")
// work out how far the mouse has been dragged, relative to the width of the spinX_mc
// value between -1 and +1
percent = (mouseX - offsetX) / spinX_mc.width;
// trace(percent);
// work out which frame to go to. offsetFrame is the frame we started from
var frame:int = Math.round(percent * spinX_mc.totalFrames) + offsetFrame;
// reset when hitting the END of the spinX_mc timeline
while (frame > spinX_mc.totalFrames)
{
frame -= spinX_mc.totalFrames;
}
// reset when hitting the START of the spinX_mc timeline
while (frame <= 0)
{
frame += spinX_mc.totalFrames;
}
// go to the correct frame
spinX_mc.gotoAndStop(frame);
}
By changing
spinX_mc.addEventListener(MouseEvent.MOUSE_MOVE,drag);
offsetX = stage.mouseX;
to
spinX_mc.addEventListener(MouseEvent.MOUSE_MOVE,drag);
offsetX = mouseX;
I seem to of solved the problem and everything runs smoothly again.

MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it (ERROR)

I have a problem that iv been trying to figure out for a couple of says and i cant seem to pin point the cause of it! I have created a first person shooter that consists of a few enemies on a small map. I have two scenes (the main menu and the game level). When my player dies it is takes to the main menu from which you can choose to play the game again. This then reloads the level again. The first time the game is run it runs without any problems. However when i doe and press the play game button again it returns to me a message which states the following "MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it." from the code below I can only see two types which are of GameObject. I have tried to remove the muzzleFlash to see if that is the issue however it makes no difference. I have unticked all the static boxes as i read that this may be the cause of the problem but this did not resolve the problem. this script below is attached to an enemy, I have a PlayerShot script attached to the FPS. Please could someone help?
// speed of the AI player
public var speed:int = 5;
// speed the ai player rotates by
public var rotationSpeed:int = 3;
// the waypoints
public var waypoints:Transform[];
// current waypoint id
private var waypointId:int = 0;
// the player
public var player:GameObject;
// firing toggle
private var firing:boolean = false;
// the Mesh Renderer of the Muzzle Flash GameObject
private var muzzleFlashAgent:GameObject;
/**
Start
*/
function Start()
{
// retrieve the player
player = GameObject.Find("First Person Controller");
// retrieve the muzzle flash
muzzleFlashAgent = GameObject.Find("muzzleFlashAgent");
// disable the muzzle flash renderer
muzzleFlashAgent.active = false;
}
/**
Patrol around the waypoints
*/
function Patrol()
{
// if no waypoints have been assigned
if (waypoints.Length == 0)
{
print("You need to assign some waypoints within the Inspector");
return;
}
// if distance to waypoint is less than 2 metres then start heading toward next waypoint
if (Vector3.Distance(waypoints[waypointId].position, transform.position) < 2)
{
// increase waypoint id
waypointId++;
// make sure new waypointId isn't greater than number of waypoints
// if it is then set waypointId to 0 to head towards first waypoint again
if (waypointId >= waypoints.Length) waypointId = 0;
}
// move towards the current waypointId's position
MoveTowards(waypoints[waypointId].position);
}
/**
Move towards the targetPosition
*/
function MoveTowards(targetPosition:Vector3)
{
// calculate the direction
var direction:Vector3 = targetPosition - transform.position;
// rotate over time to face the target rotation - Quaternion.LookRotation(direction)
transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(direction), rotationSpeed * Time.deltaTime);
// set the x and z axis of rotation to 0 so the soldier stands upright (otherwise equals REALLY bad leaning)
transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0);
// use the CharacterController Component's SimpleMove(...) function
// multiply the soldiers forward vector by the speed to move the AI
GetComponent (CharacterController).SimpleMove(transform.forward * speed);
// play the walking animation
animation.Play("walk");
}
/**
Update
*/
function Update()
{
// calculate the distance to the player
var distanceToPlayer:int = Vector3.Distance(transform.position, player.transform.position);
// calculate vector direction to the player
var directionToPlayer:Vector3 = transform.position - player.transform.position;
// calculate the angle between AI forward vector and direction toward player
// we use Mathf.Abs to store the absolute value (i.e. always positive)
var angle:int = Mathf.Abs(Vector3.Angle(transform.forward, directionToPlayer));
// if player is within 30m and angle is greater than 130 (IN FRONT) then begin chasing the player
if (distanceToPlayer < 30 && angle > 130)
{
// move towards the players position
MoveTowards(player.transform.position);
// if not firing then start firing!
if (!firing) Fire();
}
// if player is within 5m and BEHIND then begin chasing
else if (distanceToPlayer < 5 && angle < 130)
{
// move towards the players position
MoveTowards(player.transform.position);
// if not firing then start firing!
if (!firing) Fire();
}
else
{
// patrol
Patrol();
// stop firing
firing = false;
}
}
/**
Fire at the player
*/
function Fire()
{
// toggle firing on
firing = true;
// check if still firing
while (firing)
{
// hit variable for RayCasting
var hit:RaycastHit;
// range of weapon
var range:int = 30;
// fire the ray from our position of our muzzle flash, forwards "range" metres and store whatever is detected in the variable "hit"
if (Physics.Raycast(muzzleFlashAgent.transform.position, transform.forward, hit, range))
{
// draw a line in the scene so we can see what's going on
Debug.DrawLine (muzzleFlashAgent.transform.position, hit.point);
// if we hit the player
if (hit.transform.name == "First Person Controller")
{
// inform the player that they have been shot
player.GetComponent(PlayerShot).Shot();
// play gunshot sound
audio.PlayOneShot(audio.clip);
// show muzzle flash for X seconds
muzzleFlashAgent.active = true;
yield WaitForSeconds(0.05);
muzzleFlashAgent.active = false;
// wait a second or two before firing again
yield WaitForSeconds(Random.Range(1.0, 2.0));
}
}
// wait till next frame to test again
yield;
}
}
this is the PlayerShot which destroys the gameobject.
// the sound to play when the player is shot
public var shotSound:AudioClip;
// the number of lives
public var lives:int = 3;
/**
Player has been shot
*/
function Shot ()
{
// play the shot audio clip
audio.PlayOneShot(shotSound);
// reduce lives
lives--;
// reload the level if no lives left
if (lives == 0)
{
// destroy the crosshair
Destroy(GetComponent(CrossHair));
// add the camera fade (black by default)
iTween.CameraFadeAdd();
// fade the transparency to 1 over 1 second and reload scene once complete
iTween.CameraFadeTo(iTween.Hash("amount", 1, "time", 1, "oncomplete", "ReloadScene", "oncompletetarget", gameObject));
}
}
/**
Reload the scene
*/
function ReloadScene()
{
// reload scene
Application.LoadLevel("MainMenu");
}
The script attached to the enemy along with the BasicAI is the SoldierShot Script which destroys the gameobject. below is the script.
public var ragdoll:GameObject;
/**
Function called to kill the soldier
*/
function Shot()
{
// instantiate the ragdoll at this transform's position and rotation
Instantiate(ragdoll, transform.position, transform.rotation);
Destroy(GetComponent(BasicAI));
// destroy the animated soldier gameobject
Destroy(gameObject);
}
It seems that you keep a reference to the destroyed GameObject (or am I wrong?).
As opposed to what happens in common C# (and probably javascript) programs that when you have a reference to an object, it will never be garbage collected, in Unity if you destroy the object all your references to it will go to null.
Easy fix, you could delete the gameObject in the "Game Level" and instantiate your soldier on the fly with:
var instance : GameObject = Instantiate(Resources.Load("Soldier"));
You just need to make a Resources folder in your project folder and put the prefab for your solder into it.