Ejemplo n.º 1
0
    void StopBacking()
    {
        _hasInvokedStopBacking = false;

        if (_isBacking)
        {
            Freeze(false);
            _isBacking = false;
            _state = PokeballState.Lying;
        }
    }
Ejemplo n.º 2
0
    void Update()
    {
        _verticesToDraw.Clear(); // A virer.

        //if (_state == PokeballState.Lying && Hub.rightHand.index != SteamVR_TrackedObject.EIndex.None)
        //{
        //    SteamVR_Controller.Device device = SteamVR_Controller.Input((int)Hub.rightHand.index);
        //    if (device.GetPress(SteamVR_Controller.ButtonMask.ApplicationMenu))
        //    {
        //        BackToHand(Hub.rightHand.transform.position);
        //    }
        //}

        // --- Any kind of Pokeball. ---

        if (Input.GetKeyDown(KeyCode.E))
        {
            Explode();
        }

        if (_state == PokeballState.Lying
            || _state == PokeballState.Held
            || _state == PokeballState.Thrown
            || _state == PokeballState.Backing)
        {
            // Note: as this is not set exactly when the state changes, there might be a 1 frame shifting that could be exploited by players.
            _grabbableObj.SetGrabbable(true);
        }
        else
        {
            _grabbableObj.SetGrabbable(false);
        }

        if (_state == PokeballState.Held && !_isLaserActive && _content != null && !_isPokemonInside && Hub.playerHeight > 0f)
        {
            // When the Pokeball is held, it has to face the right direction so the player can see the button.

            if (ShouldTriggerLaser())
            {
                // If the player extends his arm towards its battling Pokemon, while at pointing the front of the pokeball at it, and while looking at it, it triggers the recalling laser of the Pokeball.

                _isLaserActive = true;
                ActivateRecallingLaser();
            }
        }

        if (_isLaserActive)
        {
            if (!ShouldTriggerLaser())
            {
                _isLaserActive = false;
                DisactivateRecallingLaser();
            }
        }

        if (_state == PokeballState.Held && !_grabbableObj.IsGrabbed())
        {
            /// Here we have to determine a target in order to make the assisted guidance work.
            /// I say we do the following: we know the angle, and the force of the ball. Therefore, we can predict where it's going to fall.
            /// If the pokeball will fall within a reasonable range of a wild pokemon, then we set it as the target.
            /// Otherwise, there will be no auto guidance.
            /// This is made so to catch a pokemon, you'll still have to aim well, but not perfectly.

            if (Spawner.WildPokemons.Count == 1)
            {
                _target = Spawner.WildPokemons[0].GetComponent<Pokemon>();
            }

            _state = PokeballState.Thrown;
        }

        if (false) // Button pushed.
        {
            Shrink();
        }

        if (_content == null && _state == PokeballState.Thrown)
        {
            if (_target != null)
            {
                // Assisted guidance of the pokeball so it's easier to aim for one.

                Vector3 vel = _rigid.velocity;
                Vector3 distanceToTarget = (_target.transform.position + Vector3.up * _target.GetRealHeight()) - _tr.position;
                Vector3 towardsTarget = distanceToTarget.normalized * vel.magnitude;

                Vector3 adjustedVelocity = Vector3.Lerp(vel, towardsTarget, Mathf.Min(0.03f, 1f / (20f * Mathf.Pow(distanceToTarget.magnitude, 3f))));
                _rigid.velocity = adjustedVelocity;
            }
        }
        else if (_state == PokeballState.BouncingBack)
        {
            Vector3 distToDest = _destination - _tr.position;

            if (distToDest.magnitude > 0.01f)
            {
                float speed = 4f;

                _tr.position += distToDest * speed * Time.deltaTime;

                Pokemon targetPkmn = _content;
                if (targetPkmn == null)
                {
                    targetPkmn = _temporaryContent;
                }

                Vector3 destinationAngle = targetPkmn.transform.position - _tr.position;
                destinationAngle.Normalize();
                _tr.forward = Vector3.Slerp(_tr.forward, destinationAngle, speed * 2f * Time.deltaTime);
            }
            else
            {
                _state = PokeballState.Opening;
                Freeze(true);

                _animator.SetBool("Open", true);

                if (_content == null)
                {

                }
                else if (_isPokemonInside)
                {
                    PlaySound("ReleasePokemon");
                }
            }
        }
        else if (_state == PokeballState.Falling)
        {
            if (_rigid.velocity.magnitude < 0.05f && _tr.position.y < 0.05f)
            {
                _state = PokeballState.Shaking;
            }
        }

        // --- Empty Pokéball. ---
        if (_content == null)
        {
            if (_state == PokeballState.Thrown && !_shrinked)
            {
                CheckCapture();
            }

            if (_state == PokeballState.Shaking)
            {
                if (_shakeLeft == -1 && _rigid.velocity.magnitude < 0.02f)
                {
                    _shakeLeft = Random.Range(4, 6);
                    //StopMove();
                    Invoke("ShakeOnce", 0.75f);
                }
            }
        }
        // --- Loaded Pokéball. ---
        else
        {

        }

        if (_isBacking)
        {
            BackToHand();
        }
    }
