Drone for target pursuit in unity - c#

I've already done the player drone control, now I want to make a bot. The problem is that I don't understand a little how to determine the slope, turn and climb/decrease in height.
I would not like to change the current control method, since it works fine. Also, the bot always knows about the player's position.
public class DroneFootballAI : MonoBehaviour
{
public float minMaxPitch;
public float minMaxRoll;
public float yawPower;
public Vector2 cyclic;
public float pedals;
public float throttle;
public float lerpSpeed;
public Rigidbody rb;
public Transform playerTransform;
public CheckNode checkNode;
public FootballController footballController;
private float _finalPitch;
private float _finalRoll;
private float _yaw;
private float _finalYaw;
private float _isMove;
private List<DroneEngine> _engines;
private void Awake()
{
rb = GetComponent<Rigidbody>();
_engines = GetComponentsInChildren<DroneEngine>().ToList();
checkNode = GetComponent<CheckNode>();
}
private void FixedUpdate()
{
if (footballController.isGameStart)
{
GetInput();
DroneMove();
}
}
private void GetInput()
{
_isMove = 0;
cyclic.x = Input.GetAxis("Horizontal");
cyclic.y = Input.GetAxis("Vertical");
pedals = Input.GetAxis("Pedal");
throttle = Input.GetAxis("Throttle");
_isMove = cyclic.x + cyclic.y + pedals + throttle;
}
private void DroneMove()
{
foreach (var engine in _engines)
{
engine.UpdateEngine(rb, throttle);
}
float pitch = cyclic.y * minMaxPitch;
float roll = -cyclic.x * minMaxRoll;
_yaw += pedals * yawPower;
_finalPitch = Mathf.Lerp(_finalPitch, pitch, Time.deltaTime * lerpSpeed);
_finalRoll = Mathf.Lerp(_finalRoll, roll, Time.deltaTime * lerpSpeed);
_finalYaw = Mathf.Lerp(_finalYaw, _yaw, Time.deltaTime * lerpSpeed);
Quaternion rot = Quaternion.Euler(_finalPitch, _finalYaw, _finalRoll);
rb.MoveRotation(rot);
}
}

To determine the slope, turn, and climb/descend for the bot, you can use the position of the player as a reference. For example, you can calculate the slope by finding the difference in height between the bot and the player, and use that to adjust the pitch (tilt up or down) of the bot. You can also calculate the difference in horizontal position between the bot and the player, and use that to adjust the roll (tilt left or right) of the bot.
To turn towards the player, you can calculate the angle between the bot's current direction and the direction towards the player, and use that to adjust the yaw (rotation around the vertical axis) of the bot.
To climb or descend towards the player, you can calculate the difference in height between the bot and the player and adjust the throttle (engine power) accordingly. For example, if the player is higher than the bot, you can increase the throttle to make the bot climb, and if the player is lower than the bot, you can decrease the throttle to make the bot descend.
You can use a combination of these techniques to create a simple AI for the bot that follows the player and tries to stay at a certain distance from the player. You can also use more advanced techniques, such as pathfinding or behavior trees, to create more sophisticated AI behaviors.
Below is an example to apply the above suggestions:
private void DroneMove()
{
// Calculate the vector pointing from the bot's position to the player's position
Vector3 directionToPlayer = playerTransform.position - transform.position;
// Calculate the slope of this vector by taking the difference in y-coordinates and dividing it by the difference in x-coordinates
float slope = (playerTransform.position.y - transform.position.y) / (playerTransform.position.x - transform.position.x);
// Calculate the pitch and roll values based on the slope
float pitch = slope * minMaxPitch;
float roll = -slope * minMaxRoll;
// Update the yaw value as before
_yaw += pedals * yawPower;
// Lerp the final pitch, roll, and yaw values as before
_finalPitch = Mathf.Lerp(_finalPitch, pitch, Time.deltaTime * lerpSpeed);
_finalRoll = Mathf.Lerp(_finalRoll, roll, Time.deltaTime * lerpSpeed);
_finalYaw = Mathf.Lerp(_finalYaw, _yaw, Time.deltaTime * lerpSpeed);
// Calculate the quaternion based on the final pitch, roll, and yaw values
Quaternion rot = Quaternion.Euler(_finalPitch, _finalYaw, _finalRoll);
// Set the bot's rotation to the calculated quaternion
rb.MoveRotation(rot);
// Calculate the throttle value based on the distance to the player
throttle = Mathf.Clamp(1 - (directionToPlayer.magnitude / checkNode.viewDistance), 0, 1);
// Update the engines with the calculated throttle value
foreach (var engine in _engines)
{
engine.UpdateEngine(rb, throttle);
}
}
Note that i didn't test this code since this is just for guidance.

Related

