How to apply friction to this physics model? - c#

I'm trying to make my little small engine in order to make a table Puck slider game like this one :
Then , i'm having problems to move pucks well , cause i'm using velocity normal to make aceleration be opposite to velocity vector:
velocity = ((Vector2) (initMousePosition - Input.mousePosition)).normalized*1.42f*Mathf.Min(1f,((Vector2) (initMousePosition - Input.mousePosition)).magnitude/Screen.height);
acceleration = - velocity.normalized;
...
This are our usefull vars to resolve my problem:
Board.COEFFICIENTE_OF_FRICTION = 0.1f;
public Vector2 position;
public Vector2 velocity;
public Vector2 acceleration;
The code:
private static void Move()
{
foreach(BoardObject obj in objects)
{
if (obj is Puck)
{
auxPuck = (Puck) obj;
if (auxPuck.velocity.magnitude > 0f)
{
auxPuck.acceleration += (-auxPuck.acceleration * 9.8f*auxPuck.mass*Board.COEFFICIENTE_OF_FRICTION*Time.deltaTime);
auxPuck.velocity += auxPuck.acceleration * Time.deltaTime;
auxPuck.position += auxPuck.velocity * Time.deltaTime;
if (VectorsChangeMagnitudeSign(auxPuck.velocity,auxPuck.velocity-auxPuck.acceleration*Time.deltaTime))
{
auxPuck.acceleration = Vector2.zero;
auxPuck.velocity = Vector2.zero;
}
}
}
}
}
Maybe i'll must use acceleration like a float , or starting with another vector that's not the normalized of velocity. My problem comes when velocity got higher magnitude , it seems to have an strange remaining velocity that makes it moves constantly at the end.
Any idea of how must i do this the good way to run it smothly?

Sorry i have found the problem . I told you . I started to use normalized vector , when i throw the puck , the problem comes cause the puck changes direction vs walls , then the accel rest was decreasing the friction force , causing the const velocity.
Sorry for your time , and thanks anyway.

Related

Change direction but not affecting force

Im struggling with this, tried adding force but its not working the way I wanted, tried also changing direction but it changes by 45degrees which in my case is not what I wanted. Im thinking about adding the wind zone in the direction of arrwos, but came here to ask if theres any other(better) way to do it. Any help would be great! Thanks and have a great day!
Heres image for easier understainding
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ArrowGrass : MonoBehaviour
{
public Rigidbody ball;
public float arrowPower;
public float stoppingPower;
private void OnTriggerStay(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
Vector3 direction = ball.velocity.normalized;
float speed = ball.velocity.magnitude;
Vector3 currentVelocity = ball.velocity;
Vector3 desiredDirection = new Vector3(-1, 0, 0); // set this to the direction you want.
Vector3 newVelocity = desiredDirection.normalized * currentVelocity.magnitude;
ball.AddForce(newVelocity - currentVelocity, ForceMode.VelocityChange);
/*
ball.angularDrag = stoppingPower;
Debug.Log("Colided");
ball.AddForce(new Vector3(-1, 0, 0) * arrowPower * stoppingPower, ForceMode.VelocityChange);
*/
}
}
}
Separate the Forces.
private float userForce = 0f;
void FixedUpdate()
{
if(userForce > 0.1f) // define a minimum force, as we won't reach actual 0.
{
userForce *= 0.95; // no need for Time.deltaTime as we are in FixedUpdate!
}else{
// we can shoot again. User-Force has ended.
userForce = 0; // just make it stop completely eventually.
}
rb.AddForce(userForce * velocity * direction); // you have to define velocity and direction.
}
The OnTriggerStay logic is on the conveyor belt itself, where you can define the force strenght and direction. It is applied to the Physx system and affects the players Rigidbodies velocity. But we can track our userforce whilst ignoring other forces. So the ball can continue to move or at least get pushed to a wall etc.
In the end you can just apply the same principle to a timer as well. Either checking timestamps, or just decreasing a variable using Time.deltaTime and checking if it's < 0.

How to make a ground object follow a flying object in unity?

