Moving the object up and down - a loop - unity3d

am very much new in Unity3D. Tried to watch some youtube video tutorials. But am having a doubt. I have an object which is placed at the top-right position using the following code at game startup:
myObject.position = mainCam.ScreenToWorldPoint(new Vector3(Screen.width - 75, Screen.height ,0f));
Based on the docs, the (0,0) position in camera viewport is on the left bottom corner and the (1,1) position is on top right corner. That's why I used the following values in the above line:
x = Screen.width - 75; // to position 75px from right side
y = Screen.height; // at top on y-axis
z = 0; // not needed
What I to do is, myObject should move up and down continuously. ie, it should move from top to bottom and vice versa, as a loop. Something like this(the ball moving from top to bottom and viceversa):
While looking for solution, I found an answer. And was trying to tweak it. The object is moving, but it is not moving correctly. It's going sideways! The following tweaked script is used in myObject:
#pragma strict
var mainCam : Camera;
function Start () {
var pointA : Vector3 = transform.position;
var pointB : Vector3 = mainCam.ScreenToWorldPoint(new Vector3(transform.position.x, transform.localScale.y/2 ,0f));
while (true) {
yield MoveObject(transform, pointA, pointB, 3.0);
yield MoveObject(transform, pointB, pointA, 3.0);
}
}
function MoveObject (thisTransform : Transform, startPos : Vector3, endPos : Vector3, time : float) {
var i = 0.0;
var rate = 1.0/time;
while (i < 1.0) {
i += Time.deltaTime * rate;
thisTransform.position = Vector3.Lerp(startPos, endPos, i);
yield;
}
}
But the movement is towards bottom left corner! I have been trying to figure it out for hours now! Any guess on where it went wrong? Or if you have better solutions, I would really appreciate.

Gonna take a stab at posting this as an answer (heaps easier than doing multiple lines in comments anyway).
So, we grab the top-right and bottom-right corners of the screen in pixel dimensions (using 75 as a margin):
var screenPointA:Vector3 = Vector3(Screen.width-75, Screen.height-75, 0);
var screenPointB:Vector3 = Vector3(Screen.width-75, 75, 0);
Then we get the world positions that the object will loop back and forth between:
var pointA:Vector3 = mainCam.ScreenToWorldPoint(screenPointA);
var pointB:Vector3 = mainCam.ScreenToWorldPoint(screenPointB);
If pointA.z or pointB.z are incorrect, you can change them after if required.
(happy to continue commenting/editing if needed to help you solve this!)

Related

Math: How to spin a wheel by drag&drop (Canvas, 2D)?

I'm struggling with probably simple math to spin/rotate a wheel using drag&drop.
There is a Radial Layout in a Canvas (Unity UI) and it can already be rotated by setting a property called StartAngle that is in a range from 0-360. In this Radial there are items, so the StartAngle is for the first item and places all the child elements around the layout radius.
I want to implement drag & drop for the items so that you can drag a child around and the Radial will spin accordingly (infinitely).
Right now, I have this as a starting point:
public void OnDrag(PointerEventData eventData)
{
var delta = eventData.delta.x * Time.deltaTime;
var newAngle = radialLayout.StartAngle + delta;
if (newAngle >= 360)
newAngle = newAngle - 360;
else if (newAngle < 0)
newAngle = Mathf.Abs(360 - newAngle);
radialLayout.StartAngle = newAngle;
}
It kind of works but doesn't feel very smooth. This is for mobile/touch, so I want both the X and Y delta of the drag operation to be taken into account. Apparently, the y delta is not considered in my example and I have no idea how to incorporate this correctly. The user might do a linear drag & drop on either axis or he/she might also do like a circular drag movement.
So how can I map mouse movement to a rotation angle from 0-360 so that it feels good?
Edit: Thanks for the help, I did it like this now:
public void OnDrag(PointerEventData eventData)
{
// Note the "Head-Minus-Tale rule for Vector subtraction, see http://www.maths.usyd.edu.au/u/MOW/vectors/vectors-3/v-3-7.html
// vSourceToDestination = vDestination - vSource;
// First, we draw a vector from the center point of the radial to the point where we started dragging
var from = dragStartPoint - (Vector2)radialLayout.transform.position;
// Next, we draw a vector from the center point of the radial to the point we are currently dragging on
var to = eventData.position - (Vector2)radialLayout.transform.position;
// Now, we calculate the angle between these two:
var dragAngle = Vector2.SignedAngle(from, to);
// Lerping makes movement fast at the beginning slow at the end
var lerpedAngle = Mathf.Round(Mathf.LerpAngle(radialLayout.StartAngle, dragAngle, 0.5f));
radialLayout.StartAngle = lerpedAngle;
}
I don't know all of your code and types but I would have an idea. I can't test this right now and can not garant that it even works like this but I hope the idea gets clear.
I would probably rather use something like
// This is the vector from the center of the object to the mouse/touch position
// (in screen pixel space)
var touchDirection = eventData.position - Camera.main.WorldToScreenPoint(transform.position);
// angle between the Up (Y) axis and this touchDirection
// for the angle the length of the up vector doesn't matter so there is
// no need to convert it to pixel space
var targetAngle = Vector2.SignedAngle(Vector2.up, touchDirection);
// since the returned angle might be negative wrap it to get values 0-360
if(targetAngle < 0) targetAngle += 360;
// Now either simply use Lerp
// this would simply interpolate each frame to the middle of both values
// the result is a fast movement at the beginning and a very slow at the end
radialLayout.StartAngle = Mathf.Lerp(radialLayout.StartAngle, targetAngle, 0.5f);
// or maybe use a fixed speed like 30°/second
var difference = targetAngle - radialLayout.StartAngle;
radialLayout.StartAngle += Mathf.Sign(difference) * Mathf.Min(30f * Time.deltaTime, Mathf.Abs(difference));
Typed on smartphone but I hope the idea gets clear

