Example #1
0
    void UpdateBranch(
        Transform moveGuide,
        List <PlantJoint> plantJoints,
        PlantJoint currentJoint,
        Vector3 initJointPos,
        int jointsSinceBranch,
        int fracturesRemaining)
    {
        moveGuide.position += moveGuide.forward * MoveSpeed;

        currentJoint.position   = moveGuide.position;
        currentJoint.timeAlive += Time.deltaTime;

        // Update each joint in the plant
        for (int i = 0; i < plantJoints.Count; i++)
        {
            PlantJoint pj = plantJoints[i];
            if (pj.timeAlive < _jointMaxGrowthTime)
            {
                pj.timeAlive += Time.deltaTime;
                pj.scale      = _jointGrowthCurve.Evaluate(pj.timeAlive / _jointMaxGrowthTime) * _jointMaxGrowth;
            }

            if (!pj.attemptedBranch && pj.timeAlive > _jointMaxGrowthTime / 3f)
            {
                pj.attemptedBranch = true;

                if ((currentJoint != _mainBranchCurrentJoint || i > _minJointsBeforeBranching) &&
                    jointsSinceBranch > _minJointsBetweenBranches &&
                    Random.value < _chanceToSpawnBranch)
                {
                    jointsSinceBranch = 0;
                    StartCoroutine(StartBranchAtJoint(pj, _sideBranchLifespan.Random, fracturesRemaining));
                }
            }
        }

        // If we haven't dropped a joint yet, compare with our starting position
        Vector3 prevPos = plantJoints.Last() ? plantJoints.Last().position : initJointPos;

        float distanceSincePrevJoint = Vector3.Distance(currentJoint.position, prevPos);

        if (distanceSincePrevJoint > _jointDropDistance)
        {
            int catchupJointsNeed = Mathf.FloorToInt(distanceSincePrevJoint / _jointDropDistance);
            for (int i = 0; i < catchupJointsNeed; i++)
            {
                Vector3 dirFromLastJoint = (currentJoint.position - prevPos).normalized;
                Vector3 newJointPos      = prevPos + dirFromLastJoint * _jointDropDistance;

                PlantJoint newJoint = new PlantJoint(newJointPos, dirFromLastJoint, moveGuide.right);
                newJoint.scale = _jointGrowthCurve.Evaluate(0f) * _jointMaxGrowth;

                plantJoints.Add(newJoint);
            }

            currentJoint.timeAlive = 0f;
        }
    }
Example #2
0
    IEnumerator GrowMainBranchRoutine()
    {
        float lifeTimer = 0f;

        while (lifeTimer < _mainBranchLifespan)
        {
            Vector3 moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical"));
            moveDirection = _mainCamera.transform.TransformDirection(moveDirection);
            Vector3 moveToPosition = _mainBranchCurrentJoint.position + moveDirection;

            float lookAtHeightMod = Input.GetMouseButton(0) ? -1f : 1f;
            moveToPosition.y = _mainBranchCurrentJoint.position.y + lookAtHeightMod;

            float finishMod = 1f;
            float tenthLife = _mainBranchLifespan / 10f;
            if (lifeTimer > _mainBranchLifespan - tenthLife)
            {
                finishMod -= Mathf.InverseLerp(lifeTimer, _mainBranchLifespan - tenthLife, _mainBranchLifespan);
            }

            _mainBranchMoveGuide.LerpLookAt(moveToPosition, Vector3.up, Time.deltaTime * _lookAtMouseSpeed * finishMod);

            int jointsBefore = _mainBranchJoints.Count;
            UpdateBranch(
                _mainBranchMoveGuide,
                _mainBranchJoints,
                _mainBranchCurrentJoint,
                _initPlantPos,
                _mainBranchJointsSinceBranch,
                _maxBranchFractures - 1);
            _mainBranchJointsSinceBranch += _mainBranchJoints.Count - jointsBefore;

            lifeTimer += Time.deltaTime;
            yield return(null);
        }

        yield return(new WaitForSeconds(1f));

        gameObject.AddComponent <MeshCollider>();

        PlantJoint leafJoint = _mainBranchJoints[_mainBranchJoints.Count - 9];

        StartCoroutine(GrowLeafRoutine(leafJoint.position, leafJoint.forward, _mainLeafScaleMod));

        FinishedGrowingCallback();
    }