I'm trying to make an object on the ground follow a flying object, for example a drone leading a human (for now i'm just using shapes - a cube and a capsule). My cube follows the capsule like i desire but i want the cube to follow the capsule on the ground only, rather than go up on the y-axis with the capsule. Right now, it follows the capsule everywhere, I want the capsule to lead while the cube follows along on the ground.
I have done some research on Google and Youtube but I have not seen any results. Please let me know how I can achieve this.
This is the code script attached to the cube(ground object)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class follow_target : MonoBehaviour
{
public Transform mTarget;
float mSpeed = 10.0f;
const float EPSILON = 0.1f;
Vector3 mLookDirection;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
mLookDirection = (mTarget.position - transform.position).normalized;
if((transform.position - mTarget.position).magnitude > EPSILON)
transform.Translate(mLookDirection * Time.deltaTime * mSpeed);
}
}
If the ground is planar, you can just set the y component to 0 (or whatever the ground y vector is).
If the ground changes in topology, you can do a raycast down from the capsule to get the hit point (vector3). You can use the hit point y component for the height. After that you will need to set the cubes rotation so that it is aligned to the ground. You could do that with a raycast as well, there are a number of examples of that online.
I hope that helps get you in the right direction.
Assuming a flat ground on Y = 0
either make sure your objects sticks to the ground so set
private const float EPSILONSQR = EPSILON * EPSILON;
void Update()
{
var difference = mTarget.position - transform.position;
mLookDirection = difference.normalized;
if(difference.sqrmagnitude > EPSILONSQR)
{
// In general be aware that Translate by default moves in the
// objects own local space coordinates so you probably would rather
// want to use Space.World
transform.Translate(mLookDirection * Time.deltaTime * mSpeed, Space.World);
var pos = transform.position;
// reset the Y back to the ground
pos.y = 0;
transform.position = pos;
}
}
or simply already map the direction down on the XZ plane (ignoring any difference in Y) like
private const float EPSILONSQR = EPSILON * EPSILON;
void Update()
{
var difference = mTarget.position - transform.position;
mLookDirection = difference.normalized;
// simply ignore the difference in Y
// up to you if you want to normalize the vector before or after doing that
mLookDirection.y = 0;
if(difference.sqrmagnitude > EPSILONSQR)
{
transform.Translate(mLookDirection * Time.deltaTime * mSpeed, Space.World);
}
}

How to make camera relative movement