find the heading angle between 2 objects taking into account the forward angle of the initial object

Ok, so, i've been stuck on this for ages. Im working on an AI that will navigate a tank to a waypoint, defined as a Vector3. the position of the tank is also defines as a Vector3, both these have their Y position set to 0, as to ignore terrain elevation, the current rotation of the tank is also a Vector3, though only the Y rotation is needed, as i'm effectively projecting the 3d position onto a 2d navigational grid.
The AI passes anywhere between -1 and 1 into the control for the tank, which then handles the physics operations. so, i need to somehow calculate the angle, positive or negative in relation to the current heading angle of the tank to the position of the waypoint, then send the rotation value to the controls. At the moment I simply cant get it working, I feel like iv'e pretty much tried everything.
This is my code currently, it doesn't work, at all, and is about the 20th revision:
void driveToTarget()
{
Vector3 target0 = driveTarget;
target0.y = 0;
GameObject current0Obj = new GameObject();
Vector3 current0 = this.transform.position;
current0.y = 0;
print(current0);
print(target0);
Vector3 current0Angle = this.transform.eulerAngles;
print(current0Angle.y);
current0Angle.x = 0;
current0Angle.z = 0;
Vector3 heading = target0 - current0;
Quaternion headingAngle = Quaternion.LookRotation(heading);
print("headingAngle" + headingAngle);
print("heading direction, allegidly: " + Quaternion.Euler(heading).ToEulerAngles());
Quaternion distanceToGo = Quaternion.Lerp(Quaternion.Euler(current0Angle), headingAngle, 0.01f);
float angle = Vector3.SignedAngle(current0, target0, Vector3.up);
float difference = Mathf.Abs(angle - current0Angle.y);
print("heading angle " + angle);
if (current0 != driveTarget)
{
steeringVal = Mathf.Abs(1.5f-(1f/Mathf.Abs(distanceToGo.y))) * -Mathf.Sign(distanceToGo.y); ;
throttleVal = 0f;
} else
{
throttleVal = 0;
}
}
--EDIT--
So, I've partially solved it, and now encountered another problem, I've managded to get the tank to detect the angle between itself and the waypoint, BUT, rather than orienting forward towards the waypoint, the right side of the tank orients towards it, so it orbits the waypoint. I actually know why this is, becasue the forward vector of the tank is technically the right vector because of unity's stupid axis ruining my blender import, anyway, heres the updated code:
void driveToTarget()
{
Vector3 target0 = driveTarget;
target0.y = 0;
Vector3 current0 = this.transform.position;
current0.y = 0;
print("Current: " + current0);
print("Target: " + target0);
Vector3 current0Angle = this.transform.rotation.eulerAngles;
print("Curret rotation:" + current0Angle.y);
current0Angle.x = 0;
current0Angle.z = 0;
Vector3 heading = target0 - current0;
Quaternion headingAngle = Quaternion.LookRotation(heading);
print("heading angle: " + headingAngle.ToEuler());
float distanceToGo = (current0Angle.y) - headingAngle.eulerAngles.y;
print("DistanceToGo: " + distanceToGo);
if (current0 != driveTarget)
{
steeringVal = 1 * -Mathf.Sign(distanceToGo);
throttleVal = 0f;
} else
{
throttleVal = 0;
}
Debug.DrawRay(current0, heading, Color.red, 1);
Debug.DrawRay(current0, this.transform.up, Color.red, 1);
}
I'm not sure exactly how your code is setup or how the steering works. You may want to look into using the Unity NavMeshAgent to simplify this.
Regardless here is some code I wrote up that takes a destination and rotates an object towards it. All you'd have to do from there is move the object forwards.
Vector3 nextDestination = //destination;
Vector3 direction = nextDestination - transform.position;
direction = new Vector3(direction.x, 0, direction.z);
var newRotation = Quaternion.LookRotation(direction);
var finalRotation = Quaternion.Slerp(transform.rotation, newRotation, Time.deltaTime); //smoothes out rotation
transform.rotation = finalRotation;
Sorry if this isn't what you needed. Have you been able to figure out which part of the code is behaving unexpectedly from your print statements?

