Unity Multiplayer: Reset player position when Y axis is less then -2 - unity3d

i'm having this issue with resetting the players position when the players Y axis is less then the threshold value which is -2.
using UnityEngine;
using UnityEngine.Networking;
public class ResetPlayerPosition : NetworkManager {
public float threshold = -2f;
NetworkIdentity UniquePlayer;
// On button click, it checks the players position and resets the position if values are true
public void ResetPosition () {
UniquePlayer = GameObject.Find("Player").GetComponent<NetworkIdentity>();
var Player = GameObject.FindWithTag("Player");
// Reset player position if the players Y axis is less than -2
if (Player.transform.position.y < threshold) {
Debug.Log("player position has been reset");
Player.transform.position = new Vector3(0, 1, 0);
} else {
Debug.Log("Player position Y is currently at: " + Player.transform.position.y);
}
}
}
My goal is to catch the unique players y position and reset that to 1 if its less then -2. I got it working when you're in the match alone, but as soon as you're more than 1 player in the match, it does weird things because its not pointing to the specific player.
I'm using NetworkManager and its running on localhost. I've attempted my way around this with getting the netID of the player which is unique but can't figure out how to combine this information.
Hope someone is able to point me in the right direction.

Why don't you just use a MonoBehaviour Script and attach it to the player objects?
By this you already have the right Player GameObject and you don't have to find the GameObject with the Tag.

First I would recommend doing some more testing to narrow down how the weird behavior differs on the host system and the client system. This might give some insight into what exactly is going wrong.
Second, I agree with Sebastian that putting a MonoBehaviour on the player prefab could be a better way to go. Something like this should be a surefire solution:
using UnityEngine;
public class PositionReset : MonoBehaviour {
public float threshold = -2;
public float resetHeight = 1;
private void Update() {
if (transform.position.y < threshold) {
// Note, I keep the x and z position the same, as it sounds like that's what you were looking for. Change as needed
transform.position = new Vector3(transform.position.x, resetHeight, transform.position.z);
}
}
}
If putting the behavior on the player prefab itself isn't acceptable for some reason, here is a modified version of your code snippet that might solve the issue:
using UnityEngine;
using UnityEngine.Networking;
public class ResetPlayerPosition : NetworkManager {
public float threshold = -2f;
// On button click, it checks the players position and resets the position if values are true
public void ResetPosition () {
var Players = GameObject.FindGameObjectsWithTag("Player");
foreach(GameObject Player in Players) {
// Reset player position if the players Y axis is less than -2
if (Player.transform.position.y < threshold) {
Debug.Log("player position has been reset");
Player.transform.position = new Vector3(0, 1, 0);
} else {
Debug.Log("Player position Y is currently at: " + Player.transform.position.y);
}
}
}
}
You'll note that instead of retrieving one game object with the player tag, we retrieve all of them, and perform the evaluation against all of them with the foreach loop. This should yield more consistent behavior.
Beyond this, I would look into using a NetworkTransform, which will help keep the positions of players synced across the network for all movements; an essential tool for almost all networked games.

Related

Need help refactoring script to find closest target

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);
}
}
}
}

What kind of math could I use, to reposition my hands, to my gun in Unity?