Ejemplo n.º 3
0
    private void ShakeOnce()
    {
        if (_state != PokeballState.Shaking)
        {
            return;
        }

        _shakeLeft--;

        if (_shakeLeft > 0)
        {
            // For now Pokéballs are Masterballs.

            float escapeChance = 0.045f; // We should get this value from the Pokemon stats. // 0.045 escape chance makes a capture probability between 75% to 83% after 4 to 6 shakes.

            if (Random.value < escapeChance)
            {
                Explode();
            }
            else
            {
                Vector3 force = Random.onUnitSphere * 0.3f;
                force.y = 0;

                Freeze(false);
                StopMove();
                _rigid.AddForce(force, ForceMode.VelocityChange);
                PlaySound("Shake");

                float delay = Random.Range(1.3f, 2f) + (_shakeLeft == 1 ? 1.2f : 0f);

                //if (_editorTest)
                {
                    delay *= 0.75f;
                }

                //object[] parms = new object[2] { -force, delay / 2f };
                object[] parms = new object[2] { -force, 0.25f };

                StartCoroutine("BalanceShakeForce", parms);
                Invoke("ShakeOnce", delay);
            }
        }
        else
        {
            // The capture is a success!

            _state = PokeballState.Lying;
            _isPokemonInside = true;

            _shakeLeft = -1;

            _content = _temporaryContent;
            _content.StoreInPokeball();
            _content.SetCaptureResult(true);
            _pkmnName.text = _content._name;

            _temporaryContent = null;
            StopMove();
            _animator.SetBool("RedLightOn", false);
            PlaySound("Caught");

            Instantiate(Resources.Load("Particles/CaptureParticle"), _tr.position, Quaternion.identity);

            //StartBacking();
            StartCoroutine(StartBackingWithDelayCoroutine(2.25f));
        }
    }
Ejemplo n.º 4
0
    void Start()
    {
        _tr = this.transform;
        _rigid = GetComponent<Rigidbody>();
        _animator = GetComponent<Animator>();
        _audioSource = GetComponent<AudioSource>();

        if (_editorTest)
        {
            _state = PokeballState.Thrown;
        }

        if (_rigid == null)
        {
            Debug.LogError("No rigidbody attached to the pokeball");
            DestroyImmediate(this);
        }

        if (_animator == null)
        {
            Debug.LogError("No animator attached to the pokeball");
            DestroyImmediate(this);
        }

        if (_content == null)
        {
            _pkmnName.text = "";
        }

        DisactivateRecallingLaser();

        _grabbableObj.Grabbed += OnGrabbed;

        _tr.position = Camera.main.transform.position + Camera.main.transform.forward * 0.4f + Vector3.up * 0.4f;
    }
Ejemplo n.º 5
0
 private void OnGrabbed()
 {
     _state = PokeballState.Held;
     PlaySound("PickedUp");
     _isBacking = false;
 }
