Tilt Control Similar to Temple run - unity3d

I want to create tilt effect just like temple run.I have a character controller(player) in the game that is moving on its forward by controller.Move(transform.forward) after which I am apply tilt to it to lean it left and right .Previously for the tilt I tried modifying the player position by using transform.translate /tranform.position directly through the accelerometer readings like this :
mytransform.translate(acceleration.x*Time.delaTime*5.0f);
but that had a problem that when I shake the device my camera starts to jerk and the player also then I used the following code to create tilt on positive Z axis
Vector3 dir = new Vector3(accel.x*8f, 0,0);
if (dir.sqrMagnitude > 1)
{
dir.Normalize();
}
dir.x = Mathf.Round(dir.x * 10f) / 10f;
//mytemp is used for temp storage of player position added with the acceleration
mytemp = mytransform.position+(mytransform.right*dir.x*Time.deltaTime*5.0f);
Vector3 diffVec=Vector3.zero;
///position of the element on which the player is colliding;
Vector3 col_pos=Collidingelement.transform.position;
Vector3 unitvec=new Vector3(1,0,0);
//removing x and z of the collider
diffVec= Vector3.Scale(col_pos,unitvec);
//nullify the y,z of the updated mytransform position so that the distance is only measured on X
Vector3 ppos = Vector3.Scale(mytemp,unitvec);
//calculate the distance between player & colliding element
disti=Vector3.Distance( ppos,diffVec);
disti=Mathf.Clamp(disti,-1.5f,1.5f);
disti = Mathf.Round(disti * 10f) / 10f;
//update the player position and apply tilt to it if the distance is less than 1.5f
if(disti<=1.50f)
{
mytransform.position=mytemp;
}
now this has a problem that if lets say I have a value of 0.1 in the acceleration its keep on update my temp and if the distance is less my player will start leaning towards a side though I held my device on same position and acceleration value was always 0.1

Why don't you just calculate delta acceleration.
bool isMoved = false;
Vector2 lastAccel = Vector2.Zero;
Vector2 margin = new Vector2(0.05f, 0.05f); //not processing if its in margin.
Vector2 deltaAccel = currAccel - lastAccel ;
if(deltaAccel.x < margin.x)
{
//don't process
isMove = false;
}
else
{
isMove = true;
lastAccel = currAccel;
}
if(isMove)
{
//Process with deltaAccel here
}

Related

2D car control with mouse position in unity 2D