Hi so I am making a recoil script for my First Person Shooter. I have the gun working pretty well. Here is my script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GunRecoil : MonoBehaviour
{
public Vector3 beforeRecoilRotation, rightBeforeRecoilRotation, leftBeforeRecoilRotation;
//I have a separate script controlling maxRecoilX and recoil
public float maxRecoilX = -0, recoilSpeed = 10, recoil = 0;
[SerializeField]
GameObject leftControl, rightControl, weapon;
public bool once = false;
// Start is called before the first frame update
void Recoiling()
{
//if recoil is present
if (recoil > 0)
{
//make amount of recoil
var maxRecoil = Quaternion.Euler(maxRecoilX, 0, 0);
//move gun's rotation, according to recoil
weapon.transform.localRotation = Quaternion.Slerp(weapon.transform.localRotation, maxRecoil, Time.deltaTime * recoilSpeed);
//subtract recoil by time.
recoil -= Time.deltaTime;
}
else
{
//make sure recoil is now zero
recoil = 0;
//make min recoil, based on starting position
Quaternion minRecoil = Quaternion.Euler(beforeRecoilRotation);
Quaternion minRecoilHandRight = Quaternion.Euler(0, 0, 0);
weapon.transform.localRotation = Quaternion.Slerp(weapon.transform.localRotation, minRecoil, Time.deltaTime * recoilSpeed / 2);
// rightControl.transform.localRotation = Quaternion.Slerp(rightControl.transform.localRotation, minRecoilHandRight, Time.deltaTime * recoilSpeed / 2);
maxRecoilX = 0;
}
}
// Update is called once per frame
void Update()
{
//constantly run Recoiling
Recoiling();
}
}
I also have hands for my gun. I want them to follow the rotation of the gun, to the rotation of my gun.
First I tried just applied the recoil to my hand. The results were close-ish, but not close enough. I used something like
var maxRecoilRight = Quaternion.Euler(maxRecoilX *5f, 0, 0);
rightControl.transform.localRotation = Quaternion.Slerp(weapon.transform.localRotation, maxRecoilRight, Time.deltaTime * recoilSpeed);
Here are the results:
recoil One
I also tried using Fast IK: https://assetstore.unity.com/packages/tools/animation/fast-ik-139972#reviews .
It didn't work, since I am using the parts of the arm in an animation
I also cannot parent the hands to the gun, since I am going to have to replace animations, and it might break my generic rig.
What kind of math could I use, to reposition my hands, to my gun in Unity? Please leave any suggestions for me. Thank you and have a good day/evening.
You could turn off the animation of the hands while the recoil is ongoing, and use an IK solution for that time. Then when the recoil is finished you can turn it back on.

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.

GameObject Follow cursor yet also follows enemies?

I'm making a simple character that follows the player's cursor. What I also want is for when the game object "enemy" appears the character then goes to that location to alert the player. Once the enemy is gone the character continues to follow the cursor like normal. Is there a reason why my script won't work. How else can I paraphrase it?
public class FollowCursor : MonoBehaviour
{
void Update ()
{
//transform.position = Camera.main.ScreenToWorldPoint( new Vector3(Input.mousePosition.x,Input.mousePosition.y,8.75f));
if (gameObject.FindWithTag == "Enemy")
{
GameObject.FindWithTag("Enemy").transform.position
}
if (gameObject.FindWithTag != "Enemy")
{
transform.position = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,Input.mousePosition.y,8.75f));
}
}
}
You are not using FindWithTag correctly, as it is a method that takes a string as parameter you need to use it like this:
GameObject.FindwithTag("Something") as stated in the Unity scripting API
Now to apply this to your code you would need to do the following to set your players position based on wether or not an enemy is found (assuming this script is on your actual player object):
if(GameObject.FindWithTag("Enemy"))
{
//If an enemy is found with the tag "Enemy", set the position of the object this script is attatched to to be the same as that of the found GameObject.
transform.position = GameObject.FindWithTag("Enemy").transform.position;
}
else
{
//when no enemy with the tag "Enemy" is found, set this GameObject its position to the the same as that of the cursor
transform.position = Camera.main.ScreenToWorldPoint( new Vector3(Input.mousePosition.x,Input.mousePosition.y,8.75f));
}
However this code will just snap your player instantly to the position of the found Enemy. If this is not the desired behaviour you could use a function like Vector3.MoveTowards instead to make the player move to it gradually.
This code also has room for optimisation as searching for a GameObject every update frame is not the ideal solution. But for now it should work.
I'm going to code coding all the function for you, I'm not pretty sure about the beavihour of your code, I understand a gameobject will be attached to the mouse position, so not really following....
Vector3 targetPosition;
public float step = 0.01f;
void Update()
{
//if there is any enemy "near"/close
//targetPosition = enemy.position;
//else
//targetPosition = MouseInput;
transform.position = Vector3.MoveTowards(transform.position, targetPosition , step);
}
For the f you can use a SphereCast and from the enemies returned get the closest one.

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;
}
}