Need help refactoring script to find closest target - find

I have an asteroid field spawned at runtime and droid prefabs the player can release to gather raw material from the asteroids. Everything works but the droids go to the furthest part of the asteroid field to start collecting. I realize I likely need a list of objects to sort through somehow and output the closest.
I suck at coding but managed to get this working by getting a link to the spawned asteroids adding MovementAIRigidbody target to this script & finding one with target = GameObject.Find("AsteroidNew2(Clone)").GetComponent().
This script is based on a GitHub MIT project which is using Vector3 targetPos; I believe to select the target position. Hope this makes sense to a kind soul out there.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UnityMovementAI
{
public class OffSetPursuitUnityMy : MonoBehaviour
{
MovementAIRigidbody target;
public Vector3 offset;
public float groupLookDist = 1.5f;
SteeringBasics steeringBasics;
OffsetPursuit offsetPursuit;
Separation separation;
NearSensor sensor;
void Start()
{
steeringBasics = GetComponent<SteeringBasics>();
offsetPursuit = GetComponent<OffsetPursuit>();
separation = GetComponent<Separation>();
target = GameObject.Find("AsteroidNew2(Clone)").GetComponent<MovementAIRigidbody>();
sensor = GameObject.Find("SeparationSensor").GetComponent<NearSensor>();
}
void LateUpdate()
{
Vector3 targetPos;
Vector3 offsetAccel = offsetPursuit.GetSteering(target, offset, out targetPos);
Vector3 sepAccel = separation.GetSteering(sensor.targets);
steeringBasics.Steer(offsetAccel + sepAccel);
/* If we are still arriving then look where we are going, else look the same direction as our formation target */
if (Vector3.Distance(transform.position, targetPos) > groupLookDist)
{
steeringBasics.LookWhereYoureGoing();
}
else
{
steeringBasics.LookAtDirection(target.Rotation);
}
}
}
}

Related

Why does exporting to Unity WebGL change the speed of objects in my game?

GOAL
So I have a space-invaders type game I have made to practise unity and I want to upload it to Itch.io as I have done in the past.
This is a clip of the game.
I switched platforms to WebGL in Build Settings etc, and everything worked fine in Unity.
PROBLEM
However when I built it and uploaded the zip file to Itch.io, the aliens are now a lot faster than usual. (Be aware there may be other things that have changed, I just haven't been able to get to them since it is extremely hard).
CODE
Alien movement:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class AleenController : MonoBehaviour
{
Rigidbody2D rigidbody;
public float speed = 10f;
ScoreController scoreController;
AudioSource aleenDie;
void Start()
{
scoreController = GameObject.Find("Canvas/Score").GetComponent<ScoreController>();
rigidbody = GetComponent<Rigidbody2D>();
aleenDie = GameObject.Find("Main Camera/AleenDie").GetComponent<AudioSource>();
}
void Update()
{
rigidbody.MovePosition(transform.position + new Vector3 (0, -1, 0) * speed * Time.deltaTime);
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "laser")
{
aleenDie.Play();
scoreController.score += 1;
Destroy(gameObject);
}
}
}
NOTE
I am really struggling to find out what is wrong here, since everything is fine in unity. If you do need more details just leave a comment.
If you use physics you should
not set or get values via Transform at all
do things in FixedUpdate
In general though in your case instead of using
void Update()
{
rigidbody.MovePosition(transform.position + new Vector3 (0, -1, 0) * speed * Time.deltaTime);
}
at all simply set the velocity once like e.g.
void Start ()
{
...
rigidbody.velocity = Vector3.down * speed;
}
The rest seems to depend a bit on your screen size. Looks like you are moving your elements in pixel space -> the smaller the display the less pixel distance between the top and bottom -> the faster elements seem to travel.

calculate dynamic stoppingDistance in unity

For control NammeshAgent and stop after reach to destination i used OnAnimatorMove(). but when it reached to destination, run animation won't stop.
I used BlendTree for control animations. so this is my code:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
// private vriables
private Animator anim;
private NavMeshAgent navAgent;
public Transform target;
private float speed;
void Start()
{
anim = GetComponent<Animator>();
navAgent = GetComponent<NavMeshAgent>();
}
void Update()
{
MoveToDestination();
}
private void MoveToDestination()
{
// Move to Target
if (Vector3.Distance(transform.position, target.position) > navAgent.stoppingDistance)
{
speed = 1f;
navAgent.SetDestination(target.position);
}
else
{
speed = 0;
}
anim.SetFloat("Speed", speed, 0.1f, Time.deltaTime);
}
private void OnAnimatorMove()
{
navAgent.speed = (anim.deltaPosition / Time.deltaTime).magnitude;
}
NOTE: when NavmeshAgent is reached to destination, speed value in NavmeshAgent Component is greater than 1. i seen this with print below line.
Vector3.Distance(transform.position, target.position)
NOTE: I set stoppingDistance to 0 in NavMesh Component.
So i need calculate stoppingdistance dinamically between player and target.
Some minor problems with your code:
you set speed = 0; but I don't see speed anywhere defined, except for navAgent.speed - make sure you use the correct/intended variable!
Vector3.Distance(transform.position, target.position) > navAgent.stoppingDistance is basically distance > 0 - replace stoppingDistance with 0.2f or some other small value. The distance will almost never be exactly zero, therefore (almost) always > 0.
Some thoughts:
You could set the speed of your animations to the agent speed, so the animation would "run" but not actually move if the player won't move. Also it would scale with acceleration automatically. Maybe your blendTrees would work better then, too.
Why did you put stopping distance to 0?
problem was in this part and i removed it.
private void OnAnimatorMove()
{
navAgent.speed = (anim.deltaPosition / Time.deltaTime).magnitude;
}
and also i set stoppingDistance to none zero.