Example #3
0
    void Awake()
    {
        _mesh       = new Mesh();
        _meshFilter = GetComponent <MeshFilter>();

        _mainCamera = Camera.main;

        _mainBranchMoveGuide          = new GameObject("MoveGuide").transform;
        _mainBranchMoveGuide.parent   = transform;
        _mainBranchMoveGuide.position = transform.position;
        _mainBranchMoveGuide.LookAt(_mainBranchMoveGuide.position + Vector3.up);

        _initPlantPos = transform.position;

        _mainBranchJoints.Add(new PlantJoint(transform.position, _mainBranchMoveGuide.forward, Vector3.right));
        _mainBranchCurrentJoint = new PlantJoint(transform.position, _mainBranchMoveGuide.forward, Vector3.right);

        StartCoroutine(GrowMainBranchRoutine());
    }
Example #4
0
    IEnumerator StartBranchAtJoint(PlantJoint startingJoint, float lifespan, int fracturesRemaining)
    {
        List <PlantJoint> branchJoints    = new List <PlantJoint>();
        Vector3           newForward      = (startingJoint.right + startingJoint.forward) / 2f;
        Vector3           newRight        = Vector3.Cross(startingJoint.forward, startingJoint.right);
        PlantJoint        branchMainJoint = new PlantJoint(startingJoint.position, newForward, newRight);

        Transform moveGuide = new GameObject("TempMoveGuide").transform;

        moveGuide.position = branchMainJoint.position;
        moveGuide.parent   = transform;

        moveGuide.LookAt(branchMainJoint.position, branchMainJoint.forward);
        moveGuide.rotation *= Quaternion.Euler(Random.Range(0f, 360f), 0f, 0f);

        // If our branch starts point downward, keep rerolling until it isn't
        float downDot = Vector3.Dot(Vector3.down, moveGuide.forward);

        while (downDot > 0.4f || downDot < -0.8f)
        {
            moveGuide.rotation *= Quaternion.Euler(Random.Range(0f, 360f), 0f, 0f);
            downDot             = Vector3.Dot(Vector3.down, moveGuide.forward);
        }

        Quaternion startRotation = moveGuide.rotation;
        float      yRotation     = Random.Range(-90f, -30f);
        Quaternion midRotation   = Quaternion.Euler(Random.Range(-45f, 45f), Random.Range(-45f, 45f), 0f);
        Quaternion endRotation   = Quaternion.Euler((Random.insideUnitSphere * 360f).SetX(yRotation));

        Vector3 initJointPos        = branchMainJoint.position;
        int     jointsSinceBranch   = 0;
        bool    attemptedLeafGrowth = false;

        float lifeTimer = 0f;

        while (lifeTimer < lifespan)
        {
            int jointsBefore = branchJoints.Count;
            UpdateBranch(
                moveGuide,
                branchJoints,
                branchMainJoint,
                initJointPos,
                jointsSinceBranch,
                fracturesRemaining - 1);
            jointsSinceBranch += branchJoints.Count - jointsBefore;

            branchJoints.Add(branchMainJoint);
            CalculateBranchMesh(branchJoints);
            branchJoints.Remove(branchMainJoint);

            float halfLife = lifespan / 2f;
            if (lifeTimer > halfLife && !attemptedLeafGrowth)
            {
                attemptedLeafGrowth = true;
                if (Random.value < _chanceToGrowLeaves)
                {
                    StartCoroutine(GrowLeafRoutine(initJointPos, startingJoint.forward));
                }
            }

            if (lifeTimer < halfLife)
            {
                moveGuide.rotation = Quaternion.Lerp(startRotation, midRotation, lifeTimer / halfLife);
            }
            else
            {
                moveGuide.rotation = Quaternion.Lerp(midRotation, endRotation, (lifeTimer - halfLife) / halfLife);
            }

            lifeTimer += Time.deltaTime;
            yield return(null);
        }

        Destroy(moveGuide.gameObject);
        branchJoints.Add(branchMainJoint);
        _finishedBranches.Add(branchJoints);
    }