i am new in unity. I want to car game with mouse control to Unity 2D. I was trying this code but not working. Car vibrates when i move mouse over car. I want it to work perfectly when the mouse hovers over the car. how can i do this? my code is as follows:
private void OnMouseOver()
{
// Distance from camera to object. We need this to get the proper calculation.
float camDis = cam.transform.position.y - my.position.y;
// Get the mouse position in world space. Using camDis for the Z axis.
Vector3 mouse = cam.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, camDis));
float AngleRad = Mathf.Atan2 (mouse.y - my.position.y, mouse.x - my.position.x);
float angle = (180 / Mathf.PI) * AngleRad;
body.rotation = angle;
Vector3 temp = Input.mousePosition;
temp.z = 10f; // Set this to be the distance you want the object to be placed in front of the camera.
this.transform.position = Camera.main.ScreenToWorldPoint(temp);
}
I'm not too clear on the effect you want to achieve, but if you just want the object to move and turn gradually instead of instantly changing, that can be achieved using Vector3.MoveTowards and Quaternion.RotateTowards, e.g.:
private void OnMouseOver()
{
// Distance from camera to object. We need this to get the proper calculation.
float camDis = cam.transform.position.y - my.position.y;
// Get the mouse position in world space. Using camDis for the Z axis.
Vector3 mouse = cam.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, camDis));
float AngleRad = Mathf.Atan2 (mouse.y - my.position.y, mouse.x - my.position.x);
float angle = (180 / Mathf.PI) * AngleRad;
//body.rotation = angle; //??
float turnSpeed = 200f;
transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.Euler(0, 0, angle), turnSpeed * Time.deltaTime);
Vector3 temp = Input.mousePosition;
temp.z = 10f; // Set this to be the distance you want the object to be placed in front of the camera.
float moveSpeed = 10f;
transform.position = Vector3.MoveTowards(transform.position, Camera.main.ScreenToWorldPoint(temp), moveSpeed * Time.deltaTime);
}
Edit in response to comment: If you want it to move only when the player begins the drag on the car, then yes, putting it in OnMouseDrag() would work. If you want it to move when the player drags from anywhere on the screen, you'd want to put the movement code in Update() and check whether the left mouse button is being held down using Input.GetMouseButton(0).
If you wanted it to keep moving towards the last mouse position (e.g. player can click on the screen and it will move there while the mouse button is not being held down), you'd need to keep the last mouse location in a class variable and move towards that in Update().
Incidentally if you want it to move a bit more like a car, you could always move it forwards while it turns towards the mouse, rather than moving it directly towards the mouse even if it's facing a different direction.
Here's an example but be aware that I've changed a few things that didn't seem necessary to me, like using my.position rather than transform.position. If you use it you may need to adapt it to suit the rest of your code.
public float maxTurnSpeed = 250f;
public float maxSpeed = 8f;
public float stopDistance = 0.5f;
public float slowDistance = 2.5f;
private void Update()
{
if( !Input.GetMouseButton(0) ) // If the mouse button is NOT being held down this frame
return; // Don't move. (Ideally you would decelerate the car rather than stopping it immediately though.)
// Remove the above two lines and move all of this to OnMouseDrag if you want to require the drag to begin on this object to move it.
// Also note: this code now assumes the object begins in the desired z position and doesn't change it, rather than forcing a z position.
// Distance from camera to object. We need this to get the proper calculation.
float camDis = transform.position.z - Camera.main.transform.position.z; // Changed this to use z instead of y as it appeared to be a mistake(?)
// Get the mouse position in world space. Using camDis for the Z axis.
Vector3 mouse = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, camDis));
float distanceFromMouse = Vector3.Distance(transform.position, mouse);
// If we're further away from the mouse than stopDistance, move.
if( distanceFromMouse > stopDistance )
{
float speedMultiplier = 1.0f;
float rotationMultiplier = 1.0f;
// If we're closer to the mouse than slowdistance, slow down proportionately to the remaining distance from stopDistance
if( distanceFromMouse < slowDistance )
{
speedMultiplier = (distanceFromMouse - stopDistance) / (slowDistance - stopDistance);
}
// Reduce turning speed as we approach stopDistance, but not by as much as speed is reduced
if( speedMultiplier < 0.5f )
rotationMultiplier = speedMultiplier * 2f;
float AngleRad = Mathf.Atan2(mouse.y - transform.position.y, mouse.x - transform.position.x);
float angle = (180 / Mathf.PI) * AngleRad;
// Turn the car towards facing the mouse position
transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.Euler(0, 0, angle), maxTurnSpeed * rotationMultiplier * Time.deltaTime);
// Move the car towards its transform.right vector.
transform.position += transform.right * (maxSpeed * speedMultiplier * Time.deltaTime);
}
}

3rd Person RigidBody Movement Script Using CineMachine

I am trying to create a 3rd person movement script using Cinemachine as camera, I followed Brackeys "THIRD PERSON MOVEMENT in Unity" YouTube tutorial. I then Changed the base of it from character controller to rigidbody and the movement works perfectly fine. However my code sets the velocity of the rigidbody's y axis to 0 when I move the player which fights the gravity making the player jitter slowly to the ground when I move. The Character however does drop to the ground when the player stops moving. All I need is for the script to ignore the y axis and simply listen to unity's gravity.
void Update()
{
if (!photonView.isMine)
{
Destroy(GetComponentInChildren<Camera>().gameObject);
Destroy(GetComponentInChildren<Cinemachine.CinemachineFreeLook>().gameObject);
return;
}
float horizontal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
isGrounded = Physics.CheckSphere(new Vector3(transform.position.x, transform.position.y - 1, transform.position.z), 0.01f, layerMask);
Vector3 inputVector = new Vector3(horizontal, 0f, vertical).normalized;
if (inputVector.magnitude >= 0.1f)
{
float targetAngle = Mathf.Atan2(inputVector.x, inputVector.z) * Mathf.Rad2Deg + cam.eulerAngles.y;
float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
transform.rotation = Quaternion.Euler(0f, angle, 0f);
Vector3 moveDir = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
rb.velocity = moveDir.normalized * speed;
}
if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
{
rb.AddForce(Vector3.up * jumpForce);
}
}
The player jitters because, in your movement section, you set the y velocity to 0, since Vector3.forward returns new Vector3(0, 0, 1) and you only rotate the vector around the y axis. Instead of this, consider doing:
Vector3 moveDir = new Vector3(transform.forward.x, rb.velocity.y, transform.forward.z);
This will preserve the velocity as it was, removing the jittering.
Note: transform.forward automatically gets the forward vector for the player.

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?