How can I make a camera zoom script in c# for unity?

I want a c# script so when I hold right click it zooms in a little and when you stop holding right click it goes back to its original position.
You would first want to store the original camera z distance. (As I assume you want it to go forward in the z direction). Then you would want to have a float for the amount of tome zoom was held down. (Increase it when zooming, and decrease it when you dont click it).
Also have a target z, so it doesn't go too far
public float startZ;
public float targetZ;
public float zoomInSpeed;
public float zoomOutSpeed;
float heldDownTime;
float originalZ;
void Start()
{
startZ = transform.position.z;
}
void Update()
{
if (Input.GetKey(KeyCode.Mouse0))
{
heldDownTime += Time.deltaTime * zoomInSpeed;
}
else
{
heldDownTime -= Time.deltaTime * zoomOutSpeed;
heldDownTime = Mathf.Clamp(heldDownTime, 0, Mathf.Infinity);
}
float smoothed = System.Math.Tanh(heldDownTime);
Vector3 pos = transform.position;
transform.position = new Vector3(pos.x, pos.y, startZ + smoothed * (targetZ - startZ));
}
I basically get the time held down, then I smooth it out, so it doesn't zoom to far forward.
Let me know in the comments if you get any errors!

Swerve Control Unity C#

Hi I am creating a hyper casual game with unity, but I have encountered a problem with the swerve control (I have also seen many git hubs but even these do not work perfectly)
I've put this in my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
private float lastframeposx;
private float movefactorx;
public float MoveFactorX => movefactorx;
public Camera m_MainCam;
private float speed = 2.0f;
[SerializeField]
GameObject character;
[SerializeField] private float swerveSpeed = 0.5f;
[SerializeField] private float maxSwerveAmount = 1f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
transform.position += Vector3.forward * speed * Time.deltaTime;
Cammina();
/*Vector3 destra = Camera.main.ScreenToWorldPointt(Input.touches[i].position);
transform.position += Vector3.zero destra;*/
}
void Cammina()
{
if(Input.GetMouseButtonDown(0))
{
lastframeposx = Input.mousePosition.x;
float swerveAmount = Time.deltaTime * swerveSpeed * MoveFactorX;
swerveAmount = Mathf.Clamp(swerveAmount, -maxSwerveAmount, maxSwerveAmount);
transform.Translate(swerveAmount, 0, 0);
}
else if (Input.GetMouseButton(0))
{
movefactorx = Input.mousePosition.x - lastframeposx;
lastframeposx = Input.mousePosition.x;
float swerveAmount = Time.deltaTime * swerveSpeed * MoveFactorX;
swerveAmount = Mathf.Clamp(swerveAmount, -maxSwerveAmount, maxSwerveAmount);
transform.Translate(swerveAmount, 0, 0);
}
else if(Input.GetMouseButtonUp(0))
{
movefactorx = 0f;
float swerveAmount = Time.deltaTime * swerveSpeed * MoveFactorX;
swerveAmount = Mathf.Clamp(swerveAmount, -maxSwerveAmount, maxSwerveAmount);
transform.Translate(swerveAmount, 0, 0);
}
}
/*void vaidoveschiacciato()
{
if (Input.touchCount > 0 && Input.touches[0].phase == TouchPhase.Began)
{
Ray ray = Camera.main.ScreenPointToRay(Input.touches[0].position);
RaycastHit hit;
if(Physics.Raycast(ray, out hit))
{
if(hit.collider != null)
{
transform.position += hit.collider.GetComponent<Transform.position> * speed * Time.deltaTime;
}
}
}
}*/
}
1 Problem: he don't go when the finger is
2 Problem: How do I eliminate the movement from right to left (Without making it go out of the path)
(Langauge: C#)
The problem: When you swerve, it swerves just in the direction, there is no limits on how far it goes.
How I would fix this: I would put the movement to change it through a function. This could clamp it, so the higher the distance to the center of the track, the less it swerves. Or, you can altogether check if the distance is a maximum and then stop swerving.
Note: you can use other functions to do this (they just have to flatten out the larger the input).
Smooth, good looking bell curve way
For example you could use a bell curve. Look one up if you've never seen one before. It is at it's highest possible output of one, at a zero input. When it gets hiher or lower, it outputs lower to zero.
the simplest equation is y = i-(x2). The lower i is (above 1), the wider the curve, or the larger the output is for a larger input. I made a graph here.
x can be the distance to the center of the track, so you should adjust i, so the maximum distance from the track is flat.
This output is what you should change swerveAmount to.
The flatter parts of the graoh is how much you will swerve when you are that distance from the center (x axis)
Alternatively
You could just check the distance, and if it passes a certain distance don't translate it.
Let me know in the omments if there are any problems! :)

Unity enemy ai always firing bullets high over the player

