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.
Related
I'm currently making a 2D game as a beginner and I made a spinning platform. But when it's rotating the player's rotation (z-axis) also changes because it's a child of the platform. I need this when I use moving platforms. Now I want to lock the z-axis of the rotation of the player. I already tried it in 3 different ways, but none of them seems to be working. Does anybody know how to do this?
These are the three ways I tried:
// 1
PlayerTrans.transform.Rotate(
PlayerTrans.transform.rotation.x,
PlayerTrans.transform.rotation.y,
0);
// 2
PlayerTrans.transform.Rotate(
PlayerTrans.transform.rotation.x,
PlayerTrans.transform.rotation.y,
0,
Space.Self);
// 3
PlayerTrans.transform.localRotation = Quaternion.Euler(new Vector3(
PlayerTrans.transform.localEulerAngles.x,
PlayerTrans.transform.localEulerAngles.y,
0f));
and this is, what my code looks like for staying on the moving platforms. I used raycasting for this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Raycasting : MonoBehaviour
{
// Start is called before the first frame update
Transform PlayerTrans;
public float RayCastRange = 3;
void Start()
{
PlayerTrans = transform.parent;
}
// Update is called once per frame
void Update()
{
RaycastHit2D PlattformCheck = Physics2D.Raycast(transform.position, -Vector2.up, RayCastRange);
if (PlattformCheck.collider != null)
{
if (PlattformCheck.collider.gameObject.tag == "Platform")
{
PlayerTrans.transform.SetParent(PlattformCheck.collider.gameObject.transform);
}
else
{
PlayerTrans.transform.SetParent(null);
}
}
else
{
PlayerTrans.transform.SetParent(null);
}
}
}
There are 2 ways that might help you:
Just freeze the rotation from the inspector:
you can use some LookAt function (there is one for 3D but you can look and find ones for 2D) and just look at the camera.
(if you cant find it let me know and I will add it)
You should raycast directly down and then apply velocities to both objects (un-child the player from the platforms). You could do something like this for the player:
public LayerMask mask; //set ‘mask’ to the mask of the
//platform in the Unity Editor.
public Vector3 velocity;
void Update()
{
RaycastHit hit;
if (Physics.Raycast(transform.position, -Vector3.up, out hit, 0.1f, mask))
//0.1f is the distance to the platform to be able to be moved by the platform.
{
velocity = hit.collider.gameObject.GetComponent<Platform>().velocity;
}
float h = Input.GetAxis(“Horizontal”);
//this one is for CharacterController:
cc.Move(velocity);
//this one is for rigidbody:
rb.velocity = velocity;
velocity = 0;
}
It takes the velocity from the ‘Platform’ script and moves the player based on it. Now we should add the platform script. Call it ‘Platform’.
public Vector3 velocity;
public Vector3 a; //a and b are the two points you want the platform to go between.
public Vector3 b;
public float period = 2f; //the amount of seconds per cycle.
float cycles;
void Update()
{
cycles = Time.time / period;
float amplitude = Mathf.Sin(Mathf.PI * 2f * cycles);
Vector3 location = Vector3.Lerp(a, b, amplitude);
velocity = transform.position - location;
transform.position = velocity;
}
This script interpolates between the point a and b, then it finds the velocity and applies it. The player takes this velocity and it moves the player. Comment if you found an error.
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);
}
}
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.
I have tried both of these C#scripts to rotate my directional light:
using System.Collections;
using UnityEngine;
public class LightRotator : MonoBehaviour
{
void Update ()
{
transform.rotation = Quaternion.Euler(transform.eulerAngles.x + 1.0f,
transform.eulerAngles.y,
transform.eulerAngles.z);
}
}
and
using System.Collections;
using UnityEngine;
public class LightRotator : MonoBehaviour
{
void Update ()
{
transform.localEulerAngles = new Vector3(transform.localEulerAngles.x + 1.0f,
transform.localEulerAngles.y,
transform.localEulerAngles.z);
}
}
They both seem to function exactly the same: If I change transform.eulerAngles.y to transform.eulerAngles.y + 0.5f, the light will rotate along the y-axis, and the same works for the z-axis. However, when I try to do this with the x-axis, it will rotate until it hits 90º, at which point it will continue to attempt rotation but it immediately and continuously shoved back to 90º. If I reverse the direction, it does the same thing at -90º. For example, the rotation might be: 88.5,89.0,89.5,90.0, 90.5, 89.93, 90.24, 89.4, etc.
What is causing this clamping and how do I fix it?
I think this is what you are looking for: http://answers.unity3d.com/questions/187073/rotation-locks-at-90-or-270-degrees.html
In order to fix your problem, you need to use an additional vector, change it inside Update every frame, and then pass it to the eulerAngles propriety of the transform.
Vector3 vect = Vector3.zero;
float rotationSpeed = 10f;
void Start () {
vect = transform.eulerAngles; //Set the vect rotation equal to the game object's one
}
void Update ()
{
vect.x += rotationSpeed * Time.deltaTime;
//Pass unique eulerAngles representation to the object without letting Unity change it
transform.eulerAngles = vect;
}
This happens btw because there're multiple euler angles representation of a single physical rotation in the 3D space, and when you work directly on the eulerAngles propriety of the transform, Unity makes some work behind the scenes, which can lead to a gimbal lock.
Use Quaternions. It's what Unity3d uses internally and doesn't have any of the side effects of euler angles.
using System.Collections;
using UnityEngine;
public class LightRotator : MonoBehaviour
{
public Vector3 RotationAxis = Vector3.right;
Quaternion _startRotation;
float _rotationIncrement = 0;
void Start()
{
_startRotation = transform.rotation;
}
void Update ()
{
Quaternion rotationMod =
Quaternion.AngleAxis(_rotationIncrement, RotationAxis);
_rotationIncrement += 1;
transform.rotation = _startRotation * rotationMod;
}
}
However, you probably want to use something like Quaternion.RotateTowards or Quaternion.Lerp along with Time.time and a rate. You will get much smoother results that way.
if you only want to rotate along the X-axis then set the other axis as 0.
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.