Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
This question was closed Apr 16, 2013 at 07:24 AM by AlucardJay for the following reason:

Question is off-topic or not relevant

avatar image
0
Question by lukejaparidze · Apr 16, 2013 at 01:19 AM · c#androidjavascriptguitexture

Android car controls c#

ok, so a while back I made a simple car game for android and put it on the amazon appstore. shortly after I did, my project became corrupt and could not work with it. I brought my project back to life but the physics were all messed up. so I found this C# script called jcar with somewhat good physics, works nicely on a pc build but I want to make an updated version of my app. the problem is I only know javascript and BARELY any c#. I need to add touch controls to this script using gui textures like I did with my old scripts. the thing is I have little to no idea how jcar applies its engine values and stuff like that. could you guys please please help me port this script to android. I have seen a version ported to jave but doesn't really help because the way its setup is ridiculous. I will attatch a copy of the jcar script and a copy of my android control script just for reference (so you can see how the gui textures work). please help me port this to android. thanks Luke

 /**
  * A simple car physics script using wheel colliders.
  * Jaap Kreijkamp [jaap] at [ctrl-j.com.au]
  *
  * orientation should be that front of car is in direction of
  * the 'blue arrow' in Unity, the roof should be in direction of
  * the green angle. Thus with rotation 0, 0, 0, adding 1 to Z
  * will move car 1m forward, adding 1 to Y will move car 1m
  * upward. The wheels should be children of the car object this
  * script is added to and connected to the wheelFL, wheelFR, ...
  * variables.
  *
  * Please modify script and do whatever you like with it,
  * in it's current state it should give a working car,
  * but by no means perfect (or even close) behavior.
  * It's my first attempt and don't really need in my current
  * project so haven't put too much effort into it to perfect
  * it. As often people are looking for help to getting
  * a car working with wheel colliders, I'd appreciate when
  * improvements are posted back on the unity forums.
  *
  * Lastly, thanks to all the people helping me on forums (especially
  * the order of initialisation problem and other example
  * code that helped me much in learning how to do stuff like
  * this).
  */
  
 using UnityEngine;
 using System.Collections;
  
 public enum JWheelDrive {
     Front = 0,
     Back = 1,
     All = 2
 }
  
  
 public class JCar : MonoBehaviour { 
  
     // if connected the controls will block if object not  active
     // (for example steer only if car camera is active).
     public GameObject checkForActive;
  
     public Transform wheelFR; // connect to Front Right Wheel transform
     public Transform wheelFL; // connect to Front Left Wheel transform
     public Transform wheelBR; // connect to Back Right Wheel transform
     public Transform wheelBL; // connect to Back Left Wheel transform
  
     public float suspensionDistance = 0.2f; // amount of movement in suspension
     public float springs = 1000.0f; // suspension springs
     public float dampers = 2f; // how much damping the suspension has
     public float wheelRadius = 0.25f; // the radius of the wheels
     public float torque = 100f; // the base power of the engine (per wheel, and before gears)
     public float brakeTorque = 2000f; // the power of the braks (per wheel)
     public float wheelWeight = 3f; // the weight of a wheel
     public Vector3 shiftCentre = new Vector3(0.0f, -0.25f, 0.0f); // offset of centre of mass
  
     public float maxSteerAngle = 30.0f; // max angle of steering wheels
     public JWheelDrive wheelDrive = JWheelDrive.Front; // which wheels are powered
  
     public float shiftDownRPM = 1500.0f; // rpm script will shift gear down
     public float shiftUpRPM = 2500.0f; // rpm script will shift gear up
     public float idleRPM = 500.0f; // idle rpm
  
     public float fwdStiffness = 0.1f; // for wheels, determines slip
     public float swyStiffness = 0.1f; // for wheels, determines slip
  
     // gear ratios (index 0 is reverse)
     public float[] gears = { -10f, 9f, 6f, 4.5f, 3f, 2.5f };
  
     // automatic, if true car shifts automatically up/down
     public bool automatic = true;
  
     public float killEngineSoundTimeout = 3.0f; // time until engine sound is cut off (in s.)
  
     // table of efficiency at certain RPM, in tableStep RPM increases, 1.0f is 100% efficient
     // at the given RPM, current table has 100% at around 2000RPM
     float[] efficiencyTable = { 0.6f, 0.65f, 0.7f, 0.75f, 0.8f, 0.85f, 0.9f, 1.0f, 1.0f, 0.95f, 0.80f, 0.70f, 0.60f, 0.5f, 0.45f, 0.40f, 0.36f, 0.33f, 0.30f, 0.20f, 0.10f, 0.05f };
  
     // the scale of the indices in table, so with 250f, 750RPM translates to efficiencyTable[3].
     float efficiencyTableStep = 250.0f;
  
     int currentGear = 1; // duh.
  
     // shortcut to the component audiosource (engine sound).
     AudioSource audioSource;
  
     // every wheel has a wheeldata struct, contains useful wheel specific info
     class WheelData {
         public Transform transform;
         public GameObject go;
         public WheelCollider col;
         public Vector3 startPos;
         public float rotation = 0.0f;
         public float maxSteer;
         public bool motor;
     };
  
     WheelData[] wheels; // array with the wheel data
  
     // setup wheelcollider for given wheel data
     // wheel is the transform of the wheel
     // maxSteer is the angle in degrees the wheel can steer (0f for no steering)
     // motor if wheel is driven by engine or not
     WheelData SetWheelParams(Transform wheel, float maxSteer, bool motor) {
         if (wheel == null) {
             throw new System.Exception("wheel not connected to script!");
         }
         WheelData result = new WheelData(); // the container of wheel specific data
  
         // we create a new gameobject for the collider and move, transform it to match
         // the position of the wheel it represents. This allows us to do transforms
         // on the wheel itself without disturbing the collider.
         GameObject go = new GameObject("WheelCollider");
         go.transform.parent = transform; // the car, not the wheel is parent
         go.transform.position = wheel.position; // match wheel pos
  
         // create the actual wheel collider in the collider game object
         WheelCollider col = (WheelCollider) go.AddComponent(typeof(WheelCollider));
         col.motorTorque = 0.0f;
  
         // store some useful references in the wheeldata object
         result.transform = wheel; // access to wheel transform 
         result.go = go; // store the collider game object
         result.col = col; // store the collider self
         result.startPos = go.transform.localPosition; // store the current local pos of wheel
         result.maxSteer = maxSteer; // store the max steering angle allowed for wheel
         result.motor = motor; // store if wheel is connected to engine
  
         return result; // return the WheelData
     }
  
     // Use this for initialization
     void Start () {
         // 4 wheels, if needed different size just modify and modify
         // the wheels[...] block below.
         wheels = new WheelData[4];
  
         // setup wheels
         bool frontDrive = (wheelDrive == JWheelDrive.Front) || (wheelDrive == JWheelDrive.All);
         bool backDrive = (wheelDrive == JWheelDrive.Back) || (wheelDrive == JWheelDrive.All);
  
         // we use 4 wheels, but you can change that easily if neccesary.
         // this is the only place that refers directly to wheelFL, ...
         // so when adding wheels, you need to add the public transforms,
         // adjust the array size, and add the wheels initialisation here.
         wheels[0] = SetWheelParams(wheelFR, maxSteerAngle, frontDrive);
         wheels[1] = SetWheelParams(wheelFL, maxSteerAngle, frontDrive);
         wheels[2] = SetWheelParams(wheelBR, 0.0f, backDrive);
         wheels[3] = SetWheelParams(wheelBL, 0.0f, backDrive);
  
         // found out the hard way: some parameters must be set AFTER all wheel colliders
         // are created, like wheel mass, otherwise your car will act funny and will
         // flip over all the time.
         foreach (WheelData w in wheels) {
             WheelCollider col = w.col;
             col.suspensionDistance = suspensionDistance;
             JointSpring js = col.suspensionSpring;
             js.spring = springs;
             js.damper = dampers;            
             col.suspensionSpring = js;
             col.radius = wheelRadius;
             col.mass = wheelWeight;
  
             // see docs, haven't really managed to get this work
             // like i would but just try out a fiddle with it.
             WheelFrictionCurve fc = col.forwardFriction;
             fc.asymptoteValue = 5000.0f;
             fc.extremumSlip = 2.0f;
             fc.asymptoteSlip = 20.0f;
             fc.stiffness = fwdStiffness;
             col.forwardFriction = fc;
             fc = col.sidewaysFriction;
             fc.asymptoteValue = 7500.0f;
             fc.asymptoteSlip = 2.0f;
             fc.stiffness = swyStiffness;
             col.sidewaysFriction = fc;
         }
  
         // we move the centre of mass (somewhere below the centre works best.)
         rigidbody.centerOfMass += shiftCentre;
  
         // shortcut to audioSource should be engine sound, if null then no engine sound.
         audioSource = (AudioSource) GetComponent(typeof(AudioSource));
         if (audioSource == null) {
             Debug.Log("No audio source, add one to the car with looping engine noise (but can be turned off");
         }
  
     }
  
     void Update() {
         if (Input.GetKeyDown("page up")) {
             ShiftUp();
         }
         if (Input.GetKeyDown("page down")) {
             ShiftDown();
         }
     }
  
     float shiftDelay = 0.0f;
  
     // handle shifting a gear up
     public void ShiftUp() {
         float now = Time.timeSinceLevelLoad;
  
         // check if we have waited long enough to shift
         if (now < shiftDelay) return;
  
         // check if we can shift up
         if (currentGear < gears.Length - 1) {
             currentGear ++;
  
             // we delay the next shift with 1s. (sorry, hardcoded)
             shiftDelay = now + 1.0f;
         }
     }
  
     // handle shifting a gear down
     public void ShiftDown() {
         float now = Time.timeSinceLevelLoad;
  
         // check if we have waited long enough to shift
         if (now < shiftDelay) return;
  
         // check if we can shift down (note gear 0 is reverse)
         if (currentGear > 0) {
             currentGear --;
  
             // we delay the next shift with 1/10s. (sorry, hardcoded)
             shiftDelay = now + 0.1f;
         }
     }
  
     float wantedRPM = 0.0f; // rpm the engine tries to reach
     float motorRPM = 0.0f;
     float killEngine = 0.0f;
  
     // handle the physics of the engine
     void FixedUpdate () {
         float delta = Time.fixedDeltaTime;
  
         float steer = 0; // steering -1.0 .. 1.0
         float accel = 0; // accelerating -1.0 .. 1.0
         bool brake = false; // braking (true is brake)
  
         if ((checkForActive == null) || checkForActive.active) {
             // we only look at input when the object we monitor is
             // active (or we aren't monitoring an object).
             steer = Input.GetAxis("Horizontal");
             accel = Input.GetAxis("Vertical");
             brake = Input.GetButton("Jump");
         }
  
         // handle automatic shifting
         if (automatic && (currentGear == 1) && (accel < 0.0f)) {
             ShiftDown(); // reverse
         }
         else if (automatic && (currentGear == 0) && (accel > 0.0f)) {
             ShiftUp(); // go from reverse to first gear
         }
         else if (automatic && (motorRPM > shiftUpRPM) && (accel > 0.0f)) {
             ShiftUp(); // shift up
         }
         else if (automatic && (motorRPM < shiftDownRPM) && (currentGear > 1)) {
             ShiftDown(); // shift down
         }
         if (automatic && (currentGear == 0)) {
             accel = - accel; // in automatic mode we need to hold arrow down for reverse
         }
         if (accel < 0.0f) {
             // if we try to decelerate we brake.
             brake = true;
             accel = 0.0f;
             wantedRPM = 0.0f;
         }
  
         // the RPM we try to achieve.
         wantedRPM = (5500.0f * accel) * 0.1f + wantedRPM * 0.9f;
  
         float rpm = 0.0f;
         int motorizedWheels = 0;
         bool floorContact = false;
  
         // calc rpm from current wheel speed and do some updating
         foreach (WheelData w in wheels) {
             WheelHit hit;
             WheelCollider col = w.col;
  
             // only calculate rpm on wheels that are connected to engine
             if (w.motor) {
                 rpm += col.rpm;
                 motorizedWheels++;
             }
  
             // calculate the local rotation of the wheels from the delta time and rpm
             // then set the local rotation accordingly (also adjust for steering)
             w.rotation = Mathf.Repeat(w.rotation + delta * col.rpm * 360.0f / 60.0f, 360.0f);
             w.transform.localRotation = Quaternion.Euler(w.rotation, col.steerAngle, 0.0f);
  
             // let the wheels contact the ground, if no groundhit extend max suspension distance
             Vector3 lp = w.transform.localPosition;
             if (col.GetGroundHit(out hit)) {
                 lp.y -= Vector3.Dot(w.transform.position - hit.point, transform.up) - col.radius;
                 floorContact = floorContact || (w.motor);
             }
             else {
                 lp.y = w.startPos.y - suspensionDistance;
             }
             w.transform.localPosition = lp;
         }
         // calculate the actual motor rpm from the wheels connected to the engine
         // note we haven't corrected for gear yet.
         if (motorizedWheels > 1) {
             rpm = rpm / motorizedWheels;
         }
  
         // we do some delay of the change (should take delta instead of just 95% of
         // previous rpm, and also adjust or gears.
         motorRPM = 0.95f * motorRPM + 0.05f * Mathf.Abs(rpm * gears[currentGear]);
         if (motorRPM > 5500.0f) motorRPM = 5500.0f;
  
         // calculate the 'efficiency' (low or high rpm have lower efficiency then the
         // ideal efficiency, say 2000RPM, see table
         int index = (int) (motorRPM / efficiencyTableStep);
         if (index >= efficiencyTable.Length) index = efficiencyTable.Length - 1;
         if (index < 0) index = 0;
  
         // calculate torque using gears and efficiency table
         float newTorque = torque * gears[currentGear] * efficiencyTable[index];
  
         // go set torque to the wheels
         foreach (WheelData w in wheels) {
             WheelCollider col = w.col;
  
             // of course, only the wheels connected to the engine can get engine torque
             if (w.motor) {
                 // only set torque if wheel goes slower than the expected speed
                 if (Mathf.Abs(col.rpm) > Mathf.Abs(wantedRPM)) {
                     // wheel goes too fast, set torque to 0
                     col.motorTorque = 0;
                 }
                 else {
                     // 
                     float curTorque = col.motorTorque;
                     col.motorTorque = curTorque * 0.9f + newTorque * 0.1f;
                 }
             }
             // check if we have to brake
             col.brakeTorque = (brake)?brakeTorque:0.0f;
  
             // set steering angle
             col.steerAngle = steer * w.maxSteer;
         }
  
         // if we have an audiosource (motorsound) adjust pitch using rpm        
         if (audioSource != null) {
             // calculate pitch (keep it within reasonable bounds)
             float pitch = Mathf.Clamp(1.0f + ((motorRPM - idleRPM) / (shiftUpRPM - idleRPM) * 2.5f), 1.0f, 10.0f);
             audioSource.pitch = pitch;
  
             if (motorRPM > 100) {
                 // turn on sound if it's not playing yet and RPM is > 100.
                 if (!audioSource.isPlaying) {
                     audioSource.Play();
                 }
                 // how long we should wait with engine RPM <= 100 before killing engine sound
                 killEngine = Time.time + killEngineSoundTimeout;
             }
             else if ((audioSource.isPlaying) && (Time.time > killEngine)) {
                 // standing still, kill engine sound.
                 audioSource.Stop();
             }
         }
     }
  
     public void OnGUI() {
         if (checkForActive.active) {
             // calculate actual speed in Km/H (SI metrics rule, so no inch, yard, foot,
             // stone, or other stupid length measure!)
             float speed = rigidbody.velocity.magnitude * 3.6f;
  
             // message to display
             string msg = "Speed " + speed.ToString("f0") + "Km/H, " + motorRPM.ToString("f0") + "RPM, gear " + currentGear; //  + " torque " + newTorque.ToString("f2") + ", efficiency " + table[index].ToString("f2");
  
             GUILayout.BeginArea(new Rect(Screen.width -250 - 32, 32, 250, 40), GUI.skin.window);
             GUILayout.Label(msg);
             GUILayout.EndArea();
         }
     }
 }