Example #5
0
    void CalculateBranchMesh(List <PlantJoint> plantJoints)
    {
        float uvHeight = 0f;

        // Iterate through each of the plant joints
        for (int i = 0; i < plantJoints.Count; i++)
        {
            PlantJoint pj = plantJoints[i];
            uvHeight += _jointDropDistance;

            // If main branch current plantjoint is at 0f time, we've just added a new plantjoint
            // Don't draw the last set of triangles otherwise there will be Z-fighting
            if (pj == _mainBranchCurrentJoint && WadeUtils.IsZero(pj.timeAlive))
            {
                continue;
            }

            for (int j = 0; j < _vertsPerJoint; j++)
            {
                Vector3 jointUp             = Vector3.Cross(pj.forward, pj.right);
                float   percentAroundCircle = j / (float)_vertsPerJoint;

                Vector3 vertPos     = pj.position;
                Vector3 circleUp    = Mathf.Sin(percentAroundCircle * Mathf.PI * 2f) * jointUp;
                Vector3 circleRight = Mathf.Cos(percentAroundCircle * Mathf.PI * 2f) * pj.right;

                vertPos += circleUp * pj.scale;
                vertPos += circleRight * pj.scale;
                _vertices.Add(vertPos);

                Vector3 basicOffset = vertPos + circleUp + circleRight;
                Vector3 normal      = (basicOffset - pj.position).normalized;

                if (uvHeight > 0.5f)
                {
                    uvHeight = uvHeight % 0.5f;
                }

                _normals.Add(normal);
                _uv.Add(new Vector2((j + 1) / (float)_vertsPerJoint, uvHeight) * 0.5f);

                // Calculate tangent in a dumb way
                Vector3 tanPos = pj.position;
                if (j == 0)
                {
                    circleRight = Mathf.Cos(percentAroundCircle - 0.001f * Mathf.PI * 2f) * -pj.right;
                }
                else
                {
                    circleRight = Mathf.Cos(percentAroundCircle + 0.001f * Mathf.PI * 2f) * pj.right;
                }

                tanPos += circleRight;
                tanPos += circleUp;

                _tangents.Add(((Vector4)(tanPos - vertPos).normalized).SetW(1f));

                if (i != 0 && j != 0)
                {
                    int currentTri       = _vertices.Count - 1;
                    int prevTri          = currentTri - 1;              // Previous vert on same joint
                    int prevJointTri     = currentTri - _vertsPerJoint; // Same vert previous joint
                    int prevJointPrevTri = prevTri - _vertsPerJoint;    // Previous vert on previous joint

                    _triangles.Add(prevJointPrevTri);
                    _triangles.Add(currentTri);
                    _triangles.Add(prevTri);

                    _triangles.Add(prevJointPrevTri);
                    _triangles.Add(prevJointTri);
                    _triangles.Add(currentTri);

                    if (j == _vertsPerJoint - 1)
                    {
                        // Need to complete the cylinder!
                        // Treat each joints 0 verts as another new vert around the cylinder as before

                        // Jump prevs up to the current and prevJoints
                        prevTri          = currentTri;                // Previous vert on same joint
                        prevJointPrevTri = prevJointTri;              // Previous vert on previous joint

                        currentTri   = _vertices.Count - _vertsPerJoint;
                        prevJointTri = currentTri - _vertsPerJoint;                         // Same vert previous joint

                        _triangles.Add(prevJointPrevTri);
                        _triangles.Add(currentTri);
                        _triangles.Add(prevTri);

                        _triangles.Add(prevJointPrevTri);
                        _triangles.Add(prevJointTri);
                        _triangles.Add(currentTri);
                    }
                }
            }
        }
    }