Translated grapple physics from Processing to Unity to get different results

tl;dr Moving my game from Processing to Unity. Code responsible for grappling by manually changing the player's velocity doesn't work even though it's basically copy/pasted.
Hi, I've been working on a project of mine over the summer on Processing, and last week I decided to translate it over to Unity.
What I'm having a problem with is the grapple/rope physics. It's supposed to essentially keep the player inside a circle (made by the endpoint of the rope and the length of the rope). When the player falls outside of this circle, the player's position is moved back to the edge of the circle and the player's velocity is set to tangent of the circle.
Decreasing the length of the rope while swinging is supposed to speed you up. (See Floating Point)
On Processing, it works perfectly just as described above, but when I basically copy/pasted the code into unity it loses momentum too quickly (always ends up stopping at the same angle on the other side the player started on). Here is the code for both (run on each physics frame):
(I've also made some images to describe the motion that both versions produce)
Processing
Code
(warning: bad and redundant)
physics update:
exists = (endPoint != null);
if(lgth<=0) lgth = 1;
if(exists) {
currentLength = phs.position.dist(endPoint);
if(currentLength > lgth) {
float angle = getAngle(endPoint, phs.position);
phs.addPosition(abs(currentLength - lgth), angle);
float angleBetween = getAngle(phs.position, endPoint);
PVector relativeVelocity = new PVector(phs.velocity.x + phs.position.x, phs.velocity.y + phs.position.y);
float displacement = angleBetween - 90;
Line l1 = lineFromTwoPoints(relativeVelocity, endPoint);
Line l2 = lineFromAngle(phs.position, displacement);
PVector pointToLerpTo = intersection(l1, l2);
if(pointToLerpTo!=null) {
phs.velocity.x = pointToLerpTo.x-phs.position.x;
phs.velocity.y = pointToLerpTo.y-phs.position.y;
}
else phs.velocity.mult(0);
}
}
when the player shortens the rope, speed increases:
if(exists) {
float newLgth = lgth-d;
float distance = getDistance(phs.position, endPoint);
if(distance > newLgth) {
float ratio = (distance-newLgth)/lgth;
phs.velocity.setMag(phs.velocity.mag()*(1+ratio));
}
lgth = newLgth;
}
Motion from Processing (good)
Player starts by moving downwards at left edge of rope circle. Doesn't lose speed and continues going around multiple times until gravity slows it down.
Unity
Code
both code blocks from above are handled in the same place here, under FixedUpdate() (problematic part seems to be the velocity section)
distance = Vector2.Distance(transform.position, endpoint);
if(connected && distance > length) {
//lerp position -> endpoint// keep gameObject within length of the rope
float posLerpAmount = (distance - length) / distance;
transform.position = Vector2.Lerp(transform.position, endpoint, posLerpAmount);
//'lerp' velocity -> endpoint// keep the velocity locked to the tangent of the circle around the endpoint
Vector2 relativeVelocity = GetComponent<Rigidbody2D>().velocity + (Vector2)transform.position;
Line l1 = Geometry.LineFromTwoPoints(relativeVelocity, endpoint);
Line l2 = Geometry.LineFromAngle(transform.position, Geometry.GetAngle(endpoint, transform.position) - 90);
if(!Geometry.AreParallel(l1, l2)) {
Vector2 pointToLerpTo = Geometry.Intersection(l1, l2) - (Vector2)transform.position;
GetComponent<Rigidbody2D>().velocity = pointToLerpTo;
}
else GetComponent<Rigidbody2D>().velocity = new Vector2(0, 0);
//increases the magnitude of the velocity based on how far the rope moved the object's position
float ratio = (distance - length) / length;
GetComponent<Rigidbody2D>().velocity *= 1 + ratio;
distance = length;
}
Motion from Unity (bad)
Player starts by moving downward at left edge of rope circle. Gains a little bit of speed from gravity, then will always stop 45 degrees on the other side where it started (regardless of starting speed), then slowly fall back down to the bottom of the circle.
If anyone needs me to explain the Geometry class (lines, intersections) then I can, but I think it's mostly self-explanatory. Otherwise, I think I explained this the best I could. Thanks in advance for any help.
(also, StackOverflow isn't letting me add the Unity2d tag so I guess I gotta settle for Unity3d)
I found out that Rigidbody2D.velocity.magnitude is not how far the object moves every physics update. This is what was causing the issue, because the Processing code was based off the velocity being added directly to the position every update.
To fix this, what I did was do the same geometry, but scale the velocity to the % of how much of the velocity was actually 'used' (it usually travels 2% of the actual velocity vector).
Here is the final code in Unity: (this time I'm showing the fill FixedUpdate(), with the irrelevant parts removed)
float lastMagnitude;
Vector2 lastPosition;
void FixedUpdate() {
float velocityMoved = Vector2.Distance(lastPosition, transform.position) / lastMagnitude;
Debug.Log(velocityMoved * 100 + "%"); //this is usually 2%
bool shortenedRope = false;
if(Input.GetButton("Shorten Rope")) {
shortenedRope = true;
length -= ropeShortenLength;
}
distance = Vector2.Distance(transform.position, endpoint);
if(connected && distance > length) {
//lerp position -> endpoint// keep gameObject within length of the rope
float posLerpAmount = (distance - length) / distance;
transform.position = Vector2.Lerp(transform.position, endpoint, posLerpAmount);
//'lerp' velocity -> endpoint// keep the velocity locked to the tangent of the circle around the endpoint
Vector2 adjustedVelocity = rigidbody.velocity * velocityMoved;
Vector2 relativeVelocity = adjustedVelocity + (Vector2)transform.position;
Line l1 = Geometry.LineFromTwoPoints(relativeVelocity, endpoint);
Line l2 = Geometry.LineFromAngle(transform.position, Geometry.GetAngle(endpoint, transform.position) - 90);
if(!Geometry.AreParallel(l1, l2)) {
Vector2 pointToLerpTo = Geometry.Intersection(l1, l2) - (Vector2)transform.position;
rigidbody.velocity = pointToLerpTo;
rigidbody.velocity /= velocityMoved;
}
else rigidbody.velocity = new Vector2(0, 0);
//'give back' the energy it lost from moving it's position
if(shortenedRope) {
float ratio = (distance - length) / length;
rigidbody.velocity *= 1 + ratio;
}
distance = length;
}
lastPosition = transform.position;
lastMagnitude = rigidbody.velocity.magnitude;
}
EDIT: Recently learned that it is better to use Time.deltaFixedTime instead of the variable I made velocityMoved, since Time.deltaFixedTime is already calculated.

Unity objects bend around forcefield

I want to achieve this image below where it looks like the towers are being influenced by forcefield.
It looks simple, right?
GameObject towers = GameObject.Find("towers");
GameObject ball = GameObject.Find ("ball");
foreach (Transform tower in towers.transform) {
Vector3 heading = ball.transform.position - tower.position;
float distance = heading.magnitude;
Vector3 direction = heading.normalized;
Vector3 newDir = Vector3.RotateTowards(ball.transform.position, heading, 1, 0.0F);
tower.rotation = Quaternion.LookRotation(newDir);
//Debug.DrawRay(ball.transform.position, newDir, Color.red);
}
This is the result:
The towers in the back are decent but the front is falling in the wrong direction. What happened? Also, is there a way to control how much influence the towers bend depending on the distance from the ball to the tower?
Here is a solution which uses an AnimationCurve to control the rotation angle of your towers according to the distance between them and your ball.
My animation curve has two keys :
(0, 90) // Meaning the tower will be rotated 90° when they are 0 units from the ball
(10, 0) // Meaning the tower will be rotated 0° when they are 10 units from the ball
public AnimationCurve effect;
private GameObject towers ;
private GameObject ball ;
private void Start()
{
towers = GameObject.Find("towers");
ball = GameObject.Find ("ball");
}
private void Update()
{
foreach (Transform tower in towers.transform)
{
Vector3 direction = (ball.position - tower.position);
Vector3 rotationAxis = Vector3.Cross( direction.normalized, Vector3.up );
float angle = effect.Evaluate( direction.magnitude ) ;
tower.rotation = Quaternion.AngleAxis( angle, rotationAxis );
// If you want your towers to look at your ball :
// tower.rotation = Quaternion.LookRotation( direction ) * Quaternion.Euler( -angle, 0, 0 );
}
}