Quantcast
Channel: Questions in topic: "crash"
Viewing all articles
Browse latest Browse all 2383

BoatPhysics not working

$
0
0
Hi, I currently am having an issue with a tutorial posted on http://www.habrador.com/tutorials/unity-boat-tutorial/4-waves-endless-ocean with the endless ocean part. When I left the three scripts from the tutorial fully unedited, unity would freeze forcing me to quit and relaunch. But now I have fixed that error, and incountered a new one that is ("IndexOutOfRangeException: Array index is out of range. WaterSquare.GenerateMesh () (at Assets/Scripts/WaterSquare.cs:130) WaterSquare..ctor (UnityEngine.GameObject waterSquareObj, Single no, Single spacing) (at Assets/Scripts/WaterSquare.cs:56) EndlessWaterSquare.AddWaterPlane (Single xCoord, Single zCoord, Single yPos, Single squareWidth, Single spacing) (at Assets/Scripts/EndlessWaterSquare.cs:211) EndlessWaterSquare.CreateEndlessSea () (at Assets/Scripts/EndlessWaterSquare.cs:171) EndlessWaterSquare.Start () (at Assets/Scripts/EndlessWaterSquare.cs:36)") Here are my slightly edited Scripts: WaterSquare.cs using UnityEngine; using System.Collections; using System.Collections.Generic; //Generates a plane with a specific resolution and transforms the plane to make waves public class WaterSquare { public Transform squareTransform; //Add the wave mesh to the MeshFilter public MeshFilter terrainMeshFilter; //The total size in m private float size = 5; //Resolution = Width of one square public float spacing = 3; //The total number of vertices we need to generate based on size and spacing private int width = 18; //For the thread to update the water //The local center position of this square to fake transformpoint in a thread public Vector3 centerPos; //The latest vertices that belong to this square public Vector3[] vertices; public WaterSquare(GameObject waterSquareObj, float no, float spacing) { this.squareTransform = waterSquareObj.transform; size = 5; this.spacing = spacing; this.terrainMeshFilter = squareTransform.GetComponent(); //Calculate the data we need to generate the water mesh width = (int)(size / spacing); //Because each square is 2 vertices, so we need one more width += 1; //Center the sea float offset = -((width - 1) * spacing) / 2; Vector3 newPos = new Vector3(offset, squareTransform.position.y, offset); squareTransform.position += newPos; //Save the center position of the square this.centerPos = waterSquareObj.transform.localPosition; //Generate the sea //To calculate the time it took to generate the terrain float startTime = System.Environment.TickCount; GenerateMesh(); //Calculate the time it took to generate the terrain in seconds float timeToGenerateSea = (System.Environment.TickCount - startTime) / 1000f; Debug.Log("Sea was generated in " + timeToGenerateSea.ToString() + " seconds"); //Save the vertices so we can update them in a thread this.vertices = terrainMeshFilter.mesh.vertices; } //If we are updating the square from outside of a thread public void MoveSea(Vector3 oceanPos, float timeSinceStart) { Vector3[] vertices = terrainMeshFilter.mesh.vertices; for (int i = 0; i < vertices.Length; i++) { Vector3 vertex = vertices[i]; //From local to global //Vector3 vertexGlobal = squareTransform.TransformPoint(vertex); Vector3 vertexGlobal = vertex + centerPos + oceanPos; //Unnecessary because no rotation nor scale //Vector3 vertexGlobalTest2 = squareTransform.rotation * Vector3.Scale(vertex, squareTransform.localScale) + squareTransform.position; //Debug if (i == 0) { //Debug.Log(vertexGlobal + " " + vertexGlobalTest); } //Get the water height at this coordinate vertex.y = WaterController.current.GetWaveYPos(vertexGlobal, timeSinceStart); //From global to local - not needed if we use the saved local x,z position //vertices[i] = transform.InverseTransformPoint(vertex); //Don't need to go from global to local because the y pos is always at 0 vertices[i] = vertex; } terrainMeshFilter.mesh.vertices = vertices; terrainMeshFilter.mesh.RecalculateNormals(); } //Generate the water mesh public void GenerateMesh() { //Vertices List verts = new List(); //Triangles List tris = new List(); //Texturing //List uvs = new List(); for (int z = 0; z < 18; z++) { verts.Add(new Vector3[z]); for (int x = 0; x < 1; x++) { Vector3 current_point = new Vector3(); //Get the corrdinates of the vertice current_point.x = x * spacing; current_point.z = z * spacing; current_point.y = squareTransform.position.y; verts[z][x] = current_point; //uvs.Add(new Vector2(x,z)); //Don't generate a triangle the first coordinate on each row //Because that's just one point if (x <= 0 || z <= 0) { continue; } //Each square consists of 2 triangles //The triangle south-west of the vertice tris.Add(x + z * width); tris.Add(x + (z-1) * width); tris.Add((x-1) + (z-1) * width); //The triangle west-south of the vertice tris.Add(x + z * width); tris.Add((x-1) + (z-1) * width); tris.Add((x-1) + z * width); } } //Unfold the 2d array of verticies into a 1d array. Vector3[] unfolded_verts = new Vector3[width * width]; int i = 0; foreach (Vector3[] v in verts) { //Copies all the elements of the current 1D-array to the specified 1D-array v.CopyTo(unfolded_verts, i * width); i++; } //Generate the mesh object Mesh newMesh = new Mesh(); newMesh.vertices = unfolded_verts; //newMesh.uv = uvs.ToArray(); newMesh.triangles = tris.ToArray(); //Ensure the bounding volume is correct newMesh.RecalculateBounds(); //Update the normals to reflect the change newMesh.RecalculateNormals(); //Add the generated mesh to this GameObject terrainMeshFilter.mesh.Clear(); terrainMeshFilter.mesh = newMesh; terrainMeshFilter.mesh.name = "Water Mesh"; Debug.Log(terrainMeshFilter.mesh.vertices.Length); } } EndlessWaterSquare.cs using UnityEngine; using System.Collections; using System.Collections.Generic; using System.Threading; //Creates an endless water system with squares public class EndlessWaterSquare : MonoBehaviour { //The object the water will follow public GameObject boatObj; //One water square public GameObject waterSqrObj; //Water square data private float squareWidth = 3f; private float innerSquareResolution =9f; private float outerSquareResolution = 2f; //The list with all water mesh squares == the entire ocean we can see List waterSquares = new List(); //Stuff needed for the thread //The timer that keeps track of seconds since start to update the water because we cant use Time.time in a thread float secondsSinceStart; //The position of the boat Vector3 boatPos; //The position of the ocean has to be updated in the thread because it follows the boat //Is not the same as pos of boat because it moves with the same resolution as the smallest water square resolution Vector3 oceanPos; //Has the thread finished updating the water so we can add the stuff from the thread to the main thread bool hasThreadUpdatedWater; void Start() { //Create the sea CreateEndlessSea(); //Init the time secondsSinceStart = Time.time; //Update the water in the thread ThreadPool.QueueUserWorkItem(new WaitCallback(UpdateWaterWithThreadPooling)); //Start the coroutine StartCoroutine(UpdateWater()); } void Update() { //UpdateWaterNoThread(); //Update these as often as possible because we don't know when the thread will run because of pooling //and we always need the latest version //Update the time since start to get correct wave height which depends on time since start secondsSinceStart = Time.time; //Update the position of the boat to see if we should move the water boatPos = boatObj.transform.position; } //Update the water with no thread to compare void UpdateWaterNoThread() { //Update the position of the boat boatPos = boatObj.transform.position; //Move the water to the boat MoveWaterToBoat(); //Add the new position of the ocean to this transform transform.position = oceanPos; //Update the vertices for (int i = 0; i < 5; i++) { waterSquares[i].MoveSea(oceanPos, Time.time); } } //The loop that gives the updated vertices from the thread to the meshes //which we can't do in its own thread IEnumerator UpdateWater() { while (true) { //Has the thread finished updating the water? if (hasThreadUpdatedWater) { //Move the water to the boat transform.position = oceanPos; //Add the updated vertices to the water meshes for (int i = 0; i < 5; i++) { waterSquares[i].terrainMeshFilter.mesh.vertices = waterSquares[i].vertices; waterSquares[i].terrainMeshFilter.mesh.RecalculateNormals(); } //Stop looping until we have updated the water in the thread hasThreadUpdatedWater = false; //Update the water in the thread ThreadPool.QueueUserWorkItem(new WaitCallback(UpdateWaterWithThreadPooling)); } //Don't need to update the water every frame yield return new WaitForSeconds(Time.deltaTime * 3f); } } //The thread that updates the water vertices void UpdateWaterWithThreadPooling(object state) { //Move the water to the boat MoveWaterToBoat(); //Loop through all water squares for (int i = 0; i < 5; i++) { //The local center pos of this square Vector3 centerPos = waterSquares[i].centerPos; //All the vertices this square consists of Vector3[] vertices = waterSquares[i].vertices; //Update the vertices in this square for (int j = 0; j < 5; j++) { //The local position of the vertex Vector3 vertexPos = vertices[j]; //Can't use transformpoint in a thread, so to find the global position of the vertex //we just add the position of the ocean and the square because rotation and scale is always 0 and 1 Vector3 vertexPosGlobal = vertexPos + centerPos + oceanPos; //Get the water height vertexPos.y = WaterController.current.GetWaveYPos(vertexPosGlobal, secondsSinceStart); //Save the new y coordinate, but x and z are still in local position vertices[j] = vertexPos; } } hasThreadUpdatedWater = true; Debug.Log("Thread finished"); } //Move the endless water to the boat's position in steps that's the same as the water's resolution void MoveWaterToBoat() { //Round to nearest resolution float x = innerSquareResolution * (int)Mathf.Round(boatPos.x / innerSquareResolution); float z = innerSquareResolution * (int)Mathf.Round(boatPos.z / innerSquareResolution); //Should we move the water? if (oceanPos.x != x || oceanPos.z != z) { Debug.Log("Moved sea"); oceanPos = new Vector3(x, oceanPos.y, z); } } //Init the endless sea by creating all squares void CreateEndlessSea() { //The center piece AddWaterPlane(0f, 0f, 0f, squareWidth, innerSquareResolution); //The 8 squares around the center square for (int x = -1; x <= 1; x += 1) { for (int z = -1; z <= 1; z += 1) { //Ignore the center pos if (x == 0 && z == 0) { continue; } //The y-Pos should be lower than the square with high resolution to avoid an ugly seam float yPos = -0.5f; AddWaterPlane(x * squareWidth, z * squareWidth, yPos, squareWidth, outerSquareResolution); } } } //Add one water plane void AddWaterPlane(float xCoord, float zCoord, float yPos, float squareWidth, float spacing) { GameObject waterPlane = Instantiate(waterSqrObj, transform.position, transform.rotation) as GameObject; waterPlane.SetActive(true); //Change its position Vector3 centerPos = transform.position; centerPos.x += xCoord; centerPos.y = yPos; centerPos.z += zCoord; waterPlane.transform.position = centerPos; //Parent it waterPlane.transform.parent = transform; //Give it moving water properties and set its width and resolution to generate the water mesh WaterSquare newWaterSquare = new WaterSquare(waterPlane, squareWidth, spacing); waterSquares.Add(newWaterSquare); } }` The last script was left unedited Im pretty sure I know the cause to these errors, but cant fix them. BTW: I'm running an expiremental build on Linux : 5.6.0xb8

Viewing all articles
Browse latest Browse all 2383

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>