Got an issue where the enemy will fire at the player, but always seems to go high or to the side of the player even when the player is stationary and isn't moving. Am I doing something wrong in my code which creates this wild issue or is it just a random annoying bug?
Using the same script for the player albeit it under a different name works, which leads me to believe the issue lies within the fire point. Under the player's script I fire like so:
// Get the place the player has clicked
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
// Holds information regarding the mouseclick
RaycastHit hitInfo;
// Now work out if we fire or not
if (Physics.Raycast(ray, out hitInfo))
{
if(hitInfo.distance < maxRange)
{
FireAtPoint(hitInfo.point);
Whereas in the enemy script it is just done through the player's position.
// Holds information regarding the mouseclick
RaycastHit hitInfo;
// Now work out if we fire or not
if (Physics.Raycast(player.transform.position,transform.forward, out hitInfo))
{
Is this underlying issue in the Physics.Raycast call then?
Rest of code for reference:
//More above this but doesn't influence the firing
if (Physics.Raycast(player.transform.position,transform.position, out hitInfo))
{
if (hitInfo.distance < maxRange)
{
FireAtPoint(hitInfo.point);
}
}
private void FireAtPoint(Vector3 point)
{
// Get the velocity to fire out at
var velocity = FiringVelocity(point, angle);
Rigidbody rg = Instantiate(bulletPrefab.gameObject, firePoint.position, firePoint.rotation).GetComponent<Rigidbody>();
EnemyBulletController newProjectile = rg.GetComponent<EnemyBulletController>();
newProjectile.speed = velocity;
}
private Vector3 FiringVelocity(Vector3 destination, float angle)
{
// Get the direction of the mouse click from the player, then get the height differential.
Vector3 direction = destination - transform.position;
float height = direction.y;
height = 0;
// Get the distance in a float of the vector3
float distance = direction.magnitude;
// Turn the firing angle into radians for calculations, then work out any height differential
float AngleRadians = angle * Mathf.Deg2Rad;
direction.y = distance * Mathf.Tan(AngleRadians);
distance += height / Mathf.Tan(AngleRadians);
// Calculate the velocity magnitude
float velocity = Mathf.Sqrt(distance * Physics.gravity.magnitude / Mathf.Sin(2 * AngleRadians));
// Return the normalized vector to fire at.
return velocity * direction.normalized;
}
Picture for reference:
Your equation for computing the velocity looks doubtful. Let's re-derive it:
The equations of free-fall motion under constant gravity are:
After rearranging by substituting the first into the second, we find an expression for the firing velocity:
This is different to what you have, as you are missing the h/d term; said term also gives a constraint on the allowed values of θ:
(Basically means that if you fire directly at the target the bullet would never reach due to gravity)
There are many other problems with your code; just to list three:
Why set height to zero?
Why add a correction to distance? The correction has no physical interpretation.
The fix suggested by #BasillePerrnoud
Amended code:
private Vector3 FiringVelocity(Vector3 destination, float angle)
{
Vector3 direction = destination - transform.position;
float height = direction.y;
float distance = Mathf.Sqrt(direction.x * direction.x + direction.z * direction.z); // *horizontal* distance
float radians = angle * Mathf.Deg2Rad;
float hOverd = height / distance;
float tanAngle = Mathf.Tan(radians);
if (tanAngle <= hOverd)
// throw an exception or return an error code, because no solution exists for v
float cosAngle = Mathf.Cos(radians);
direction.Y = distance / cosAngle;
float velocity = Mathf.Sqrt((distance * Physics.gravity.magnitude) /
(2 * cosAngle * cosAngle * (tanAngle - hOverd)));
return velocity * direction.normalized;
}
I think you use Raycast wrongly. According to the doc, the second argument is the direction, not the destination:
if (Physics.Raycast(player.transform.position,transform.position, out hitInfo))
Should be
if (Physics.Raycast(transform.position, player.transform.position -
transform.position, out hitInfo))
That would explain why it is not firing at the right moment and why the direction is not accurate (since hitInfo is wrong)

Unity: Special movement for game

I'm writing movement for my space game and spaceship object (player) with mouse cursor.
Currently have following code:
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
public class Move : MonoBehaviour {
public float speed = 1.5f;
public float rotationSpeed = 90f;
public float rotPrecision = 0.1f;
public float movePrecision = 0.1f;
private Vector3 pos;
private Quaternion qTo;
void Start () {
pos = transform.position;
qTo = transform.rotation;
}
void Update () {
if (!EventSystem.current.IsPointerOverGameObject())
{
if (Input.GetMouseButtonDown(0) || Input.GetMouseButton(0))
{
pos = Input.mousePosition;
pos.z = transform.position.z - Camera.main.transform.position.z;
pos = Camera.main.ScreenToWorldPoint(pos);
}
var dir = pos - transform.position;
qTo = Quaternion.LookRotation(Vector3.forward, pos - transform.position);
if (Quaternion.Angle(transform.rotation, qTo) >= rotPrecision) //just set your own precision
transform.rotation = Quaternion.RotateTowards(transform.rotation, qTo, Time.deltaTime * rotationSpeed);
if (Vector3.Distance(transform.position, pos) > movePrecision) // 0.1f
transform.Translate(Vector3.up * speed * Time.deltaTime);
}
}
}
But there i have the problem with the movement precision and rotation when the point is too close to player (have infinite loop).
The idea of this movement system described with the following image:
(Player actor is green, path is gray, and destination point is red).
I hope that somebody could help me w/ that.
Thank you!
If I understand your question correctly, the problem is that the player's movement never stops as the code can't reach a finishing point.
To solve this you can add an acceptable precision margin.
So calculate if the difference between the rotation you wish or the movement you wish, and the players actual rotation/position, is less than a given variable, for example less than 0.05%.
That way you could allow the program to know that if it's just within 0.05% precision, then it's okay for it to stop moving.
Otherwise, if the program never reaches a complete and perfect rotation and position, it will continue to adjust endlessly due to slight mathematical imprecision in the calculations and movement pattern.

Building an orthographic camera for Unity3D, how can I keep four specific targets in sight?

I have a 2D Orthographic camera for a game that is built similarly to Tennis. I've been working out the code for this, and I think I'm only part of the way so far. At the moment... it... sort-of keeps the two players in frame, with the frame leading more towards the human player - Player One. However, it also has a tendency to drop below the ground level - especially when it zooms out to keep the targets in view. There are four specific targets: The Ground, Ball, Player One, and Player Two.
The ground should always be at the 'bottom', otherwise when the camera goes below ground it shows sky - not really a desirable effect. This is the code I've developed so far... the two players are effectively paddles, but it only shows the center between them:
using UnityEngine;
using System.Collections;
public class CameraController : MonoBehaviour {
// Moving Camera, This Camera tries to follow Player One, Two, and Ball //
public static CameraController Instance;
public Transform PlayerOne;
public Transform PlayerTwo;
public Transform Ball;
public bool Ready = false;
private float MinX = -46.0f;
private float MaxX = 46.0f;
private float MinY = 12.0f;
private float MaxY = 35.0f;
private float LimitFromPlayerX = 20.0f;
private float LimitFromPlayery = 20.0f;
private float DistanceToGround = 0.0f;
private float DistanceFromCenter = 2.0f;
private float Height = 4.0f;
private float Damping = 5f;
private Vector3 EstimatedCameraPosition = Vector3.zero;
private Vector3 WantedPosition = Vector3.zero;
void Awake()
{
Instance = this;
}
public void SetCameraPosition()
{
Vector3 PlayerPosistion = PlayerOne.position;
PlayerPosistion.z = -10.10f;
transform.position = PlayerPosistion;
}
// Update is called once per frame
void FixedUpdate () {
if (Ready) {
Vector3 PlayerPosistion = PlayerOne.position;
PlayerPosistion.z = -10.10f;
Vector3 CameraPosition = transform.position;
CameraPosition.z = -10.10f;
// Get the Distance from the Player to the Ball //
Vector3 WantedPosition = PlayerTwo.transform.position - -PlayerOne.transform.position;
float WPMag = Mathf.Abs(WantedPosition.magnitude);
WPMag = Mathf.Clamp(WPMag, 20, 40);
Debug.Log(WPMag);
Camera.main.orthographicSize = WPMag;
transform.position = Vector3.Lerp(CameraPosition, WantedPosition, Damping * Time.deltaTime);
}
}
void LateUpdate()
{
Vector3 Posit = transform.position;
Posit.x = Mathf.Clamp (Posit.x, MinX, MaxX);
Posit.y = Mathf.Clamp (Posit.y, MinY, MaxY);
transform.position = Posit;
}
}
WPMag was my attempt to zoom out and match the players at least, but so far it's only partially working.
To keep all three objects in view, you'll want to focus the camera on the midpoint or "average" position of the three objects. Getting the midpoint of three objects works just like getting the midpoint of two objects: (PlayerOne.position + PlayerTwo.position + Ball.position) / 3.0f
You'll then want to set orthographic size to the furthest distance from the midpoint of the three tracked objects. This will ensure that all three objects stay in the frame.
Finally, to keep the camera from showing underground skies, you should enforce a lower limit for the camera's Y position. The orthographic size is half the vertical height of the viewport, so you'd use CameraPosition.y = Mathf.Max(CameraPosition.y, groundHeight + camera.main.orthographicSize)

Categories