Ejemplo n.º 6
0
    private void OpeningDone()
    {
        if (_state == PokeballState.Opening)
        {
            if (_content == null)
            {
                _state = PokeballState.Swallowing; // The next state will be called by the animation once it's done.

                // Do calls on the Pokemon.
                //_temporaryContent.Swallow(this);
                ConvertToRedEnergy(true);
            }
            else if (_isPokemonInside)
            {
                _state = PokeballState.Releasing; // This phase is actually usuless, it's just a delay so that the pokeball stays mid air for a short time. It's not synchronized with the pokemon appearance animation.

                _isPokemonInside = false;

                // Do calls on the Pokemon.
                _content.ReleaseFromPokeball();

                Invoke("Close", 0.3f);
            }
        }
    }
Ejemplo n.º 7
0
    private void ClosingDone()
    {
        // Is called by the animation when the pokeball is fully opened.

        if (_state == PokeballState.Closing)
        {
            // After swallowing a Pokemon, the Pokeball falls down.
            if (_content == null)
            {
                _state = PokeballState.Falling;
                _animator.SetBool("RedLightOn", true);

                Freeze(false);
            }
            else
            {
                // The ball goes back to the player's hand after releasing the Pokemon it contains.
                StartCoroutine(StartBackingWithDelayCoroutine(0.5f));

                //Freeze(false);
            }
        }
    }
Ejemplo n.º 8
0
    void Explode()
    {
        _state = PokeballState.Breaking;

        _animator.SetBool("RedLightOn", false);

        if (_temporaryContent != null)
        {
            _temporaryContent.gameObject.SetActive(true);
            _temporaryContent.transform.position = _tr.position;
            _temporaryContent.SetCaptureResult(false);
            Spawner.WildPokemons.Add(_temporaryContent.GetComponent<SphereCollider>());
            _temporaryContent = null;
        }

        if (_content != null)
        {
            _content.gameObject.SetActive(true);
            _content.transform.position = _tr.position;
            _content.SetCaptureResult(false);
            Spawner.WildPokemons.Add(_content.GetComponent<SphereCollider>());
            _content = null;
        }

        if (_bottomPart == null || _topPart == null)
        {
            return;
        }

        Destroy(_grabbableObj);
        Destroy(_animator);

        Vector3 explosionPos = _tr.position;
        explosionPos.y = 0f;

        Rigidbody bottomRigid = _bottomPart.parent.gameObject.AddComponent<Rigidbody>();
        CopyRigidbody(_rigid, ref bottomRigid);
        bottomRigid.AddExplosionForce(60f, explosionPos, 10f);
        bottomRigid.angularVelocity = Random.onUnitSphere;
        _bottomPart.GetComponent<MeshCollider>().enabled = true;

        Rigidbody topRigid = _topPart.parent.gameObject.AddComponent<Rigidbody>();
        CopyRigidbody(_rigid, ref topRigid);
        topRigid.AddExplosionForce(60f, explosionPos, 10f);
        topRigid.angularVelocity = Random.onUnitSphere;
        _topPart.GetComponent<MeshCollider>().enabled = true;

        if (_buttonPart != null)
        {
            _buttonPart.GetComponent<MeshCollider>().enabled = true;
        }

        Destroy(_rigid);

        // Then we should destroy the pokeball a little later, ideally with an animation.
        StartCoroutine(DestroyWithDelayCoroutine(topRigid, bottomRigid, 4f, 10f, 0.5f));
    }
Ejemplo n.º 9
0
 private void Close()
 {
     _state = PokeballState.Closing;
     _animator.SetBool("Open", false);
 }