I'm learning unity and c#, and want to make my movement to be camera relative movement instead of world relative movement. How do I do that?
I'm learning unity and c#, my unity version is 2018.3.12f1. I would be happy for help.
just to let know, instead of moving the cam I'm rotating the player.
void Update()
{
float AxisY = Player.transform.eulerAngles.y;
/* Movement starts here */
Vector3 Movement = new Vector3 (Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) { //running code
Player.transform.position += Movement * running_speed * Time.deltaTime;
} else {
Player.transform.position += Movement * speed * Time.deltaTime;
}
/*Movement ends here */
/* Rotation controller starts here */
Quaternion target = Quaternion.Euler(Player.transform.eulerAngles.x, Player.transform.eulerAngles.y, Player.transform.eulerAngles.z);
/*if (Player.transform.eulerAngles.x != 0 || Player.transform.eulerAngles.z != 0 || Player.transform.eulerAngles.y != 0) {
Player.transform.rotation = Quaternion.Euler(0,0,0);
}*/
if (Input.GetKey(KeyCode.E))
{
Debug.Log("E got pressed");
//float AxisYPositive = Player.transform.eulerAngles.y;
AxisY = AxisY+1;
Player.transform.rotation = Quaternion.Euler(0, AxisY, 0);
} else if (Input.GetKey(KeyCode.Q))
{
Debug.Log("Q got pressed");
//float AxisYNegetive = Player.transform.eulerAngles.y;
AxisY=AxisY-1;
Player.transform.rotation = Quaternion.Euler(0, AxisY, 0);
}
}
}
The player's movement is world relative, how to make the movement camera relative?
If you want to make the movements relative to the gameObject, call the method Transform.Rotate() on the transform of the gameObject you want to rotate rather than modifying its Quaternion directly. Just make sure the final argument is set to Space.Self.
if (Input.GetKey(KeyCode.E))
{
Debug.Log("E got pressed");
//float AxisYPositive = Player.transform.eulerAngles.y;
AxisY = AxisY+1;
Player.transform.Rotate(Quaternion.Euler(0, AxisY, 0), Space.Self);
}
In general you don't want to directly mess with objects transform.rotation, at least not unless you at least somewhat understand quaternions (I don't!).
I can see a few issues with your code, but the common thread seems to be that you don't really understand how transforms work. Specifically, you might want to look into World/Local space.
The usual way to control a player goes roughly like this:
void DoMovement(Transform player)
{
//If you move first your controls might feel 'drifty', especially at low FPS.
Turn(player);
Move(player);
}
void Turn(Transform player)
{
float yaw = Input.GetAxis("Yaw") * time.deltaTime; //Aka turn left/right
player.Rotate(0, yaw, 0, Space.Self);
// Space.Self is the default value, but I put it here for clarity.
//That means the player will rotate relative to themselves,
//...instead of relative to the world-axis, like in your code.
}
You didn't ask about movement, but as-is your character will always move relative to the world. The below should make it move relative to the camera.
Transform _cameraTransform; //Assumes this is set druing Start()
void Move(Transform player)
{
var forwardMove = _cameraTransform.Forward; //Get whatever direction is 'forward' for camera
forwardMove.Y = 0; //Don't want movement up and down.
forwardMove = forwardMove.normalized; //Normalize sets the 'power' of the vector to 1.
//If you set Y to 0 and don't normalize you'll go slower when camera looks down
//...than when camera is flat along the plane
player.position += forwardMove * Input.GetAxis("Vertical") * time.deltaTime;
//Here you could do the same for strafe/side to side movement.
//Would be same as above, but using the transform.right and Horizontal axis
}
Now, I'm making some assumptions here since you haven't specified what kind of game it is and what kind of controls you want. I'm assuming you have a character running around on a mostly flat plane (no aircraft/spaceship controls), and that the camera is attached to the player. This might not not actually be the case.
In any case I advice you to check out the tutorials, especially the Roll-a-Ball tutorial which I have found is good for beginners to get a grasp on basic players controls that are not just world-relative. The other tutorials, too, are pretty good if you think they're interesting.
Aside from the official Unity tuts a ton of decent to amazing tutorials out there, including video tutorials, so for something like this you could just search for <game type> tutorial and pick whatever seems good to you. While getting started I advice you to avoid the shortest videos, as you will likely benefit greatly from explanation that only fits in longer videos. Of course, that doesn't mean you should pick the longest videos either.
In case someone needs to move an object and don't care about colliders, you can use transform.Translate and assign to his second parameter relativeTo your camera (or any transform) to automatically calculate the translation relative to the object assigned.

Steering behaviors: Why is my wandering algorithm not working as intended?

