Unity3d RotateTowards only on z axis - unity3d

I have GameObject that I need to rotate arouns Z axis. It needs to face the cursor all the time. But it rotates on all axis. Here is the code:
Vector3 mouseClickPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector3 dir = mouseClickPos - transform.position;
Vector3 h1dir = Vector3.RotateTowards(hand1.transform.forward, dir, 6.0f, 1.0f);
hand1.transform.rotation = Quaternion.LookRotation(h1dir);

Related

Why does Camera.transform.Rotate(X, Y, 0) change Z?

I would like to rotate a camera using a joystick.
The camera should rotate up and down and left and right, but it should not rotate around z.
I have tried the following lines:
float speed = 3.0f;
float yRotation = speed * fY;
float xRotation = speed * fX;
camera.transform.Rotate(-yRotation, xRotation, 0.0f);
It seems to work, but after a few joystick movements, I can see that the camera rotation's z-value has changed, and it looks like this:
Does anybody see an obvious mistake in my code, or is the problem located somewhere else?
Ok, here's how to do it, I have to use eulerAngles:
yaw += speedH * fX;
pitch -= speedV * fY;
pitch = Mathf.Clamp(pitch, -20, 30);
camera.transform.eulerAngles = new Vector3(pitch, yaw, 0.0f);

Rect relative to Render Texture

I am having a hard time figuring out how to find correct rect that represents a ui element area. I get the Ui element RectTransform. I tried to use it directly, using a function and RectTransformUtility, but nothing seems to wok.
Here is the code.
RenderTexture.active = scr;
//adjust rect position
//Rect rect = RectUtils.RectTransformToScreenSpace (rectTransform);
int width = System.Convert.ToInt32 (rect.width);
int height = System.Convert.ToInt32 (rect.height);
// Create a texture the size of the screen, RGB24 format
Texture2D tex = new Texture2D(width, height, TextureFormat.RGBA32, false);
RenderTexture.active = scr;
// Read screen contents into the texture
tex.ReadPixels(rect, 0, 0);
tex.Apply();
RenderTexture.active = null;
// Encode texture into PNG
byte[] bytes = tex.EncodeToPNG();
//todo destroy the texture
Object.Destroy (tex);
// For testing purposes, also write to a file in the project folder
File.WriteAllBytes(path, bytes);
I tried to create rect in different ways like:
Methood 1:
Vector2 size = Vector2.Scale(transform.rect.size, transform.lossyScale);
Rect rect = new Rect(transform.position.x, Screen.height - transform.position.y, size.x, size.y);
rect.x -= (transform.pivot.x * size.x);
rect.y -= ((1.0f - transform.pivot.y) * size.y);
return rect;
Method 2:
Vector2 temp = rectT.transform.position;
var startX = temp.x - width/2;
var startY = temp.y - height/2;
var tex = new Texture2D (width, height, TextureFormat.RGB24, false);
tex.ReadPixels (new Rect(startX, startY, width, height), 0, 0);
I am using Unity 5.5 Mac version.
when i pass to ReadPixels new Rect (0, 0, Screen.width, Screen.height) i see the whole RenderTexture in its defined dimensions 1920x1080
I want to use this as a baker of UI elements as I am having performance issue, and definitively no other solution to implement the required behavior.
I also struggled with this problem. Here's how I solved it.
First we need the position of RectTransform in screen and for this I used RectTransformUtility. Then since the rect x, y is the starting point at left bottom (note: in GUI x, y is at left top) we subtract respectively the half of width and height.
Vector2 rectPos = RectTransformUtility.WorldToScreenPoint (Camera.main, rectTransform.position);
float startX = rectPos.x - width / 2;
float startY = rectPos.y - height / 2;
Rect screenRect = new Rect (startX, startY, width, height);
Note: width height should be integer.
Edit: The above solution when we use Screen overlay and change resolution from standard to any other do not work. Even if I used the lossyscale I could not get consistent behavior.
One method of RecTransformUtility is really helpful for this situation (WorldToScreenPoint).
Vector3[] bounds = new Vector3[4];
rectTransform.GetWorldCorners (bounds);
Vector2 rectPos = RectTransformUtility.WorldToScreenPoint (camera, rectTransform.position);
Vector2 minPosition = RectTransformUtility.WorldToScreenPoint (camera, bounds[0]);
Vector2 maxPosition = RectTransformUtility.WorldToScreenPoint (camera, bounds[2]);
Vector2 size = maxPosition - minPosition;
float startX = rectPos.x - size.x / 2;
float startY = rectPos.y - size.y / 2;
return new Rect (startX, startY, size.x, size.y);