Ejemplo n.º 10
0
    private bool CheckCapture()
    {
        // We check if the pokeball hit a pokemon.
        Vector3 pos = _tr.position;
        foreach (SphereCollider pk in Spawner.WildPokemons)
        {
            // To reduce the amount of calculation, we first check if the pokeball is close enough to the pokemon.
            Transform pkTr = pk.transform;
            float maxScale = Mathf.Max(pk.transform.lossyScale.x, pk.transform.lossyScale.y, pk.transform.lossyScale.z);
            if ((pos - (pkTr.TransformPoint(pk.center))).magnitude < pk.radius * maxScale)
            {
                //Debug.Break();
                SkinnedMeshRenderer[] renderers = pk.GetComponentsInChildren<SkinnedMeshRenderer>();

                // A pokemon is supposed to have one mesh. This script has been built on that hypothesis, so we better check.
                if (renderers.Length > 1f)
                {
                    Debug.LogError("More than one skin renderers found on " + pk.name + ":");

                    foreach (Renderer rend in renderers)
                    {
                        Debug.LogError("- " + rend.name);
                    }

                    Debug.Break();
                    DestroyImmediate(this);
                    return false;
                }
                else if (renderers.Length <= 0)
                {
                    Debug.LogError("No skin renderer found for " + pk.name + ":");

                    Debug.Break();
                    DestroyImmediate(this);
                    return false;
                }
                else if (renderers.Length == 1)
                {
                    Mesh mesh = new Mesh();
                    renderers[0].BakeMesh(mesh); // This may take a lot of time and shouldn't be called every frame! Especially at 90 FPS!

                    //Vector3 posBis = pos - pkTr.position; // This represents the position of the pokeball relative to the pokemon space (so we don't have to convert every vertex of the pokemon to world space).
                    foreach (Vector3 vertex in mesh.vertices)
                    {
                        // If a vertex of a pokemon is within the ball radius, then it is captured! Watch out though: a pokemon with wide space between its vertices (like big wings) may be missed by the pokeball.
                        Vector3 vertexWorldPos = pkTr.position + pkTr.rotation * vertex; // pkTr.TransformPoint(vertex); //
                        _verticesToDraw.Add(vertexWorldPos); // A virer.
                        Vector3 distance = (pos - vertexWorldPos);
                        if (distance.magnitude < _pokeballCatchRadius)
                        {
                            // Pokémon touched!

                            Debug.Log(pk.name + " as been touched!");

                            Pokemon pkmn = pkTr.GetComponent<Pokemon>();
                            _destination = pkmn.Touched(this);

                            if (_destination == Vector3.zero)
                            {
                                Debug.Log("... but " + pk.name + " has already been captured.");
                                _state = PokeballState.Breaking;
                                return false;
                            }

                            PlaySound("PokemonImpact");

                            _state = PokeballState.BouncingBack;
                            _destination += _tr.position;
                            Freeze(true);

                            _temporaryContent = pkmn;
                            _target = null;

                            Spawner.WildPokemons.Remove(pk);

                            return true;
                        }
                    }
                }
            }
        }

        return false;
    }
Ejemplo n.º 11
0
    public void StartBacking(Vector3? dest_ = null)
    {
        if (_state == PokeballState.Lying
            || (_content == null && _state == PokeballState.Thrown)
            || (_content != null && _state == PokeballState.Closing))
        {
            //if ((_tr.position - Camera.main.transform.position).magnitude > 1f) // We allow the pokeball to back only if it's far from the player. Otherwise it would look bad. Anyway if the pokeball is close by the player, he better go pick it up by himself!
            {
                _state = PokeballState.Backing;
                _backingOrigin = _tr.position;

                if (dest_ != null)
                {
                    _backingDestination = (Vector3)dest_;
                }
                else
                {
                    if (false && (Hub.rightHand != null || Hub.leftHand != null))
                    {
                        Transform hand = (Hub.rightHand != null ? Hub.rightHand.transform : Hub.leftHand.transform);
                        _backingDestination = hand.position;
                        _backingDestination += (_backingOrigin - hand.position).normalized * 0.3f;
                        _backingDestination.y = Camera.main.transform.position.y * 0.8f;
                    }
                    else // If no hand is detected, we'll use the head as a target instead. Actually this formula may be better than the previous one!
                    {
                        Transform hand = Camera.main.transform;
                        _backingDestination = hand.position;
                        //_backingDestination += (_backingOrigin - hand.position).normalized * 0.3f;
                        _backingDestination += hand.forward * 0.45f;
                        _backingDestination += hand.right * 0.3f;
                        _backingDestination.y = Camera.main.transform.position.y * 0.8f;
                    }
                }

                // We want the speed of the pokeball to go slower when it's closer and we'd like to keep an average back time close to 1 second when the pokeball is far away. However, to look realistic, we set a max speed to the pokeball.
                Vector3 travel = _tr.position - _backingDestination;
                float pokeballMaxSpeed = 20f;
                float backingSpeed = 3f;
                float backingDesiredDuration = 1f;
                _backingTotalDuration = travel.magnitude / backingSpeed;

                if (_backingTotalDuration > backingDesiredDuration)
                {
                    _backingTotalDuration = Mathf.Lerp(_backingTotalDuration, backingDesiredDuration, 0.85f);
                }

                if (travel.magnitude / _backingTotalDuration > pokeballMaxSpeed) // If the pokeball speed is higher than its max speed, we cap it to its max speed, so the travel of the pokeball looks credible.
                {
                    _backingTotalDuration = travel.magnitude / pokeballMaxSpeed;
                }

                _backingDuration = 0f;
                _isBacking = true;
            }
        }
    }
