Example #1
0
 protected void SetBoatIdle(CBoat boat)
 {
     boat.m_targetPoint.x = Mathf.Clamp(Random.Range(boat.m_handle.transform.position.x - m_boatIdleRange, boat.m_handle.transform.position.x + m_boatIdleRange), -m_waterSimulation.m_Scale.x / 2.0f, m_waterSimulation.m_Scale.x / 2.0f);
     boat.m_targetPoint.y = Mathf.Clamp(Random.Range(boat.m_handle.transform.position.z - m_boatIdleRange, boat.m_handle.transform.position.z + m_boatIdleRange), -m_waterSimulation.m_Scale.z / 2.0f, m_waterSimulation.m_Scale.z / 2.0f);
     boat.m_stateTime     = m_boatIdleTimeMax;
     boat.m_state         = EBoatState.IDLE;
 }
Example #2
0
    protected bool HasBoatLostTarget(CBoat boat, Vector2 boatPos, float range, out Vector2 delta)
    {
        Vector2 d      = new Vector2(boat.m_targetWhale.transform.position.x - boatPos.x, boat.m_targetWhale.transform.position.z - boatPos.y);
        float   distSq = d.SqrMagnitude();

        delta = d;
        return(distSq > range * range * 1.1f || Vector2.Dot(d.normalized, boat.m_moveDirection) < m_chaseDetectionProjection);
    }
Example #3
0
    void CreateBoats()
    {
        if (m_waterSimulation == null || !m_waterSimulation.HasObstruction())
        {
            return;
        }

        Vector2 boatPos = new Vector2();
        Vector2 ori     = new Vector2();
        float   anglMod = Random.Range(0.0f, 1.0f);
        float   minDist = m_waterSimulation.m_Scale.x / 8.0f;
        float   maxDist = m_waterSimulation.m_Scale.x / 2.0f;

        for (uint i = 0; i < m_boatCount; i++)
        {
            m_boats[i] = new CBoat();

            float angle = 3.1415926f * 2.0f * (i + anglMod) / m_boatCount;
            ori.x = Mathf.Cos(angle);
            ori.y = Mathf.Sin(angle);

            uint j;
            for (j = 0; j < 10; j++)
            {
                float dist = Random.Range(minDist, maxDist);
                boatPos = ori * dist;
                if (m_waterSimulation.GetObstruction(boatPos.x, boatPos.y) > m_occlusionHeight)
                {
                    break;
                }
            }

            // Unlikely, but just don't create the boat for now =P
            if (j >= 10)
            {
                Debug.Log("Could not find place for boat =(");
                continue;
            }

            GameObject newBoat = GameObject.Instantiate(m_boatModel);
            newBoat.transform.SetParent(transform);
            newBoat.transform.localScale = new Vector3(3.0f, 3.0f, 3.0f);
            newBoat.transform.position   = new Vector3(boatPos.x, 0.0f, boatPos.y);

            m_boats[i].m_handle        = newBoat;
            m_boats[i].m_state         = EBoatState.IDLE;
            m_boats[i].m_targetPoint   = new Vector2(Random.Range(boatPos.x - m_boatIdleRange, boatPos.x + m_boatIdleRange), Random.Range(boatPos.y - m_boatIdleRange, boatPos.y + m_boatIdleRange));
            m_boats[i].m_moveDirection = new Vector2(Random.Range(-1.0f, 1.0f), Random.Range(-1.0f, 1.0f));
            m_boats[i].m_moveDirection.Normalize();
            m_boats[i].m_stateTime = m_boatIdleTimeMax;
        }

        m_initialized = true;
    }
