Using Accelometer in unity,to move a gameobject with in the scene - accelerometer

I am placing 2 gameobjects at the left down corner and right upper of the screen. So I am using 2 gameobjects to form a border. And using boundaries class to create a bound such that it will stop the pivot point of my gameobject and I will move it inside bound using accelometer (It means I have 2 borders, outer border and inner border, I am drawing inner border using bounds with width and height calculating from formula I derived).
This is the code
void Start ()
{
valueOfHeight = (Screen.height * 110 )/ 320;
valueOfWidth = (Screen.width * 110 )/ 480;
Boundaries = new Bounds (new Vector3(Screen.width/2,Screen.height/2,0f),new Vector3(Screen.width - valueOfWidth,Screen.height - valueOfHeight,0f));
}
void Update ()
{
if(gameObject.transform.position.x > Cornerpoints [1].transform.position.x &&
gameObject.transform.position.x < Cornerpoints [3].transform.position.x&&
gameObject.transform.position.y > Cornerpoints [1].transform.position.y&&
gameObject.transform.position.y < Cornerpoints [3].transform.position.y)
{
Debug.Log("1");
gameObject.transform.position = Boundaries.ClosestPoint(gameObject.transform.position);
if (Boundaries.Contains (gameObject.transform.position))
{
Debug.Log("2");
direction = new Vector3 ((Input.acceleration.x), (Input.acceleration.y), 0);
}
But the problem here my gameobject is jerking on one side of the border (mostly left side).If the problem is occurs on all sides means,my code is wrong.But its only occuring only on left side of the border and i checked logs,(i kept logs 1 and 2),see when gameobejct comes to left side of the border,its 1 is only executing so that it is looking like jerking.But it is not happening on all sides.SO i want to know why? Thanks in advance.

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

Is there a better way to write this top down car mdoel

I Am writing a top down car drift game, where i want to make the car move in a circle and user controls the radius of the circle with the steering, basically straight steering is a straight line and turned left is a small circle to the left of the car which it will follow. as the car turns more (either side) i try to make the cars front turn more and more towards the centre, as if its drifting.
Am using unity and this is how i though i should design the model.
This is for a mobile game. so i have written a steering controller for the car, to control its left and right, the speed is constant.
There are two rigid bodies.
The front white coloured box and the big grey coloured box both are rigid bodies. connected with a hinge joint.
The front box on every frame rotate a certain amount of degrees on it own z axis and moves a little forward. Thus follows a circle shape. how much is rotates is determined my the steering.
I Can make both the bodies kinematic and make sure they follow a circle shape and move that way, but i also want appropriate behaviour during collisions, In the final plan there can be all kinds of collisions. So i made them kinematic and added velocities using add force methods. On it's own the front box is perfect, It rotates in circle as i change the steering the circle gets bigger everything is fine, But when i add the Other chassis box, the forces are all messed up. centrifugal forces, and the inertia messes everything.
Basically i need the car to drift is perfect circles and user should be able to control the radius of the circle. What is the best way to model this.
Here is the code for both the rigid bodies.
the front box code. This is just the fixed update method. Please ignore the controls related code. It'e unnecessary so i left it out.
{
//-------------------------
// I N I T.
//-------------------------
current_steering_angle = controls_i.ToSignedRotation(controls_i.getSteeringAngle());
current_steering_angle = (current_steering_angle < 0) ? (current_steering_angle + 90): current_steering_angle;
current_steering_angle -= 45;
//-------------------------
// S P E E D.
//-------------------------
current_speed = Utils.curve_map_linear(0, 45, min_speed, max_speed, Mathf.Abs(current_steering_angle), -1);
_rigid_body.AddRelativeForce(acceleration * Vector3.up);
velocity = transform.InverseTransformVector(_rigid_body.velocity);
if(velocity.y > current_speed){
velocity.y = current_speed;
}
// to prevent reverse movement due to centrifugal force.
velocity.x = 0;
//-------------------------
// R O T A T I O N.
//-------------------------
current_radius = Mathf.Sign(current_steering_angle) * Utils.exp_range_3(0, 45, min_radius, max_radius, Mathf.Abs(current_steering_angle), steering_tension, -1);
current_rot_rate = (velocity.y / (2 * Mathf.PI * current_radius)) * 360;
Vector3 angle = transform.localEulerAngles;
angle.z += (current_rot_rate * Time.fixedDeltaTime);
transform.localEulerAngles = angle;
//-------------------------
// A P P L Y.
//-------------------------
_rigid_body.velocity = transform.TransformVector(velocity);
}
The Utils.exp_linear and exp_range functions are just range to range mappers with some tension, to control the sensitivity of the steering on the controls.
Code for the chassis.
{
//-------------------------
// I N I T.
//-------------------------
current_steering_angle = controls_i.ToSignedRotation(controls_i.getSteeringAngle());
current_steering_angle = (current_steering_angle < 0) ? (current_steering_angle + 90): current_steering_angle;
current_steering_angle = current_steering_angle - 45;
current_steering_angle = ((float)((int)(current_steering_angle * Mathf.Pow(10, 5))))/Mathf.Pow(10,5);
//-------------------------
// R O T A T I O N.
//-------------------------
current_angle = front_transform.eulerAngles.z - _rigid_body.transform.eulerAngles.z;
current_angle = (Mathf.Abs(current_angle) > 180) ? ((Mathf.Abs(current_angle) - 360) * Mathf.Sign(current_angle)) : current_angle;
current_angle += Mathf.Sign(current_steering_angle) * Utils.curve_map_linear(0, 45, min_angle, max_angle, Mathf.Abs(current_steering_angle), 1);
_rigid_body.transform.RotateAround(front_transform.position, Vector3.forward, current_angle);
//-------------------------
// S P E E D.
//-------------------------
Vector3 velocity = _rigid_body.transform.InverseTransformVector(_rigid_body.velocity);
if (velocity.y < 0){
velocity.y = 0;
}
_rigid_body.velocity = _rigid_body.transform.TransformVector(velocity);
}
I would like to know how to actually implement something like this in unity. I am new to this unity stuff. I looked all over and there was a lot of stuff for 3d cars but not much on top down ones. Appreciate any kind of feedback.
Make it non kinematic, remove the rigidbody of the front tires and make the front tires a child of the chassis.
Handling position:
Make a method that looks at the car's current position, how much the player is turning, and returns the tangential velocity the car needs to go to drive in the appropriate circle:
Vector2 GetTangentialVelocity(...) { }
Then, find the difference between that velocity and the current velocity of the chassis:
Vector2 velDiff = GetTangentialVelocity(...) - chassis_rigidbody.velocity;
Then, apply that difference using AddForce with ForceType.VelocityChange:
chassis_rigidbody.AddForce(velDiff, ForceType.VelocityChange);
Handling rotation:
Move the center of mass forward. You can do this by making the rigidbody long and put the collider at the rear of the object, or by setting RigidBody.centerOfMass:
chassis_rigidbody.centerOfMass = Vector2.up * 0.5;
Make a function similar to GetTangentialVelocity that returns the desired angular velocity, find the difference from chassis_rigidbody.angularVelocity, then use AddTorque with ForceType.VelocityChange:
Vector2 angVelDiff = GetAngularVelocity(...) - chassis_rigidbody.angularVelocity;
chassis_rigidbody.AddTorque(angVelDiff , ForceType.VelocityChange);

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!)

Detect tap on a sphere in unity

I want to detect a tap on sphere. I have searched on google and many approaches like ontriggerenter() and using ray cast etc were found.
But what I want to get some values also that where user has touched on ball.
Like if the center of a sphere is x=0, y=0. then I should got positive x and y when user touch upper right corner of sphere.
It is not necessary to get exactly this value, Value can be anything but by these value I should be able to know that user has tapped on one of these 8 portions of ball.
upper right near center of circle
lower right near center of circle
upper left near center of circle
lower left near center of circle
upper right near corner of circle
lower right near corner of circle
upper left near corner of circle
lower left near corner of circle
You can use the methods you found, with raycasting you will get the exact position of the tap. Then you have to transform the centerpoint and the tap position of the sphere to screenspace coordinates. Then you can get the difference between those vectors to get the direction and distance from the center.
PS: Do circles have corners?
you need to have a GameObject with a Collider attatched to it which is set to "Is Trigger". And a script containing following code.
void OnMouseDown()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
//hits for sure, because we are in the click event
Physics.Raycast(ray, out hit);
Vector3 hitOnScreen = Camera.main.WorldToScreenPoint(hit.point);
Vector3 centerOnScreen = Camera.main.WorldToScreenPoint(transform.position);
Vector3 offset = hitOnScreen - centerOnScreen;
if(offset.x > 0 && offset.y > 0)
{
Debug.Log("upper right");
}else if(offset.x < 0 && offset.y > 0)
{
Debug.Log("upper left");
}else if(offset.x > 0 && offset.y < 0)
{
Debug.Log("lower right");
} else //if(offset.x < 0 && offset.y < 0)
{
Debug.Log("lower left");
}
}
For the distance to the center it is getting more complicated.
We have to get a vector perpendicular to the from the camera to the center and scale this to the propper size. If we add this to the center and transform it into screenspace we will have the maximum magnitude a point on the surface of the sphere could reach.
Vector3 perpendicular = Vector3.Cross(transform.position - Camera.main.transform.position, Vector3.one);
Vector3 maxDistToCenter = transform.position + (perpendicular.normalized * (transform.lossyScale.x * 0.5f));
Vector3 maxDistToCenterOnScreen = Camera.main.WorldToScreenPoint(maxDistToCenter);
float maxDist = (maxDistToCenterOnScreen - centerOnScreen).magnitude;
float dist = offset.magnitude;
if (dist < maxDist * 0.5f) // 50% of the way not the area
{
Debug.Log("inner 50%");
}
else
{
Debug.Log("outer 50%");
}
Combining both grant you the ability to evaluate any point on the sphere in angle and distance to the center compared with the maximum distance.
If you just want to apply force to the point clicked, you just need a ridgit body and raycasting. This oficial Unity tutorial will explay it.
Maybe you have to combine both answers, but I think the Unity tutorial is sufficient for your needs.
PS: Please ask questwions with the final goal you want to reach and not just a step you think is needed to get the job done.
You dont need to se raycasts, you can use "OnMouseDown".
Documentation here: http://docs.unity3d.com/ScriptReference/MonoBehaviour.OnMouseDown.html
Note: your object needs a collider in order for this to work.

Moving the object up and down - a loop

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!)