Ejemplo n.º 12
0
    public void OnCollisionEnter(Collision collision)
    {
        bool soundPlayed = false;

        if (_state == PokeballState.Thrown)
        {
            if (!_editorTest)
            {
                Vector3 camPos = Camera.main.transform.position;
                Vector2 playerPos = new Vector2(camPos.x, camPos.z);
                Vector2 ballPos = new Vector2(_tr.position.x, _tr.position.z);

                float horizontalDistanceToPlayer = (playerPos - ballPos).magnitude;
                if (_content != null && _isPokemonInside && horizontalDistanceToPlayer > 1f)
                {
                    if (collision.contacts[0].point.y < 0.05f && Trainer._pkmnInBattle == null)
                    {
                        _content.gameObject.SetActive(true);
                        Trainer._pkmnInBattle = _content;

                        _destination = _tr.position + Camera.main.transform.right + Vector3.up * Mathf.Max(1f, _content.GetRealHeight() * 1.1f);

                        _content.transform.position = _tr.position;

                        Vector3 forward = _tr.position - Camera.main.transform.position;
                        forward.y = 0f;
                        forward.Normalize();

                        // We want to keep at least 50cm between the trainer and the Pokémon he is currently releasing from the this pokeball.
                        float pkmnDepth = _content.GetBaseBoundingBoxSize().z / 2f;
                        if (horizontalDistanceToPlayer < 0.5f + pkmnDepth)
                        {
                            _content.transform.position += forward * (pkmnDepth + 0.5f - horizontalDistanceToPlayer);
                        }

                        _content.transform.LookAt(_content.transform.position + forward, Vector3.up);

                        Freeze(true);
                        _state = PokeballState.BouncingBack;

                        PlaySound("PokemonImpact");
                        soundPlayed = true;
                    }
                    else
                    {
                        // The trainer tried to send out his Pokémon, but his throw ended in a wrong spot. So we tell the Pokéball to go back.
                        StartBacking();
                    }
                }
                else if (_content == null) // A virer ?
                {
                    /// Thoughts:
                    /// Making an empty pokeball go back to the trainer after a missed throw allows the player to use it several times until it breaks.
                    /// This behaviour doesn't exist neither in the anime nor in the video games.
                    /// It the pokeball doesn't come back, the player can't use it again during this battle as the pokeball will be close to the wild pokemon.
                    /// He could pick it up after the battle to refill its inventory, which is great!
                    /// Throwing the pokeball back at him might be over powered and makes no sense. So actually, we'll get rid of it after the test phase :)

                    _missedShots++;

                    if (_missedShots > 4)
                    {
                        Explode();
                    }
                    else
                    {
                        _state = PokeballState.Lying;
                        //StartBacking();
                    }
                }
                else
                {
                    _state = PokeballState.Lying;
                }
            }
        }

        if (!soundPlayed)
        {
            float mag = collision.impulse.magnitude;
            if (mag > 0.05f)
            {
                float volume = Mathf.Clamp01(mag);
                volume = Mathf.Pow(volume, 0.5f);
                //volume *= volume;
                volume /= 2f;

                PlaySound("GroundImpact", volume);
            }
        }
    }
Ejemplo n.º 13
0
 public void EndSwallow()
 {
     _state = PokeballState.Closing;
     _animator.SetBool("Open", false);
 }