Example #4
0
    // Update is called once per frame
    void Update()
    {
        if (m_waterSimulation == null || !m_waterSimulation.HasObstruction())
        {
            return;
        }

        if (!m_initialized)
        {
            CreateBoats();
        }

        // TODO - replace with 2nd-order operation if this becomes too stiff
        float turnAngle = Time.deltaTime * m_boatTurnSpeed;
        float turnX     = Mathf.Cos(turnAngle);
        float turnY     = Mathf.Sin(turnAngle);

        // Boat movement
        for (uint i = 0; i < m_boatCount; i++)
        {
            CBoat   boat    = m_boats[i];
            Vector2 boatPos = new Vector2(boat.m_handle.transform.position.x, boat.m_handle.transform.position.z);

            float boatSpeed = 0.0f;

            // State-specific code
            switch (boat.m_state)
            {
            case EBoatState.IDLE:
            case EBoatState.UNSTUCK:
                boatSpeed = m_boatIdleSpeed;
                break;

            case EBoatState.CHASE:
                if (boat.m_targetWhale == null)
                {
                    SetBoatIdle(boat);
                    break;
                }

                boatSpeed            = m_boatChaseSpeed;
                boat.m_targetPoint.x = boat.m_targetWhale.transform.position.x;
                boat.m_targetPoint.y = boat.m_targetWhale.transform.position.z;
                break;

            case EBoatState.ASSAULT:
                if (boat.m_targetWhale == null)
                {
                    SetBoatIdle(boat);
                    Destroy(m_harpoons[i]);
                    break;
                }

                boatSpeed = 0.0f;
                break;
            }
            ;


            Vector2 vf = m_waterSimulation.SampleVectorFieldWorld(boatPos.x, boatPos.y);

            // Movement code works the same regardless of state
            if (boatSpeed > 0.0f || vf.SqrMagnitude() > 0.0f)
            {
                // Turning
                Vector2 delta = boat.m_targetPoint - boatPos;
                delta.Normalize();
                delta += vf * m_vfTurnMagnitude;

                float perpdp = (delta.x * boat.m_moveDirection.y) - (delta.y * boat.m_moveDirection.x);

                if (perpdp < 0.0f)
                {
                    float tmp = boat.m_moveDirection.x * turnX - boat.m_moveDirection.y * turnY;
                    boat.m_moveDirection.y = boat.m_moveDirection.x * turnY + boat.m_moveDirection.y * turnX;
                    boat.m_moveDirection.x = tmp;
                }
                else
                {
                    float tmp = boat.m_moveDirection.x * turnX + boat.m_moveDirection.y * turnY;
                    boat.m_moveDirection.y = boat.m_moveDirection.y * turnX - boat.m_moveDirection.x * turnY;
                    boat.m_moveDirection.x = tmp;
                }

                // If we completed the turn, just go directly to target
                float newPerp = (delta.x * boat.m_moveDirection.y) - (delta.y * boat.m_moveDirection.x);
                if ((newPerp < 0) != (perpdp < 0))
                {
                    boat.m_moveDirection = delta;
                    boat.m_moveDirection.Normalize();
                }

                boatSpeed += Vector2.Dot(boat.m_moveDirection, vf) * m_vfPushMagnitude;

                // Boat movement
                Vector2 newPos = boatPos + boat.m_moveDirection * boatSpeed * Time.deltaTime;

                // Stuck detection
                if (m_waterSimulation.GetObstruction(newPos.x, newPos.y) < m_occlusionHeight)
                {
                    if (boat.m_state != EBoatState.UNSTUCK)
                    {
                        boat.m_targetPoint = boatPos - boat.m_moveDirection * 32.0f;
                    }
                    boat.m_state = EBoatState.UNSTUCK;
                }
                else
                {
                    boatPos = newPos;
                }

                Vector3 normal;
                float   height = m_waterSimulation.GetWaterHeightNormal(boatPos.x, boatPos.y, out normal);

                // Update position
                boat.m_handle.transform.position = new Vector3(boatPos.x, height + m_boatRenderHeight, boatPos.y);

                // Update orientation (yeah, it's a bit iffy with axes, broken model =P)
                Vector3    forward = new Vector3(boat.m_moveDirection.x, 0, boat.m_moveDirection.y);
                Vector3    up      = normal;
                Vector3    right   = Vector3.Cross(up, forward);
                Quaternion q       = new Quaternion();
                q.SetLookRotation(up, right);
                boat.m_handle.transform.rotation = q;
            }

            // Post-movement state
            switch (boat.m_state)
            {
            case EBoatState.IDLE:
            case EBoatState.UNSTUCK:
                boat.m_stateTime -= Time.deltaTime;
                if ((boatPos - boat.m_targetPoint).SqrMagnitude() < 12.0f * 12.0f || boat.m_stateTime < 0.0f)
                {
                    SetBoatIdle(boat);
                }

                // Enumerate whales
                if (m_whaleManager != null)
                {
                    List <GameObject> whales;
                    m_whaleManager.EnumerateWhalesInRange(boat.m_handle.transform.position, m_chaseDetectionRange, out whales);
                    foreach (GameObject whale in whales)
                    {
                        Vector2 delta = new Vector2();
                        delta.x = whale.transform.position.x - boatPos.x;
                        delta.y = whale.transform.position.z - boatPos.y;
                        delta.Normalize();
                        if (Vector2.Dot(delta, m_boats[i].m_moveDirection) >= m_chaseDetectionProjection)
                        {
                            boat.m_state       = EBoatState.CHASE;
                            boat.m_targetWhale = whale;
                            SoundManager.Get().PlayOneShotSound(m_boatSound, m_boatVolume, boat.m_handle.transform.position);
                        }
                    }
                }
                break;

            case EBoatState.CHASE:
            {
                Vector2 delta;
                if (HasBoatLostTarget(boat, boatPos, m_chaseDetectionRange, out delta))
                {
                    SetBoatIdle(boat);
                }
                else if (delta.SqrMagnitude() < m_assaultRange * m_assaultRange)
                {
                    boat.m_state     = EBoatState.ASSAULT;
                    boat.m_stateTime = m_harpoonTime;
                    m_harpoons[i]    = GameObject.Instantiate(m_harpoonModel);
                    m_harpoons[i].transform.SetParent(transform);
                    m_harpoons[i].transform.localScale = new Vector3(3.0f, 3.0f, 3.0f);
                    m_harpoons[i].transform.position   = new Vector3(boatPos.x, 0.0f, boatPos.y);
                    SoundManager.Get().PlayOneShotRandomSound(m_harpoonSounds, m_harpoonVolume, m_harpoons[i].transform.position);
                }
            }
            break;

            case EBoatState.ASSAULT:
            {
                Vector2 delta;
                if (HasBoatLostTarget(boat, boatPos, m_assaultRange, out delta))
                {
                    SetBoatIdle(boat);
                    Destroy(m_harpoons[i]);
                }
                else
                {
                    delta.x          += m_whaleTargetOffset.x;
                    delta.y          += m_whaleTargetOffset.z;
                    boat.m_stateTime -= Time.deltaTime;
                    if (boat.m_stateTime < 0)
                    {
                        boat.m_targetWhale.GetComponent <Whale>().Damage();
                        boat.m_stateTime = m_harpoonTime;
                        SoundManager.Get().PlayOneShotRandomSound(m_harpoonSounds, m_harpoonVolume, m_harpoons[i].transform.position);
                    }
                    m_harpoons[i].transform.position = Vector3.Lerp(boat.m_targetWhale.transform.position + m_whaleTargetOffset, boat.m_handle.transform.position, boat.m_stateTime / m_harpoonTime);

                    const float c_arcHeight = 8.0f;
                    float       halfTime    = m_harpoonTime * 0.5f;
                    float       baseSpeed   = 2.0f * c_arcHeight / halfTime;
                    float       baseAccel   = -c_arcHeight / (halfTime * halfTime);

                    float activeTime = m_harpoonTime - boat.m_stateTime;
                    m_harpoons[i].transform.position += new Vector3(0, baseAccel * activeTime * activeTime + baseSpeed * activeTime, 0);

                    float yDir = (2 * baseAccel * activeTime + baseSpeed);
                    m_harpoons[i].transform.right = new Vector3(delta.x, yDir, delta.y);
                }
            }
            break;
            }
        }
    }