How do I set the view angle of a sphere cast and also read the angle at which the objects are present in front of it?

this is what i want to achieve
I am currently trying to build a RADAR sensor on unity. I am currently using spherecast. How do i set the view angle of the sphere cast and also how do i read the angle at which an object is present in front of it.
What i have used now is Vector3.angle but this shows 160 degrees if the object is directly infront of the radar instead it should be showing 90 degrees.
Ill paste the code that i have implemented below
Any guidance is appreciated.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class spherecast : MonoBehaviour
{
Rigidbody rb;
public List<GameObject> CurrentHitObjects = new List<GameObject>();
//public GameObject curobject;
public float radius;
public float maxdist;
public LayerMask layermask;
public float velocity;
public Time deltatime;
public Vector3 previous;
private Vector3 origin;
private Vector3 direction;
private float hitdist;
// Use this for initialization
void Start()
{
foreach (GameObject cur in CurrentHitObjects)
{
previous = cur.transform.position;
}
}
// Update is called once per frame
void Update()
{
origin = transform.position;
direction = transform.forward;
hitdist = maxdist;
CurrentHitObjects.Clear();
RaycastHit[] hits = Physics.SphereCastAll(origin, radius, direction, maxdist, layermask, QueryTriggerInteraction.UseGlobal);
foreach (RaycastHit hit in hits)
{
Plane[] planes = GeometryUtility.CalculateFrustumPlanes(Camera.main);
if (GeometryUtility.TestPlanesAABB(planes, hit.collider.bounds))
{
float angle = Vector3.Angle(transform.forward, hit.point.normalized);
float degree = Mathf.Acos(angle) * Mathf.Rad2Deg;
Vector3 pos = hit.point;
Debug.Log(hit.collider.name + "position =" + pos);
CurrentHitObjects.Add(hit.transform.gameObject);
hitdist = hit.distance;
Debug.Log(hit.transform.name + "Distance ="+ hitdist);
Debug.Log(hit.collider.name + "Angle = " + angle);
velocity = ((hit.transform.position - previous).magnitude) / Time.deltaTime;
previous = hit.transform.position;
Debug.Log(hit.transform.name + "Velocity =" + velocity);
}
else
{
return ;
}
}
}
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Debug.DrawLine(origin, origin + direction * hitdist);
Gizmos.DrawWireSphere(origin + direction * hitdist, radius);
}
}
As far as I can tell your code doesn't do anything. My first tip would be to remove all of your commented out code, but after that here is why your code does nothing at all:
You pass an array of objects to your script. Fine so far.
You take this entire array of objects 'CurrentHitObjects' and pass the transform.position of every single object to a single vector3. This means that all the values are overwritten except for the last one. This would be a big problem if you were trying to find the position of every single object. This would instead require vector3[]. But there is another bigger problem.
'previous', which holds transform.position of the objects is not used anywhere. So you are not actually finding the location of anything.
You use start() (which only runs once by the way) to iterate through your object array, but then you clear, CurrentHitObjects.Clear();, right at the beginning of update() (which runs many times per second by the way). The problem here, is that if you hoped to use CurrentHitObjects for anything in your code, you can't because you have wiped it before you even start doing anything with it.
Your raycast[] is shooting towards nothing. Seems to me like it just shoots forward.
You are finding the angle between the forward direction and the forward direction?
Honestly there are a lot of major problems with this code. I don't mean to be harsh, but it looks like you copy and pasted someone else's code and don't know how to use it. This needs a complete rework. If you know how to code I would throw it out and start over again. See my comment on your answer for a better way to do what you want.
If you don't know how to code, you should not be asking for freebie working code on stackoverflow. Try a unity forum instead. If you are trying to get better, see my above comments.

2D raycasting in unity doesn't work

