i was working on a simple car controller script and a humvee model i downloaded. the script works as its supposed to but the car wheels are out of place and are spinning crazy. i tried searching everywhere but didn't found any solution.
here's the code:
using UnityEngine;
public class GroundVehicleController : MonoBehaviour {
public void GetInput()
{
m_horizontalInput = Input.GetAxis("Horizontal");
m_verticalInput = Input.GetAxis("Vertical");
}
private void Steer()
{
m_steeringAngle = maxSteerAngle * m_horizontalInput;
frontDriverW.steerAngle = m_steeringAngle;
frontPassengerW.steerAngle = m_steeringAngle;
}
private void Accelerate()
{
frontDriverW.motorTorque = m_verticalInput * motorForce;
frontPassengerW.motorTorque = m_verticalInput * motorForce;
}
private void UpdateWheelPoses()
{
UpdateWheelPose(frontDriverW, frontDriverT);
UpdateWheelPose(frontPassengerW, frontPassengerT);
UpdateWheelPose(rearDriverW, rearDriverT);
UpdateWheelPose(rearPassengerW, rearPassengerT);
}
private void UpdateWheelPose(WheelCollider _collider, Transform _transform)
{
Vector3 _pos = _transform.position;
Quaternion _quat = _transform.rotation;
_collider.GetWorldPose(out _pos, out _quat);
_transform.position = _pos;
_transform.rotation = _quat;
}
private void FixedUpdate()
{
GetInput();
Steer();
Accelerate();
UpdateWheelPoses();
}
private float m_horizontalInput;
private float m_verticalInput;
private float m_steeringAngle;
public WheelCollider frontDriverW, frontPassengerW;
public WheelCollider rearDriverW, rearPassengerW;
public Transform frontDriverT, frontPassengerT;
public Transform rearDriverT, rearPassengerT;
public float maxSteerAngle = 30;
public float motorForce = 50;
}
The error on Unity console is telling you the problem:
UnassignedReferenceException: The variable frontDriverW of
groundVehicleController has not been assigned. You problably need to
assign the frontDriverW variable of the GroundVehicleController script
in the inspector.
Well, when your script runs, it tries to access the field frontDriverW, but since it was never assigned a value, it throws the mentioned exception.
You need to go in the inspector for the object that contains the GroundVehicleController script and add a value for the frontDriverW field. While you're there, make sure all the other fields have values too, because if they don't, those will also cause the same error.
From the pictures you've show us, it is not possible to know in which object you added the GroundVehicleController script, but just check all of the Humvee objects until you find it in the inspector. My guess is that it will probably be in the object Wheels, or the object Humvee.
a) Check the prefab you've created to see if these offsets are there even on the prefab.
b) You're updating the wheel pose with global positions and rotations. this is probably what is causing the offsets. try setting the pose local, or just make the wheel meshes follow whatever the wheel colliders are doing, make sure they're all under the same co-ordinate space. Why not just child each individual wheel to it's corresponding wheel collider? theyre just meshes after all.
c) You haven't assigned your wheel meshes at all in your script.
c) play around with different mass values on the RigidBody (keep it heavy), and also consider attaching a physic material to your wheel colliders to reduce slip and spinning (If the car controller already doesnt have a slip setting)
Related
I am using the Transform function in Unity inorder to rotate my gun in my 2d top down shooter when the mouse is aimed in a certain direction. However, the problem is that Unity returns one of my functions as Null and therefore says that the game object can't be found. I have done some debugging and found that my Debug.Log(aimTransform); come back as null.
The code goes like this;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerAimWeapon : MonoBehaviour
{
public static Vector3 GetMouseWorldPosition()
{
Vector3 vec = GetMouseWorldPositionWithZ(Input.mousePosition, Camera.main);
vec.z = 0f;
return vec;
}
public static Vector3 GetMouseWorldPositionWithZ()
{
return GetMouseWorldPositionWithZ(Input.mousePosition, Camera.main);
}
public static Vector3 GetMouseWorldPositionWithZ(Camera worldCamera)
{
return GetMouseWorldPositionWithZ(Input.mousePosition, worldCamera);
}
public static Vector3 GetMouseWorldPositionWithZ(Vector3 screenPosition, Camera worldCamera)
{
Vector3 worldPosition = worldCamera.ScreenToWorldPoint(screenPosition);
return worldPosition;
}
private Transform aimTransform;
private void Start()
{
Debug.Log(aimTransform);
aimTransform = transform.Find("Aim");
}
private void Update()
{
Vector3 mousePosition = GetMouseWorldPosition();
Vector3 aimDirection = (mousePosition - transform.position).normalized;
float angle = Mathf.Atan2(aimDirection.y, aimDirection.x) * Mathf.Rad2Deg;
aimTransform.eulerAngles = new Vector3(0, 0, angle);
Debug.Log(angle);
}
}
The main problem I think is below.
private Transform aimTransform;
private void Start()
{
Debug.Log(aimTransform); <--------------- This comes back as Null which is the problem.
aimTransform = transform.Find("Aim"); <-------- Aim is just the object in my game (Gun)
}
I have spent some time figuring out how to Initialize the object and then call it using the Find function so it doesn't come back as Null but I haven't been successfull.
Once unity can find the Object, it should work fine with the mouse pointer code I have further below.
As said before, I debugged the Null from the aimTransform and it returns as null. I'm not sure how to fix it and allow Unity to actually find my game object and let it be transformed. I also know that the main issue is that the object hasn't been initialized properly and I don't really know how to do it. Thanks.
Problem in aimTransform field, it's not initialized and you try to get transform with name "Aim" from null field. Transform.Find() search transform by name in it's childs. If you want to find gameobject with name "Aim" you have several ways:
If you have possibility you can serialize field aimTransform and drag and drop reference from Inspector.
You can call GameObject.Find("Aim") to find gameobject by name, but it will work only in case if gameobject with apropriate name exists on your scene.
The correct code would be this:
private void Start()
{
aimTransform = transform.Find("Aim"); // <-- assuming you don't mean
// GameObject.Find() at which point
// you'd need to change the type of
// aimTransform as well :)
Debug.Log(aimTransform);
}
aimTransform is not yet "set", therefore, it's null. First assign it, then you can log it.
I've been trying to fix this one bug in my code for over 7 hours now, upon being teleported, the movement controls cease to function, the mouse works fine, you can look around, but you can't move around.
I wanted to set up some simple code that would teleport the player to a "checkpoint" upon achieving a negative or null y level. I was doing this for a parkour based game, if the player fell off the platform they would have to start over, but after teleporting, it becomes impossible to move as I'm sure I have already said. My code is pretty simple:
public class Main : MonoBehaviour
{
float Fall;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Vector3 Checkpoint = new Vector3 (0,3,0);
GameObject Player = GameObject.FindGameObjectWithTag("Player");
Fall = GameObject.FindGameObjectWithTag("Player").transform.position.y;
if (Fall<-4)
{
Player.transform.position = Checkpoint;
}
}
}
You would think that this would just simply change the coordinates of the player, but I think this might be screwing with the FPSController script.
I am using Unity3d, with Standard Assets imported, All of the code is in C#.
Instead of checking the Y value of your character, I would instead place a death collider under the map. Make this a trigger and if the player touches this trigger, then teleport them back. Nothing with your code should screw with the FPS controller so it might be something else. I would also highly recommend not using a FindGameObjectWithTag in the Update() method as it is extremely expensive to use this every frame, especially twice. If you would rather keep the Update() Y component of the position check, please rewrite the code to something like this:
public class Main : MonoBehaviour
{
// assign this object of your player in the inspector - it stores the reference to reuse
// instead of grabbing it every frame
[SerializeField] private Transform playerTransform = null;
// make this a variable as it is not changing - might as well make this const too
private Vector3 checkpoint = new Vector3(0, 3, 0);
// constant value of what to check for in the Y
private const int FALL_Y_MARKER = -4;
// Update is called once per frame
void Update()
{
if (playerTransform.position.y < FALL_Y_MARKER)
{
playerTransform.position = checkpoint;
}
}
}
With your current code, there should be nothing breaking your input/movement, but with that said, we can not see your input/movement code. All the above snippet does is check if the Y component of the player objects position is below a certain value, and if it is, it sets the position to a new vector. Can you post a bit more movement code or somewhere else it can go wrong that you think is the issue?
I'm working on a small game: I want all GameObjects to be pulled into the middle of the screen where they should collide with another GameObject.
I tried this attempt:
using UnityEngine;
using System.Collections;
public class Planet : MonoBehaviour
{
public Transform bird;
private float gravitationalForce = 5;
private Vector3 directionOfBirdFromPlanet;
void Start ()
{
directionOfGameObjectFromMiddle = Vector3.zero;
}
void FixedUpdate ()
{
directionOfGameObjectFromMiddle = (transform.position-bird.position).normalized;
bird.rigidbody2D.AddForce (directionOfGameObjectFromMiddle * gravitationalForce);
}
}
sadly I can't get it to work. I've been told that I have to give the object that is being pulled another script but is it possible to do this just with one script that is used on the object that pulls?
So first you have a lot of typos / code that doesn't even compile.
You use e.g. once directionOfBirdFromPlanet but later call it directionOfGameObjectFromMiddle ;) Your Start is quite redundant.
As said bird.rigidbody2D is deprecaded and you should rather use GetComponent<Rigidbody2D>() or even better directly make your field of type
public Rigidbody2D bird;
For having multiple objects you could simply assign them to a List and do
public class Planet : MonoBehaviour
{
// Directly use the correct field type
public List<Rigidbody2D> birds;
// Make this field adjustable via the Inspector for fine tuning
[SerializeField] private float gravitationalForce = 5;
// Your start was redundant
private void FixedUpdate()
{
// iterate through all birds
foreach (var bird in birds)
{
// Since transform.position is a Vector3 but bird.position is a Vector2 you now have to cast
var directionOfBirdFromPlanet = ((Vector2) transform.position - bird.position).normalized;
// Adds the force towards the center
bird.AddForce(directionOfBirdFromPlanet * gravitationalForce);
}
}
}
Then on the planet you reference all the bird objects
On the birds' Rigidbody2D component make sure to set
Gravity Scale -> 0
you also can play with the Linear Drag so in simple words how much should the object slow down itself while moving
E.g. this is how it looks like with Linear Drag = 0 so your objects will continue to move away from the center with the same "energy"
this is what happens with Linear Drag = 0.3 so your objects lose "energy" over time
I'm working on a project in Unity that involves regions that teleport any non-static object from one to the paired. That part's fine, but for convenience, I'm trying to write a part of the script that will resize one object if its pair is resized, such that they will always be of equal size. And so far it works - mostly. The only problem I encounter is when trying to resize through the Transform component - as in, typing in numbers in Inspector, or using the value sliders on X or Y or Z. The handles work fine. It's not a big deal, I suppose, but if I could figure out why this isn't working, so I can learn what to do in the future, I'd be very glad. Here's the code:
[ExecuteInEditMode]
public class TransferRegion : MonoBehaviour {
// Unrelated code...
public bool scaleManuallyAltered {
get; private set;
}
[SerializeField]
private TransferRegion pair;
private Vector3 scale;
// Called whenever the scene is edited
void Update () {
if (scale != gameObject.transform.localScale) {
scaleManuallyAltered = true;
scale = gameObject.transform.localScale;
}
if (pair && scaleManuallyAltered && !pair.scaleManuallyAltered) {
pair.transform.localScale = scale;
}
}
// Called AFTER every Update call
void LateUpdate () {
scaleManuallyAltered = false;
}
// Unrelated code...
}
If anyone can see some major logical failure I'm making, I'd like to know. If my code's a bit hard to understand I can explain my logic flow a bit, too, I know I'm prone to making some confusing constructs.
Thanks folks.
If you want one object to be the same scale as another, why not just simplify your code by setting the scale of the re sizing game object, directly to the scale of the game object it is based off of? For example, this script re sizes an object to match the scale of its pair while in edit mode:
using UnityEngine;
using UnityEditor;
using System.Collections;
[ExecuteInEditMode]
public class tester : MonoBehaviour
{
public Transform PairedTransform;
void Update()
{
if (!Selection.Contains(gameObject))
{
gameObject.transform.localScale = PairedTransform.localScale;
}
}
}
I tested this on two cubes in my scene. I was able to resizing using gizmos as well as manually typing in numbers to the transform edit fields in the inspector.
Edit: By taking advantage of Selection you can apply the scale change only to the object in the pair that is not selected in the hierarchy. This way the pairs wont be competing with each other to re scale themselves.
So I figured it out.
I'm not sure what was wrong with my original code, but eventually I decided to slip into the realm of good old handy events:
[ExecuteInEditMode]
public class TransferRegion : MonoBehaviour {
//...
[SerializeField]
private UnityEvent rescaled;
//...
void Update() {
if (scale != gameObject.transform.localScale) {
scale = gameObject.transform.localScale;
rescaled.Invoke();
}
}
//...
public void OnPairRescaled() {
gameObject.transform.localScale = pair.transform.localScale;
scale = gameObject.transform.localScale;
}
}
And just set the OnPairRescaled event to be the listener for the paired object's rescaled event.
Ta-da!
Within my 2d game i wsih to have a number of OnGui elements there for the user to select, however, the cursor that im using is another ongui element(using kinect to navigate) is this possible by any chance, at the moment im using planes but i will be zooming in and out of the camera so ill essentially need them attatched to the screen. Any ideas, suggestions or workarounds.
THis is currently my cursor.
using UnityEngine;
using System;
using System.Collections;
public class PillarAgent : MonoBehaviour {
public SkeletonWrapper sw;
public Vector3 distance;
public float progress =0f;
public Texture2D cursor;
public Texture2D load;
public Camera mainCam;
public float startTime;
private int roundedRestSecounds;
// Use this for initialization
float differencex = 0;
float differencey = 0;
void Start () {
distance =new Vector3(0f,0f,0f);
}
float translate(float value, float leftMin, float leftMax,
float rightMin,float rightMax)
{
float leftSpan = leftMax - leftMin;
float rightSpan= rightMax - rightMin;
float valueScaled = (value-leftMin)/(leftSpan);
return rightMin+(valueScaled * rightSpan);
}
// Update is called once per frame
void Update () {
if (sw.pollSkeleton())
{
distance.x=sw.bonePos[0,0].x - sw.bonePos[0,7].x;//5 is left shoulder
distance.y=sw.bonePos[0,0].y -sw.bonePos[0,7].y;
differencex=translate(distance.x,.6f,0,0,Screen.width);
differencey=translate(distance.y,-.5f,0,0,Screen.height);
//Debug.Log();
float width = sw.bonePos[0,5].x+ sw.bonePos[0,9].x;
float height =sw.bonePos[0,4].y- sw.bonePos[0,0].y;
float heightdiv= (height/2)+sw.bonePos[0,0].y;
}
}
void OnGUI() {
//left top width height
Rect r = new Rect(differencex,differencey,80,50);
GUI.Label(r,cursor);
GUI.BeginGroup(new Rect(differencex,differencey+50,50*Mathf.Clamp01(progress),15));
//Debug.Log(progress);
GUI.DrawTexture(new Rect(0,0,50,50),load);
GUI.EndGroup();
transform.position =mainCam.ScreenToWorldPoint(new Vector3(differencex,Screen.height-differencey,50));
//mainCam.fieldOfView()
}
void OnCollisionStay(Collision Other)
{
startTime+=Time.deltaTime;
if(Other.gameObject.GetComponent(typeof(TextControl)))
{
roundedRestSecounds=Mathf.CeilToInt(Time.time);
progress = Time.time *0.2f;
CurrentState=true;
}
else if(Other.gameObject.tag==("Scalpal")){
progress = startTime *0.5f;
//scallpall activated
//
}
}
void OnCollisionExit(Collision Other){
startTime =0f;
progress =0f;
}
public Boolean CurrentState{get;set;}
}
The next class is essentially the class in which i pick up my tools, currently this code doesnt work(not sure why), but what i wish to do is select some tools which show up on the screen so that i can use them,for e.g pick up paint brush start painting bricks or what not. at the moment i have my tools on a plane, i wish to always have them on the screen at all times when the camera moves.
using UnityEngine;
using System.Collections;
public class SelectTool : MonoBehaviour {
public Tools tools;
public float startTime;
public bool ScalpalSelected;
public GameObject selectedTool;
void Start()
{
tools = this.GetComponent<Tools>(); //in order to use this tools muyst be attached to the game object
//this is essentially saying with regards to this game object get the component named tools
}
void update()
{
}
void OnCollisionStay(Collision Other)
{
startTime +=Time.deltaTime;
if(startTime >5f){
if(Other.collider.tag==("Scalpal"))
{
selectedTool = Other.collider.gameObject;
Debug.Log(selectedTool+" What in gods good name is:" +tools.utilities[0]);
}
else {
selectedTool=null;
}
if(selectedTool){
for(int i=0;i<tools.utilities.Length;i++)
{
}
}
ScalpalSelected=true;
renderer.material.color = Color.yellow;
}
}
void OncollisionStay(Collision other){
startTime = 0f;
}
}
From the comment section to the question I will assume that you want to know how to do this:
"... you want your plane objects to move together with the camera ..." - Steven Mills
"thank you #StevenMills Do you have any example of how this can be done?" j bel
While the answer provided in the comments is to just manually add the planes as children of the camera (a very straightforward, manual approach), I will give another way to do this through scripting (in light of maybe this will help someone else out disregarding the likeliness of someone using this solution).
The idea of this is to create a script (thus following being attached to the MainCamera) that will search through all of the GameObject in the Object Hierarchy with the method GameObject.FindGameObjectsWithTag. Once we have all our GameObject with the associated Tag, we can then loop through the array and parent the attached script's GameObject to each.
public class ParentGameObjects : MonoBehaviour {
//The tag to search for on all game objects in the hierarchy
public String objectTag;
//The game objects that we will parent the main camera to
private GameObject[] children;
//It's not necessary to store references to the children but if you want to modify them at some point you will be able to
void Start() {
//Find all game objects with the tag we want
children = GameObject.FindGameObjectsWithTag(objectTag);
//Loop through all of the game objects found and parent this object's transform
for(int i = 0; i < children.Length; i++) {
children[i].transform.parent = transform;
}
}
}
Now, there are a few things you have to do for this script to work:
Attach this script to any GameObject that you want to parent other objects to.
In the Inspector of the GameObject that the script is attached to, enter in the name of the Tag you want to use.
For all GameObject(s) in the Hierarchy that should be added as children, assign the same Tag.
Of course there are other things you can do like, for example, instead of only searching for one Tag be able to search for multiple but that requires a bit (not exactly much) more work. Nonetheless, I hope this will at least be useful information to someone on how parenting works via scripting.