How to know end coordinates of animation in Unity?

I want to know coordinates of root bone in the end of animation in Unity. I tried to put unit with Animator controller programmaticaly to the scene, play animation and execute Update() several times. But coordinates are slightly different from the real.
Is there method to know accurate coordinates in the end of animation?
Upd. This code should work as it should, but it doesnt work accurately:
animator.transform.position = new Vector3(0, 0, 0);
animator.transform.rotation = Quaternion.Euler(0, 0, 0);
animator.Play(_hashName, 0, 0);
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
duration = stateInfo.length;
float t = 0;
float delta = 0.01f;
while (t < duration)
{
animator.Update(delta);
t += delta;
}
Vector3 endCoords = animator.transform.position;
Finally I found the brilliant answer on Unity3d forum.
animator.SetTarget(AvatarTarget.Root, 1.0f);
animator.Update(0);
Vector3 position = animator.targetPosition;
It works perfectly.

Unity track object rotation

I have several object rotating by itself in FixedUpdate().
Now I need to track rotation of one object, lets call it objX. Rotation goes only from 0 to 360 when I retrieve it. Is it possible to get rotation after 360 degrees?
For example when I use something like
float x = objX.transform.rotation.z;
variable x should be 560 degrees.
Is something like that possible?
Here is the way to track rotation.
Vector3 mouseClickPos;
float angle;
float lastAngle;
int fullRotations;
public float realAngle;
void FixedUpdate(){
mouseClickPos = Input.mousePosition;
Vector3 dir = mouseClickPos - Camera.main.WorldToScreenPoint(transform.position);
angle = Mathf.Atan2(dir.y,dir.x) * Mathf.Rad2Deg;
angle-=90;
if(lastAngle - angle > 270){
fullRotations ++;
}else if(angle - lastAngle > 270){
fullRotations --;
}
Debug.Log(360*fullRotations + angle);
Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.RotateTowards(transform.rotation, q, 6);
lastAngle = angle;
}

CCMoveTo doesn't get the updated player postition.....(iphone,cocos2d)

I'm adding an enemy like this:
-(void)addEnemy {
if ([spawnedEnemies count] < 25) {
CCSprite* sprite = [CCSprite spriteWithFile:#"white.png"];
float randomX = arc4random() % 480;
float randomY = arc4random() % 320;
sprite.position = ccp(randomX,randomY);
[spawnedEnemies addObject:sprite];
[self addChild:sprite];
[sprite runAction:[CCMoveTo actionWithDuration:5 position:player.position]];
} }
but if my player moves the sprite still moves to the last player position...
because of that i tried this in my tick:
-(void)tick:(ccTime)delta {
for (CCSprite *sp in spawnedEnemies) {
[sp stopAllActions];
[sp runAction:[CCMoveTo actionWithDuration:5
position:player.position]];
} }
but the enemies will only move if i stop moving (there just moving reallllllllyyyyyyyyy slow because every time i move it calls [sp stopAllActions]
What should I do now?
EDIT:*EDIT:*EDIT:*EDIT:*EDIT:*EDIT:*EDIT:*EDIT:*EDIT:
Now I'm doing this and the enemies are moving to the player even if the player is moving
but there's a problem: the nearer the enemy (is to the player) the slower they are moving...
How to solve this?
//function to apply a velocity to a position with delta
static CGPoint applyVelocity(CGPoint velocity, CGPoint position, float delta){
return CGPointMake(position.x + velocity.x * delta, position.y + velocity.y * delta);
}
-(void)tick:(ccTime)delta {
for (CCSprite *sp in spawnedEnemies) {
CGPoint m = ccpSub(player.position, sp.position);
sp.position = applyVelocity(m, sp.position, 1.0/60.0f);
}
}
I have four ideas:
Schedule a new update selector with a lower frequency and move the enemies in that method: [self schedule:#selector(moveEnemies) interval:0.1];
Only move the enemies when the player.position changes, maybe in your ccTouchesMoved-method.
Instead of using CCActions, set the position of the sprite directly, you need to do some vector-computations.
Use a physics-engine like Box2D (included in Cocos2D SDK). Then you can simply apply a force to each enemy to the direction of the player in each step.
EDIT:
In order to move the enemies with constant velocity, normalize the velocity vector m:
m = ccpMult(ccpNormalize(m), kSpeed);
kSpeed is a constant float value to adjust the speed.
Hope that helps...