We're learning about steering behaviors in my artificial intelligence for games class, and I figured I'd try my hand at implementing some of them. I've mainly been reading The Nature of Code to familiarize myself with the topics.
Here is the repository for my Unity project. The relevant scene is under Assets/Scenes/Wandering.unity.
Here's the associated script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Wandering : MonoBehaviour
{
public float maxSpeed;
private float speed;
public float maxForce;
public float radius;
private Rigidbody body;
void Awake()
{
body = gameObject.GetComponent<Rigidbody>();
speed = maxSpeed;
body.velocity = new Vector3(5, 0, 5);
}
void Update()
{
// Get future position
Vector3 futurePosition = GetFuturePosition();
// Select random point on circle of radius "radius" around the future position
Vector3 target = GeneratePointOnCircle(futurePosition);
// Compute desired velocity as one pointing there
Vector3 desiredVelocity = GetDesiredVelocity(target);
// Get the steering force vector
Vector3 steerForce = desiredVelocity - body.velocity;
steerForce.y = 0;
// Cap the force that can be applied (lower max force = more difficult to turn)
if (Vector3.Magnitude(steerForce) > maxForce)
{
steerForce = Vector3.Normalize(steerForce) * maxForce;
}
// Apply the force to the body
body.AddForce(steerForce);
}
/* Returns a random point on a circle positioned at the given center and radius.
*/
Vector3 GeneratePointOnCircle(Vector3 center)
{
Vector3 point = center;
float angle = Random.Range(0, 360) * Mathf.Deg2Rad;
point.x += radius * Mathf.Cos(angle);
point.z += radius * Mathf.Sin(angle);
return point;
}
/* Computes and returns the future, predicted position of this object, assuming
* it continues traveling in its current direction at its current speed.
*/
Vector3 GetFuturePosition()
{
// We have a current velocity
// We have a time elapsed
// We have a current position
// Future position = current position + current velocity * delta time
return transform.position + body.velocity * Time.deltaTime;
}
/* The desired velocity is simply the unit vector in the direction of the target
* scaled by the speed of the object.
*/
Vector3 GetDesiredVelocity(Vector3 target)
{
return Vector3.Normalize(target - transform.position) * speed;
}
}
Values set in the editor:
maxSpeed: 40
maxForce: 20
radius: 60
When I run this, the agent does not behave as intended. The main problem is that instead of traveling smoothly, it stutters around in brief bursts, seems to pause, and then starts moving again. This random behavior is still pretty neat, and sort of mimics that of a disoriented rodent, but I'm looking for more intelligent-seeming behavior.
Is there a flaw in my script or logic that's forcing the agent to behave in this erratic manner? Any advice would be greatly appreciated.
It seems the problem was my use of Time.deltaTime for calculating the predicted point in the future if the agent were to continue at its current velocity.
Since this is really the time elapsed since the last frame update, it's quite a small number. Thus, using it for predicting the future point was misleading and would produce points very close to the agent (hence the "stuttering" behavior).
Instead, I opted to use a fixed "lookahead" time (say 2) to predict further into the future.

Rotate player with platform without parenting

I'm currently making a small platformer 3D game, but unfortunately I can't make the player to rotate properly when it is riding the platform, the thing here is that I don't want to make the player child of the platform, so far I've managed to make him move smoothly along with the platform, but the rotation is still going nowhere, here is the code I'm using for the rotation:
player.transform.rotation *= platform.rotation;
and here is the effect I got:
Rotation Error
not very nice :(
I guess the solution is something simple, some formula, but unfortunately I'm not very good with math :( So, thank you guys, I hope you can help me.
I'll show you a simple script example which makes a cube rotate by input while reacting to the rotation of the platform on which it stands:
using UnityEngine;
public class CubeRotation : MonoBehaviour {
public GameObject Platform;
Quaternion PreviousPlatformRotation;
public float rotationSpeed = 50;
private void Start() {
PreviousPlatformRotation = Platform.transform.rotation;
}
private void Update() {
//Rotate the cube by input
if (Input.GetKey(KeyCode.A)) {
transform.Rotate(Vector3.up, Time.deltaTime * rotationSpeed);
}
if (Input.GetKey(KeyCode.D)) {
transform.Rotate(Vector3.up, -Time.deltaTime * rotationSpeed);
}
//Adjust rotation due to platform rotating
if (Platform.transform.rotation != PreviousPlatformRotation) {
var platformRotatedBy = Platform.transform.rotation * Quaternion.Inverse(PreviousPlatformRotation);
transform.rotation *= platformRotatedBy;
PreviousPlatformRotation = Platform.transform.rotation;
}
}
}
The logic of the adjustment to the platform rotation is this:
Get at start the rotation quaternion of the platform (in your case, get it when the cube object climbs on the platform)
With A and D rotate the cube normally around the local Y axis.
Afterwards check if the platform's rotation has changed, if yes:
3.a Get how much the platform rotated since the previous frame, with the operation Actual rotation * Inverse(Previous Rotation); this operation it's akin to a difference between two quaternions
3.b Add that quaternion to the cube's rotation with the *= operator
3.c Set the platform's previous rotation value to the new one.
That's pretty much it.

Categories