Unity C#: Line renderer from Gameobject (3D) to Canvas (Screen Space - Camera) [duplicate]

I have an image UI in a canvas with Screen Space - Camera render mode. What I like to do is move my LineRenderer to the image vertical position by looping through all the LineRenderer positions and changing its y axis. My problem is I cant get the correct position of the image that the LineRenderer can understand. I've tried using ViewportToWorldPoint and ScreenToWorldPoint but its not the same position.
Vector3 val = Camera.main.ViewportToWorldPoint(new Vector3(image.transform.position.x, image.transform.position.y, Camera.main.nearClipPlane));
for (int i = 0; i < newListOfPoints.Count; i++)
{
line.SetPosition(i, new Vector3(newListOfPoints[i].x, val.y, newListOfPoints[i].z));
}
Screenshot result using Vector3 val = Camera.main.ScreenToWorldPoint(new Vector3(image.transform.localPosition.x, image.transform.localPosition.y, -10));
The green LineRenderer is the result of changing the y position. It should be at the bottom of the square image.
Wow, this was annoying and complicated.
Here's the code I ended up with. The code in your question is the bottom half of the Update() function. The only thing I changed is what was passed into the ScreenToWorldPoint() method. That value is calculated in the upper half of the Update() function.
The RectTransformToScreenSpace() function was adapted from this Unity Answer post1 about getting the screen space coordinates of a RectTransform (which is exactly what we want in order to convert from screen space coordinates back into world space!) The only difference is that I was getting inverse Y values, so I changed from Screen.height - transform.position.y to just transform.position.y which did the trick perfectly.
After that it was just a matter of grabbing that rectangle's lower left corner, making it a Vector3 instead of a Vector2, and passing it back into ScreenToWorldPoint(). The only trick there was because of the perspective camera, I needed to know how far away the line was from the camera originally in order to maintain that same distance (otherwise the line moves up and down the screen faster than the image). For an orthographic camera, this value can be anything.
void Update () {
//the new bits:
float dist = (Camera.main.transform.position - newListOfPoints[0]).magnitude;
Rect r = RectTransformToScreenSpace((RectTransform)image.transform);
Vector3 v3 = new Vector3(r.xMin, r.yMin, dist);
//more or less original code:
Vector3 val = Camera.main.ScreenToWorldPoint(v3);
for(int i = 0; i < newListOfPoints.Count; i++) {
line.SetPosition(i, new Vector3(newListOfPoints[i].x, val.y, newListOfPoints[i].z));
}
}
//helper function:
public static Rect RectTransformToScreenSpace(RectTransform transform) {
Vector2 size = Vector2.Scale(transform.rect.size, transform.lossyScale);
Rect rect = new Rect(transform.position.x, 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;
}
1And finding that post from a generalized search on "how do I get the screen coordinates of a UI object" was not easy. A bunch of other posts came up and had some code, but none of it did what I wanted (including converting screen space coordinates back into world space coordinates of the UI object which was stupid easy and not reversibe, thanks RectTransformUtility!)

Unity make a missile follow a given trajectory

Im making a game where you can fire missiles at tanks. I want the missile to follow this trajectory:
https://imgur.com/a/bRQ44zq
I have tried a few things but no luck. Does anyone has an idea on how I could achieve this trajectory?
Thanks in advance for any help.
You should search for: ballistics, cannon, ballistics physics, ball parabola, etc.
Here is an example of of shooting ball at transform:
https://answers.unity.com/questions/148399/shooting-a-cannonball.html
I don't have Unity open right now, so I can't give you full code. By the way, try to change the code below for your own use and let me know in comments.
function BallisticVel(target: Transform, angle: float): Vector3 {
var dir = target.position - transform.position; // get target direction
var h = dir.y; // get height difference
dir.y = 0; // retain only the horizontal direction
var dist = dir.magnitude ; // get horizontal distance
var a = angle * Mathf.Deg2Rad; // convert angle to radians
dir.y = dist * Mathf.Tan(a); // set dir to the elevation angle
dist += h / Mathf.Tan(a); // correct for small height differences
// calculate the velocity magnitude
var vel = Mathf.Sqrt(dist * Physics.gravity.magnitude / Mathf.Sin(2 * a));
return vel * dir.normalized;
}
var myTarget: Transform; // drag the target here
var cannonball: GameObject; // drag the cannonball prefab here
var shootAngle: float = 30; // elevation angle
function Update(){
if (Input.GetKeyDown("b")){ // press b to shoot
var ball: GameObject = Instantiate(cannonball, transform.position, Quaternion.identity);
ball.rigidbody.velocity = BallisticVel(myTarget, shootAngle);
Destroy(ball, 10);
}
}

Unity, Rigidbody Character keeps falling over

I have a problem with trying to keep my character from rolling over, yet allow it to pitch and yaw. The suggestions I have seen have been to lock different axis, but no matter if I lock the x, y, or z axis I always run into a situation where the character can fall over. The best I can get is to lock both the y and z axis. This allows the character to change pitch to conform to the terrain. But, again, if I turn left or right while going up or down a hill and I can roll the character over.
Here is my current code for movement (in case it helps). I have no other code and my rigid body is all defaults. I have a mesh collier for the character set to convex but defaults otherwise.
Any suggestions on how to make this work?
Here's a live demo of y and z axis being locked. Just waltz up the hill and hang a left or right and you'll fall over. (ASWD controls)
https://dl.dropboxusercontent.com/u/27946381/Builds/builds.html
Thanks so much!
var speed = 3.0;
var rotateSpeed = 3.0;
function FixedUpdate() {
var hAxis = 0;
var vAxis = 0;
if( Input.GetAxis("Horizontal") > 0 ) { hAxis = 1.0; } else if( Input.GetAxis("Horizontal") < 0 ) { hAxis = -1.0; } else { hAxis = 0.0; }
if( Input.GetAxis("Vertical") > 0 ) { vAxis = 1.0; } else if( Input.GetAxis("Vertical") < 0 ) { vAxis = -1.0; } else { vAxis = 0.0; }
var rigidBody: Rigidbody = GetComponent(Rigidbody);
// Rotate around y axis
// transform.Rotate(0, hAxis * rotateSpeed, 0);
var deltaRotation : Quaternion = Quaternion.Euler(0, hAxis * rotateSpeed, 0);
rigidbody.MoveRotation(rigidbody.rotation * deltaRotation);
// Move forward / backward
var forward = transform.TransformDirection(Vector3.forward);
var currSpeed = speed * vAxis;
rigidBody.MovePosition( rigidBody.position + (forward * currSpeed) );
var animatorController: Animator = GetComponent(Animator);
animatorController.SetFloat("Speed", currSpeed);
}
well maybe you should check your rigidbody properties called gravity scale.. set it to 0 and you will never fall
I believe your problem is in these MovePosition and MoveRotation. Take a look into scripting reference - these methods basically ignores collision until body is teleported at the specified pose. I.e. you may place the body into some kind of irresolvable situation, when physics engice unable to find appropriate forces to push the body away from another collider, and therefore the body will fall through. In this case it is better to use AddForce and AddTorque.
Also, you can use CharacterController instead of RigidBody. Though it cannot be rotated at all, there are fine methods for kinematic motion with precise collision detection. And you can attach another body to the character controller and rotate it as you wish.
Changing code will change nothing.
Try changing the hitbox of the player to a big cube
(Better) Try to look into the rigidbody properties, as far as I remember I had the same problem and fixed it that way, it might help