and now my script:

 // These variables allow the script to power the wheels of the car.
 var FrontLeftWheel : WheelCollider;
 var FrontRightWheel : WheelCollider;
 var BackLeftWheel : WheelCollider;
 var BackRightWheel : WheelCollider;
 
 
 var gasButton : GUITexture; 
 var brakeButton : GUITexture;
 var leftTurnButton : GUITexture;
 var rightTurnButton : GUITexture; 
 var reverseButton : GUITexture;
 
 var motorInputTouch : int = 0;
 var brakePower : float = 200;
 // These variables are for the gears, the array is the list of ratios. The script
 // uses the defined gear ratios to determine how much torque to apply to the wheels.
 var GearRatio : float[];
 var CurrentGear : int = 0;
 
 // These variables are just for applying torque to the wheels and shifting gears.
 // using the defined Max and Min Engine RPM, the script can determine what gear the
 // car needs to be in.
 var EngineTorque : float = 230.0;
 var MaxEngineRPM : float = 3000.0;
 var MinEngineRPM : float = 1000.0;
 private var EngineRPM : float = 0.0;
 
 
 
 function Awake()  {
     gasButton = GameObject.Find("gas").guiTexture;
     brakeButton = GameObject.Find("Brake").guiTexture;
     leftTurnButton = GameObject.Find("left").guiTexture;
     rightTurnButton = GameObject.Find("right").guiTexture;
     reverseButton = GameObject.Find("reverse").guiTexture;
 
 }
 function Start () {
     // I usually alter the center of mass to make the car more stable. I'ts less likely to flip this way.
 rigidbody.centerOfMass += Vector3(0, -.75, .25);
     }
 
 function Update () {
 
     for (var touch : Touch in Input.touches)
     {    
         if (touch.phase == TouchPhase.Stationary && gasButton.HitTest (touch.position)) {
         motorInputTouch = 1;
     }
         else if (touch.phase == TouchPhase.Ended && gasButton.HitTest) {
         motorInputTouch = 0;
     }    
         
         if (touch.phase == TouchPhase.Stationary && brakeButton.HitTest (touch.position)) {
         brakePower = 90;
     }
         else if (touch.phase == TouchPhase.Ended && brakeButton.HitTest) {
         brakePower = 0;
     }            
         if (touch.phase == TouchPhase.Stationary && leftTurnButton.HitTest (touch.position)) {
             FrontLeftWheel.steerAngle = -15.0;
             FrontRightWheel.steerAngle = -15.0;
     }
         else if (touch.phase == TouchPhase.Ended && leftTurnButton.HitTest) {
             FrontLeftWheel.steerAngle = 0;
             FrontRightWheel.steerAngle = 0;
     }    
         
         if (touch.phase == TouchPhase.Stationary && rightTurnButton.HitTest (touch.position)) {
             FrontLeftWheel.steerAngle = 15.0;
             FrontRightWheel.steerAngle = 15.0;
         
     }
         else if (touch.phase == TouchPhase.Ended && rightTurnButton.HitTest) {
             FrontLeftWheel.steerAngle = 0;
             FrontRightWheel.steerAngle = 0;
         
     }
            if (touch.phase == TouchPhase.Stationary && reverseButton.HitTest (touch.position)) {
         motorInputTouch = -1;
     }
         else if (touch.phase == TouchPhase.Ended && reverseButton.HitTest) {
         motorInputTouch = 0;
     }                
     }                        
                                     
         // Compute the engine RPM based on the average RPM of the two wheels, then call the shift gear function
     EngineRPM = (FrontLeftWheel.rpm + FrontRightWheel.rpm)/2 * GearRatio[CurrentGear];
     ShiftGears();
 
     // set the audio pitch to the percentage of RPM to the maximum RPM plus one, this makes the sound play
     // up to twice it's pitch, where it will suddenly drop when it switches gears.
     audio.pitch = Mathf.Abs(EngineRPM / MaxEngineRPM) + 1.0 ;
     // this line is just to ensure that the pitch does not reach a value higher than is desired.
     if ( audio.pitch > 2.0 ) {
         audio.pitch = 2.0;
     }
 
     // finally, apply the values to the wheels.    The torque applied is divided by the current gear, and
     // multiplied by the user input variable.
     FrontLeftWheel.motorTorque = EngineTorque / GearRatio[CurrentGear] * motorInputTouch;
     FrontRightWheel.motorTorque = EngineTorque / GearRatio[CurrentGear] * motorInputTouch;
     BackRightWheel.brakeTorque = brakePower;
     BackLeftWheel.brakeTorque = brakePower;
         
     // the steer angle is an arbitrary value multiplied by the user input.
     //FrontLeftWheel.steerAngle = 10 * Input.GetAxis("Horizontal");
     //FrontRightWheel.steerAngle = 10 * Input.GetAxis("Horizontal");
 }
 
 function ShiftGears() {
     // this funciton shifts the gears of the vehcile, it loops through all the gears, checking which will make
     // the engine RPM fall within the desired range. The gear is then set to this "appropriate" value.
     if ( EngineRPM >= MaxEngineRPM ) {
         var AppropriateGear : int = CurrentGear;
         
         for ( var i = 0; i < GearRatio.length; i ++ ) {
             if ( FrontLeftWheel.rpm * GearRatio[i] < MaxEngineRPM ) {
                 AppropriateGear = i;
                 break;
             }
         }
         
         CurrentGear = AppropriateGear;
     }
     
     if ( EngineRPM <= MinEngineRPM ) {
         AppropriateGear = CurrentGear;
         
         for ( var j = GearRatio.length-1; j >= 0; j -- ) {
             if ( FrontLeftWheel.rpm * GearRatio[j] > MinEngineRPM ) {
                 AppropriateGear = j;
                 break;
             }
         }
         
         CurrentGear = AppropriateGear;
     }
 }
Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
â–¼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image AlucardJay · Apr 16, 2013 at 07:24 AM 0
Share

Sorry, but your question is not suitable for Unity Answers. Please use the Unity Forum for discussions such as "Port my code" : http://forum.unity3d.com/forums/17-Collaboration

Unity Answers is here to help you solve any specific problems you have.

  • http://answers.unity3d.com/page/newuser.html

  • http://video.unity3d.com/video/7720450/tutorials-using-unity-answers

0 Replies

  • Sort: 

Follow this Question

Answers Answers and Comments

11 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

GUITextures refuse to be touched 1 Answer

Change GUITexture Using UnityScript 1 Answer

Android: How do you position GUITexture and GUIText according to different screen sizes (JS)? 2 Answers

Disable gui texture in a different way? 0 Answers

Instantiated GuiTextures not showing 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges