Has anybody found or made a Go-Kart style racing AI they have found cheap or have made them selves and are willing to give to me. Or even found a series on YouTube that explains how to make a go-kart style AI in unity? If you decide to give it to me, I would add you in the description of my game if I release it.
The Gotow Car Tutorial Project is a good start. It's not actual AI, but waypoint following, meaning that cars will crash into each other. I've made a Github repository here. And also I've converted it to C# with the help of an online converter. The zip file of the C# project can be downloaded here
Well, well, well! My friend, I can make my AI code modular, or help you script it, as I have done something similar to what cl.9 did above, except I have a steering modifier in place to add variation to the car's driving. If you want to see it in action, look at my WIP thread: http://forum.unity3d.com/threads/wip-splashdash-a-sci-fi-not-yet-d-arcade-racer-for-android.267972/ And watch the latest replay clip, of which has the updated AI. Also, PM me if you need anything.
Thank you! I will be sure to try that out and see how it works with my game and Ill tell you how it goes!
If you could help me that it would be great! Ive made a very very simple AI before but I vaguely understand how it works so if you could help me that would be awesome!
Well, today's QCS testing for me, so I can only write a short explanation of how I did it. will hopefully write something better after I get home. So here goes: Basically, you have to make a line of GameObjects, all named something like "Waypoint0," "Waypoint1," etc. I have them all under one container, tagged "waypoints" When you have done this, then, in the script, you get all the waypoints and store them in an array, then set the current one to 0. By programming the movement carefully, use a steering vector, generated by using InverseTransformPoint (I think it was that... ) and then, to make it better, modify the vector a little each frame. that way, the cars follow the full path, and have steering variation too, to make it more exciting. (My car AIs do this, and often, they will merge into the lane next to them unintentionally. It is also possible for a car to wrongly guess it's steering vector, and drive off the edge... ) So that's a summary of how I did it. I will post a full report, and possibly some code to help explain, once I get home.
I sort of forgot what day that was... I will post it! the first part is obviously this: Code (csharp): cars.Sort(cars, new UpdateRanks_Laps()); And the second part is the IComparer module: Code (csharp): class UpdateRanks_Laps implements IComparer { function Compare(a : System.Object, b : System.Object) : int { if ( !(a instanceof GameObject) || !(b instanceof GameObject)) return; var CarA : GameObject = a; var CarB : GameObject = b; if (CarB.GetComponent(Rank_Sys).lap.CompareTo(CarA.GetComponent(Rank_Sys).lap)){ return CarB.GetComponent(Rank_Sys).lap.CompareTo(CarA.GetComponent(Rank_Sys).lap); } if (CarB.GetComponent(Rank_Sys).currentWaypoint.CompareTo(CarA.GetComponent(Rank_Sys).currentWaypoint)){ return CarB.GetComponent(Rank_Sys).currentWaypoint.CompareTo(CarA.GetComponent(Rank_Sys).currentWaypoint); } else { return CarA.GetComponent(Rank_Sys).dist.CompareTo(CarB.GetComponent(Rank_Sys).dist); } } } this third script is what you attach to ALL of your cars: Code (csharp): var waypointContainer : GameObject; var waypoints : Component[]; var waypointRadius : float = 1.5; var currentRank : int = 0; //vars for comparison. distance is to next waypoint, current is waypoint, lap is current laps made round track. var dist : float = 0; var currentWaypoint : int = 0; var lap : int = 1; //if finished, change to true. is false at race start. var finished : boolean = false; function Start () { lap = 1; waypointContainer = GameObject.FindGameObjectWithTag("Waypoints"); waypoints = waypointContainer.GetComponentsInChildren(Transform); } function Update () { dist = Vector3.Distance(waypoints[currentWaypoint].transform.position, transform.position); if(dist <= waypointRadius) { currentWaypoint++; if(currentWaypoint>=waypoints.Length) { currentWaypoint = 0; lap++; if (lap > GUI_Racer.laps){ finished = true; } } } } Ok, some notes on this: this is JS code. If you need it ported to C#, I can do this, so just let me know if you need anything! This code is surprisingly (or not... ) expensive on a low-end mobile device! So if you're producing a simple racing game for ALL devices, I don't suggest you use this code. (I thought my project was dragged down by physics... I tracked it down to actually be this code!) For most applications otherwise, this should work. You will need to lay down some waypoints first before you try setting up anything, as this approach uses them for tracking the objects. For anything to be picked up by the function, make sure your car objects are in the corresponding array, and all of them MUST have the third script attached. Good luck! If any of you need help with this, I can help you set up your scene, as I am currently using this method for my own mobile racer. Just search for "Splash Dash" (Yet to be renamed... I have a new name for it! ) and my WIP thread should come up. I do plan on switching methods myself though, for the reasons stated above: for more than two cars, this is surprisingly expensive on mobile! EDIT: IF you want easier integration, rename the script with the third snippet in it "Rank_Sys" Otherwise, you will have to rewrite part of the IComparer so that it knows what type to look for!
Oh shoot... wrong thread! Here's the AI code. (the stuff above is actually for ranking! ) Code (csharp): var waypointContainer : GameObject; var waypoints : Component[]; var waypointRadius : float = 1.5; var damping : float = 0.1; var speed : float = 2.0; var death : float; var turnSpeed : float; var playerName : String; private var targetHeading : Vector3; private var currentHeading : Vector3; private var targetwaypoint : int; private var timer : int; var particles : ParticleSystem; var isHit : boolean = false; var isBump : boolean = false; var hitW : Vector3; var engineNoise : AudioSource; //cache rigidbody, for speedup! var PhysX : Rigidbody; // Use this for initialization function Start() { turnMod = true; PhysX = GetComponent(Rigidbody); waypointContainer = GameObject.FindGameObjectWithTag("Waypoints"); multiplier = 0; PhysX.centerOfMass.y = -0.5; prev = transform.rotation.eulerAngles.y; waypoints = waypointContainer.GetComponentsInChildren(Transform); currentHeading = transform.forward; while(true){ timer -= 1; if (timer < 0){ timer = 0; } yield WaitForSeconds(1); } } // calculates a new heading private var prev : float = 0; var multiplier : float = 1; var isGrounded : boolean = false; var rayDist : float; var time : float; var turn : float; var frontAxle : GameObject; var backAxle : GameObject; var upperLimit : float; var isBoosting : boolean = false; var turnMod : boolean = false; var splash : GameObject; var deathBool : boolean; function OnLevelExit () { Destroy(gameObject); } var ptW : Quaternion; var pt : Quaternion; var lerpTimer : float; var variant : float; var started : boolean; function FixedUpdate() { if (GUI_Racer.start){ if (multiplier > 2.0 && !started) { isHit = true; started = true; } else if (multiplier < 1.5 && !started) { multiplier = 0; started = true; } else if (!started) { isBoosting = true; time = 0; particles.Play(); started = true; } var rot : Vector3 = transform.InverseTransformPoint(Vector3(waypoints[targetwaypoint].transform.position.x,transform.position.y,waypoints[targetwaypoint].transform.position.z)); var vector = (turnSpeed * multiplier) * (rot.x / rot.magnitude); if (PhysX.velocity.magnitude >= 0.01 && isGrounded){ frontAxle.transform.Rotate(Vector3(0,-PhysX.velocity.magnitude*1.3,0), Space.Self); backAxle.transform.Rotate(Vector3(0,-PhysX.velocity.magnitude*1.3,0), Space.Self); } if (Physics.Raycast(transform.position, -transform.up, rayDist)){ isGrounded = true; } else { isGrounded = false; } //if the car was hit by an item, carry out this action, unless the car is already flying in the air. if (isHit) { if (isGrounded){ multiplier = 0; PhysX.velocity.y = 10; PhysX.AddTorque(Vector3(0,500,0), ForceMode.VelocityChange); isHit = false; } else { isHit = false; } } if (isGrounded && !isBoosting && !isHit) { multiplier += 0.01; if (multiplier > upperLimit){ multiplier -= 0.05; } } else { multiplier -= 0.02; if (multiplier < 0){ multiplier = 0; } } //take vectors, and move car if not hit. if (!isHit && !isBump) { var move : Vector3 = transform.forward * speed * multiplier; move.y = PhysX.velocity.y; PhysX.velocity = move; } if (isBump) { PhysX.AddForce(hitW * 12, ForceMode.Force); rigidbody.velocity.y = 0; isBump = false; } if(rot.magnitude <= waypointRadius) { targetwaypoint++; if(targetwaypoint>=waypoints.Length) { targetwaypoint = 0; } } time += 0.25; //turn the car a little more to either direction, to add variation to movement if (time >= 5){ turn = Random.Range(1.2,3.5); variant = Random.Range(-10,10); time = 0; turnMod = false; deathBool = false; } if (time > 2.4 && time < 2.6) { turnMod = true; } if (timer <= 0){ isBoosting = false; } if (transform.position.y <= death) { PhysX.velocity = Vector3(0,0,0); pt = transform.rotation; transform.position = waypoints[targetwaypoint].transform.position + Vector3(0,2,0); transform.rotation = waypoints[targetwaypoint].transform.rotation; multiplier = 0; deathBool = true; } if (!isGrounded) { lerpTimer += Time.deltaTime*2.5; if (lerpTimer > 1) { lerpTimer = 1; } ptW = Quaternion.Euler(0,prev,0); transform.rotation = Quaternion.Lerp(pt,ptW,lerpTimer); isBoosting = false; } if (isGrounded && !deathBool) { // transform.Rotate(Vector3(0,Mathf.Lerp(0,vector,0.5),0)); vector += variant; transform.rotation.eulerAngles.y = Mathf.Lerp(prev,prev + vector,Mathf.Clamp01(turn*Time.deltaTime)); prev = transform.rotation.eulerAngles.y; ptW.eulerAngles = Vector3(0,transform.rotation.eulerAngles.y,0); lerpTimer = 0; } } else { backAxle.transform.Rotate(Vector3(0,-multiplier*10,0), Space.Self); time = Random.Range(0,10); started = false; if (time < 5) { multiplier += 0.08; } else { multiplier -= 0.03; if (multiplier < 0){ multiplier = 0; } } } engineNoise.pitch = multiplier*2.5 + 1.0; pt = transform.rotation; } function OnTriggerEnter (info : Collider) { if (info.gameObject.CompareTag("Dash")){ multiplier = 2; PhysX.AddForce(transform.forward * 6, ForceMode.VelocityChange); isBoosting = true; timer = 1; particles.Play(); } if (info.gameObject.CompareTag("Water")){ Instantiate(splash, transform.position, splash.transform.rotation); } if (info.gameObject.CompareTag("DeathTrigger")){ deathBool = true; PhysX.velocity = Vector3(0,0,0); pt = transform.rotation; transform.position = waypoints[targetwaypoint].transform.position + Vector3(0,2,0); transform.rotation = waypoints[targetwaypoint].transform.rotation; multiplier = 0; } } function OnCollisionEnter(info : Collision) { if (info.gameObject.CompareTag("Car") && PhysX.velocity.magnitude <= info.rigidbody.velocity.magnitude) { hitW = Vector3.Normalize(transform.InverseTransformPoint(info.transform.position)); hitW.y = 0; isBump = true; } if (info.gameObject.CompareTag("Missile") && info.gameObject.GetComponent(Missile).sender != this.gameObject && isGrounded) { isHit = true; Destroy(info.gameObject); } } function IsValid (quaternion : Quaternion) : boolean { var isNaN : boolean = float.IsNaN(quaternion.x + quaternion.y + quaternion.z + quaternion.w); var isZero : boolean = quaternion.x == 0 && quaternion.y == 0 && quaternion.z == 0 && quaternion.w == 0; return !(isNaN || isZero); } note though that I have just pulled this straight out of my own game, so it's probably not going to work first-off. Let me know what errors you get, and I will help integrate the code with your project!
Thanks alot for it Fuzzy The above line make me Heart break kid Although thanks for this stuff really appreciated.....It will surely help alot of people (including me)
Yeah searched for splash dash many games appeared not quite sure which is yours? please provide the link, I am very much excited to see it
I am actually fixing the speed issues with my code right now, so I will get back to you once I have some improvements... ...Or you could just check here! This is the droid you're looking for... LINK: http://forum.unity3d.com/threads/wip-splashdash-a-sci-fi-not-yet-d-arcade-racer-for-android.267972/ I am considering renaming the game to neoDash, as it sounds better and more suited to the game!
hi, can you post how you implemented camera on it? I am stuck at corners, camera and player do not rotate properly.. by the way neoDas seems unique game name... Good luck for it keep us updating waiting for final version
I actually used smoothfollow, of which I then assign the car to the lookAt position variable. (SmoothFollow is a script that comes with Unity: simply import that from the CharacterController package) If you're using a custom script for your camera, just pop it here, and I will help fix it up!
Yeah I got it work using Quaternion.LookRotation() and rotateTowards... Btw do you know how to change from one waypoint system to another at run time? Like suppose I have implemented shortcut way in my track then how to change waypoint system for it ?
Hello FuzzyQuills, I am making a kart race game and I tried to use the above AI script. But I am getting 2 errors: 1. (73,13): BCE0005: Unknown identifier: 'GUI_Racer'. Code (JavaScript): function FixedUpdate() { if (GUI_Racer.start){ if (multiplier > 2.0 && !started) { isHit = true; started = true; } else if (multiplier < 1.5 && !started) { multiplier = 0; started = true; } 2. (238,83): BCE0005: Unknown identifier: 'Missile'. Code (JavaScript): function OnCollisionEnter(info : Collision) { if (info.gameObject.CompareTag("Car") && PhysX.velocity.magnitude <= info.rigidbody.velocity.magnitude) { hitW = Vector3.Normalize(transform.InverseTransformPoint(info.transform.position)); hitW.y = 0; isBump = true; } if (info.gameObject.CompareTag("Missile") && info.gameObject.GetComponent(Missile).sender != this.gameObject && isGrounded) { isHit = true; Destroy(info.gameObject); } } How can I solve this?
Oh... GUI_Racer's my main script in the game I got that from! just substitute GUI_Racer.start with whatever your racing script uses to indicate when the race is starting! The second bit is actually for a missile power-up, so you can probably delete that. Other than that, good luck! If you need help writing a core script, I can definitely help!
Hi man!! I would like to make a motocross video game, I search a physic and IA scripting... I have read your post and I would like to ask you, can you ported your script in C# for unity? Thanks in advance