So here is the code I've been working on:
using System.Collections.Generic;
using UnityEngine;
public class MovePlayer : MonoBehaviour
{
public float sidewaysForce;
public float jumpingForce;
public Rigidbody2D playerRigidbody;
public Transform playerTransform;
private Vector2 forceToAdd;
private bool onGround;
private LayerMask mask = 8;
private void Start()
{
forceToAdd = new Vector2(0, 0);
}
void FixedUpdate()
{
// Basic left/right movement
forceToAdd.x = 0;
forceToAdd.y = 0;
if (Input.GetKey(KeyCode.A))
{
forceToAdd.x = -sidewaysForce;
}
else if (Input.GetKey(KeyCode.D))
{
forceToAdd.x = sidewaysForce;
}
if (Input.GetKey(KeyCode.Space) && onGround == true)
{
forceToAdd.y = jumpingForce;
onGround = false;
}
var something = Physics2D.Raycast(playerTransform.position, Vector2.down, 200000f, mask.value);
Debug.Log(something.collider);
playerRigidbody.AddForce(forceToAdd, ForceMode2D.Impulse);
}
}
And my issue is this: No matter how far I move the player upwards, whether it be to (0,5) or (0, 2044), it will still print out "Hit ground."
I've tried both Physics and Physics2D, I've tried LayerMasking, everything, and yet it won't work. I'm a beginner to Unity btw.
EDIT: I printed Physics2D.Raycast(playerTransform.position, Vector3.down, 2f).colliderand I ended up with "Player," not "Ground," any way to fix this? I tried increasing the distance to 20 and to 2000, but it yields "Player," still. Any ideas?
EDIT #2: I also tried LayerMasks, didn't work still.
The issue is that you are parsing Physics2D.Raycast the wrong parameters. As you can see in the Unity docs, the function takes a Vector2 and not a Vector3.
https://docs.unity3d.com/ScriptReference/Physics2D.Raycast.html
Also for testing Raycasts in Unity, always set the distance parameter to be Mathf.Infinity until you have designed the solution completely. This will save you a headache in debugging. It is also best practice to add a comment explaining that it is a temporary distance value and that it should be changed later.
When posting your questions in the future on forums, ensure that you properly explain your questions as I really had to look through your code to find what the purpose was.
I am going to refrain from commenting about your code design as this is stack overflow and not reddit but I teach programming at university and would love to help if you are open to leaning :)

How to modify the car controllers to do it more Arcade and less realistic in Unity 5 3D

I'm using the Unity 5 Car Asset coming with the Standard Assets. Controls are very hard. The car flips easily even if you are going at quite slow speed.
I have done some "tricks" I have found on the Internet like increasing the mass of the rigid body to 1500, adding the Stabilizer bars (A.K.A. anti-roll bars) script to the car, and setting the gravity center of the car in a fake perfect center. I have included the last versions of those scripts above.
I don't want to simulate perfect physics. I want a fun car easy to ride. Is it possible with Unity?
Script: gravity center of the car in a fake perfect center
using UnityEngine;
using System.Collections;
public class carflipfix : MonoBehaviour {
// Use this for initialization
void Start () {
GetComponent<Rigidbody>().centerOfMass = new Vector3(0, -1, 0);
}
}
Script: stabilizer bars (A.K.A. anti-roll bars).
using UnityEngine;
using System.Collections;
public class AntiRollBar : MonoBehaviour {
public WheelCollider wheelL;
public WheelCollider wheelR;
public float antiRollVal = 5000f;
// Update is called once per frame
void Update () {
WheelHit hit;
float travelL=1.0f;
float travelR=1.0f;
bool groundedL = wheelL.GetGroundHit(out hit);
if (groundedL){
travelL = (-wheelL.transform.InverseTransformPoint(hit.point).y - wheelL.radius) / wheelL.suspensionDistance;
}
bool groundedR = wheelR.GetGroundHit(out hit);
if (groundedR){
travelR = (-wheelR.transform.InverseTransformPoint(hit.point).y - wheelR.radius) / wheelR.suspensionDistance;
}
float antiRollForce = (travelL - travelR) * antiRollVal;
if (groundedL)
GetComponent<Rigidbody>().AddForceAtPosition(wheelL.transform.up * -antiRollForce,
wheelL.transform.position);
if (groundedR)
GetComponent<Rigidbody>().AddForceAtPosition(wheelR.transform.up * antiRollForce,
wheelR.transform.position);
}
}
If we remove the Rigidbody component, we won't be using the Unity physics. Then, we could move the car as we wish getting the input (from the keyboard, gamepad...) to multiply it by the current position of the car. It would be something like:
public class Car: MonoBehaviour
{
public void Update() {
// NOTICE THE FOLLOWING LINE OF CODE IS NOT CORRECT. THE CORRECT WAY SHOULD BE SOMETHING SIMILAR THOUGH:
gameObject.transform.position += input * Time.deltaTime * gameObject.transform.position;
}
}