I'm trying to implement obstacle avoidance within steering behaviors for a university project.
When I run the project, the AI agent seems to get confused and 'spaz' out moving from left to right very quickly and still doesn't avoid obstacles correctly.
I'm trying to cast a box in front of the agent so that when that box collides with an obstacle, it'll steer away from it and continue to move wander.
Here is the code for the Obstacle Avoidance
public Vector3 ObstalceAvoidance()
{
//Cast a ray from the centre of the agent, in it's forward direction
Ray ray = new Ray(transform.position, transform.forward);
//Name a raycastHit
RaycastHit hitInfo;
//Set avoidanceForce to ZERO for all axis
Vector3 avoidanceForce = Vector3.zero;
//Calculate the 'Avoidance Force'
if(Physics.BoxCast(transform.forward, new Vector3(2.5f, 2.5f, 20.0f), transform.forward, out hitInfo, transform.rotation, maxDistance))
{
if(Vector3.Angle(hitInfo.normal, transform.up) > floorAngle)
{
//Reflect the Vector
avoidanceForce = Vector3.Reflect(agent.velocity, hitInfo.normal);
//Calculate the dot product between the Force and Velocity
if (Vector3.Dot(avoidanceForce, agent.velocity) < -0.9f)
{
//Transform Right
avoidanceForce = transform.right;
}
}
}
if(avoidanceForce != Vector3.zero)
{
//Calculate desired velocity
desiredVelocity = (avoidanceForce).normalized * agent.maxSpeed;
//Calculate the steering Force
steeringForce = desiredVelocity - agent.velocity;
oldSteeringForce = steeringForce;
forceTimer = 0;
}
else
{
steeringForce = Vector3.zero;
}
return steeringForce;
}
Related
I have a scene with a globe, where the camera rotates around the globe. I need to clamp the position and rotation of this movement in certain instances of the game. I have tried several methods but none have worked. My code is below:
private void LateUpdate()
{
if (Input.GetMouseButtonDown(1))
mouseStartPosition = GetMouseHit();
if (mouseStartPosition != null)
DragPlanet();
if (Input.GetMouseButtonUp(1))
StaticPlanet();
}
public void RotateCamera(Vector3 dragStartPosition, Vector3 dragEndPosition)
{
//normalised for odd edges
dragEndPosition = dragEndPosition.normalized *planetRadius;
dragStartPosition = dragStartPosition.normalized * planetRadius;
// Cross Product
Vector3 cross = Vector3.Cross(dragEndPosition, dragStartPosition);
// Angle for rotation
float angle = Vector3.SignedAngle(dragEndPosition, dragStartPosition, cross);
//Causes Rotation of angle around the vector from Cross product
holderTransform.RotateAround(planet.transform.position, cross, angle);
}
private static Vector3? GetMouseHit()
{
RaycastHit hit;
int layer_mask = LayerMask.GetMask("Planet"); //raycasting on the planet
if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit, Mathf.Infinity, layer_mask))
{
return hit.point;
I'm trying to make a dotted line that shows where the balls going to land and reflect from there. I'm using unity's physics system.
I think something is wrong with circle cast and line renderer.
The balls are spawning thru wherever i click with my mouse. So i do not see any problem on BallCreate() function.
Here is the problem.
The Problem
As you can see in the picture, balls instantiated on transform.position and going thru hit.point. Somehow line-renderer and ball direction is not the same. There is always a little bit difference(Sometimes more).
The code is below:
I'm trying to fix this for a week, any help means so much.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public Transform BallPrefab = null;
bool ShootDirected = true;
Vector3 mousePos;
private LineRenderer linerender;
RaycastHit2D hitx;
private Vector3 dir;
private Vector3 origin;
void Start()
{
linerender = GetComponent<LineRenderer>();
}
void Update()
{
mousePos = new Vector3(Camera.main.ScreenToWorldPoint(Input.mousePosition).x, Camera.main.ScreenToWorldPoint(Input.mousePosition).y, 0);
//Direction according to mouse position.
dir = mousePos - transform.position;
origin = transform.position;
//First hit point 0.3307159f is the radius of the ball.
RaycastHit2D hit = Physics2D.CircleCast(origin, 0.3307159f, dir, 100f, 1 << 9 | 1<<10);
if (hit.collider != null)
{
//Stored reflected hit point.
Vector2 reflectDir = Vector2.Reflect(dir, hit.normal);
//Then start second ray from hit point thru reflected hit point.
RaycastHit2D SecondHit = Physics2D.CircleCast(hit.point, 0.3307159f, reflectDir, 100, 1 << 9 | 1<<10);
//Draw lines beetween origin, hit.point and secondhit point.
linerender.SetPosition(0, origin);
linerender.SetPosition(1, hit.point);
linerender.SetPosition(2, SecondHit.point);
}
//Create 50 balls when mouse clicked.
if (Input.GetMouseButtonUp(0))
{
ShootDirected = true;
StartCoroutine("BallCreate");
}
}
IEnumerator BallCreate()
{
Vector3 shootDirection = new Vector3(0,0,0);
//Create 50 balls
for (int i = 0; i < 50; i++)
{
Transform ball = Instantiate(BallPrefab, transform.position, Quaternion.identity) as Transform;
Rigidbody2D rb = ball.GetComponent<Rigidbody2D>();
if (ShootDirected)
{
//Set shootDirection to mouse position
shootDirection = Input.mousePosition;
shootDirection.z = 0.0f;
shootDirection = Camera.main.ScreenToWorldPoint(shootDirection);
//Get direction.
shootDirection = (shootDirection - transform.position);
ShootDirected = false;
}
//Apply force to each ball thru mouse direction.
rb.velocity = new Vector2(shootDirection.x, shootDirection.y);
rb.velocity = 7f * (rb.velocity.normalized);
yield return new WaitForSeconds(0.08f);
}
}
}
Found the problem with help of MelvMay on Unity Technologies.
Simply change
`RaycastHit2D SecondHit = Physics2D.CircleCast(hit.point, 0.3307159f, reflectDir, 100, 1 << 9 | 1<<10);`
to
RaycastHit2D SecondHit = Physics2D.CircleCast(hit.centroid, 0.3307159f, reflectDir, 100, 1 << 9 | 1<<10);
MelvMay's explanation;
If you look at the RaycastHit2D docs you'll see both a "point" property (which you're using) which is the actual position the shapes intersected. For a ray this is obvious as it has no size. For a shape such as a circle, this isn't the position the circle is when it intersects, it's the point on its exterior. For all the casts, you can use the "centroid" property for this. This returns the position of the shape when it is in contact. For a Line/Ray, both the "point" and "centroid" properties are identical but for (say) a circle, box, capsule or polygon, these will be different.
For a 3D first person controller game, I am converting a swipe on the screen in a direction vector.
An object is shot into this direction.
My camera can rotate based on the input of a virtual joystick.
When I don't rotate and shoot the object using swipe it goes in the right direction.
However when I rotate the camera it doesn't go in the intended direction.
The direction should be adapted to the rotation of the camera.
How do I correct the direction of my vector to the rotation of the camera?
PS: Message me for further clarification
//Converting swipe direction to 3D direction
public class TouchPair
{
public Vector2 startPos;
public int fingerId;
}
private TouchPair touchPair;
void Update()
{
foreach (Touch touch in Input.touches)
{
Vector2 touchPos = touch.position;
if (touch.phase == TouchPhase.Began)
{
Ray ray = cam.ScreenPointToRay(touchPos);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
//The player is wielding a bomb that is visible on the screen.
//only swipes that start from this object should count
if (hit.transform.tag == "Bomb")
{
touchPair = new TouchPair();
touchPair.startPos = touchPos;
touchPair.fingerId = touch.fingerId;
}
}
}
else if (touch.phase == TouchPhase.Ended)
{
if (touchPair.fingerId == touch.fingerId)
{
Vector2 endPos = touchPos;
Vector2 swipeDirectionRaw = endPos - touchPair.startPos;
float magnitude = swipeDirectionRaw.magnitude;
if (magnitude >= minSwipeLength)
{
BombController BombController = GameObject.FindWithTag("Bomb").GetComponent<BombController>();
BombController.Throw(swipeDirectionRaw.normalized, magnitude);
}
}
}
}
}
public void Throw(Vector2 direction, float magnitude)
{
//Setup variables for throw
throwDirection = new Vector3(direction.x, 0.0f, direction.y);
throwSpeed = magnitude * throwForce;
}
You need raycast with ground when touch.phase == TouchPhase.Ended then get direction from your character to raycast.hit.
Raycasthit hitInfo;
Physic.Raycast;
I had to get the view vector of the camera. By taking the amount of angles
between the player's forward and the camera's view vector the amount of angles is received that is required to get a correct direction vector.
Finally rotate the shoot direction by this amount of angles.
Vector2 endPos = touchPos;
Vector2 swipeDirectionRaw = endPos - touchPair.startPos;
float magnitude = swipeDirectionRaw.magnitude;
swipeDirectionRaw.Normalize();
if (magnitude >= minSwipeLength)
{
GameObject player = GameObject.FindWithTag("Player");
Vector3 shootOrigin = player.transform.position;
Vector3 uncorrectedShootDirection = new Vector3(swipeDirectionRaw.x, 0.0f, swipeDirectionRaw.y);
Vector3 originVector = player.transform.forward;
Vector3 viewVector = cam.transform.forward;
//Shoot direction gets corrected by angle between origin- and view vector
float angleBetweenOriginAndView = Vector3.Angle(originVector, viewVector);
//There is no clockwise or counter-clockwise in 3d space,
//hence mirroring is needed. In my case it's done to what suits my needs
if (viewVector.x < 0.0f)
{
angleBetweenOriginAndView *= -1f;
}
Vector3 correctedShootDirection = Quaternion.Euler(0, angleBetweenOriginAndView, 0) * uncorrectedShootDirection;
}
touchPair = null;
}
https://scontent.fmgf1-2.fna.fbcdn.net/v/t34.0-12/15870843_1543174992374352_1359602831_n.gif?oh=dc048c9e04617007c5e82379fd5a9c1a&oe=586CC623
Can you see the blue area in this gif? I want block the camera when the player go more to left, to not see the blue area. This is the code that I'm using to move the camera:
public class configuracoesDaCamera : MonoBehaviour {
Vector3 hit_position = Vector3.zero;
Vector3 current_position = Vector3.zero;
Vector3 camera_position = Vector3.zero;
float z = 0.0f;
public static bool bDedoNoHud;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
hit_position = Input.mousePosition;
camera_position = transform.position;
}
if (Input.GetMouseButton(0))
{
current_position = Input.mousePosition;
LeftMouseDrag();
}
Debug.Log("bDedoNoHud" + bDedoNoHud);
}
void LeftMouseDrag()
{
if (!bDedoNoHud)
{
// From the Unity3D docs: "The z position is in world units from the camera." In my case I'm using the y-axis as height
// with my camera facing back down the y-axis. You can ignore this when the camera is orthograhic.
current_position.z = hit_position.z = camera_position.y;
// Get direction of movement. (Note: Don't normalize, the magnitude of change is going to be Vector3.Distance(current_position-hit_position)
// anyways.
Vector3 direction = Camera.main.ScreenToWorldPoint(current_position) - Camera.main.ScreenToWorldPoint(hit_position);
// Invert direction to that terrain appears to move with the mouse.
direction = direction * -1;
Vector3 position = camera_position + direction;
transform.position = position;
}
}
}
You mean setting up boundaries?
This should help you
Put it in the update()
void OnMouseDrag() {
float distance = transform.position.z - Camera.main.transform.position.z;
Vector3 pos = Input.mousePosition;
pos.z = distance;
Vector3 mousePosition = new Vector3(pos.x, pos.y, pos.z);
Vector3 objPosition = Camera.main.ScreenToWorldPoint(mousePosition);
transform.position = objPosition;
}
This is the code snippet help me to move the object on mouse drag. It is moving object on mouse drag in x axis while z axis movement is not working correctly using mouse. I basically want to move the object on x and z-Axis using mouse Input.
What is wrong how can i get z position from the mouse input in order to move the object on z axis correctly.
When you casting ray to your object it is being calculated multiple times so it returns your ball position when its not being move a real deal you can try something like this
void OnMouseDrag() {
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Debug.DrawRay(ray.origin, ray.direction * 10, Color.yellow);
Debug.Log(ray);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, Camera.main.farClipPlane))
{
if (hit.transform.gameObject.name == "CameraElasticPoint")
{
return;
}
else{
transform.position = new Vector3(hit.point.x,hit.transform.position.y+1, hit.point.z);
hitPoint = Input.mousePosition;
}
}
}
what it will do it will ignore your objects and works only on other hit info which would be your floor or any other surface you are trying to drag your object along and it will drag your object on X and Z axis taking the Y position of the Floor so it will always remain on top of the floor or any other surface collider on
let me know if it works
Good day
I would recommend going through the Unity Tutorial here:
http://unity3d.com/learn/tutorials/projects/survival-shooter-project
It might give you some ideas on how to solve the problem of x/z plane movement with the mouse.
No. screenpointtoray is very unnecessary here, you just need to say that pos.z is equal to pos.x....
like so...
Vector3 pos = Camera.main.ScreenToViewportPoint(Input.mousePosition - dragOrigin);
pos.z = pos.x;
Vector3 move = new Vector3(0, pos.y * dragSpeed, pos.z * -dragSpeed);
always a pleasure x