This is a long an complex tutorial. Take your time and know that it will be frustrating at times.

The class below is attached to a pick up or power up object.

It is used to store details of the type of powerup that it is so that the player can be updated correctly.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PickUpProperties : MonoBehaviour
{
    public string type;
    public float durationSeconds = 3.0f;
    public float pickupImpactMultiplier = 5.0f;
}

Below is the code for running a timed pickup on the player.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerPickUpManager : MonoBehaviour
{
    private bool speedPickUpActive = false;
    private bool sizePickUpActive = false;

    // Check if objects are overlapping
    void OnTriggerEnter(Collider col) {
        //Debug.Log("I hit something");
        if(col.CompareTag("PickUp")) {
            //Debug.Log("I hit a pickup");
            //

            // Determine type of pickup
            GameObject pickup = col.gameObject;
            PickUpProperties pickupHit;
            if(pickup.TryGetComponent<PickUpProperties>(out pickupHit)) {
                // Check the type of pickup
                if(pickupHit.type == "size" && speedPickUpActive == false) {
                    Debug.Log("Size hit");
                    transform.localScale = transform.localScale * pickupHit.pickupImpactMultiplier;
                    sizePickUpActive = true;
                } else if(pickupHit.type == "speed") {
                    Debug.Log("Speed hit");
                    PlayerMovement playerMovement;
                    if(TryGetComponent<PlayerMovement>(out playerMovement)) {
                        // Gets here if the player movement script found
                        playerMovement.SetSpeed(playerMovement.GetSpeed() * pickupHit.pickupImpactMultiplier);
                        speedPickUpActive = true;
                    }
                }
                StartCoroutine(Timer(pickupHit.durationSeconds, pickup, pickupHit.pickupImpactMultiplier));
            }

            
        }
    }

    IEnumerator Timer(float timeDelay, GameObject go, float multipler) {
        go.SetActive(false);

        // Wait for timeDelay seconds
        yield return new WaitForSeconds(timeDelay);

        if(sizePickUpActive) {
            sizePickUpActive = false;
            transform.localScale = transform.localScale / multipler;
        }
        if(speedPickUpActive) {
            speedPickUpActive = false;
            PlayerMovement playerMovement;
            if(TryGetComponent<PlayerMovement>(out playerMovement)) {
                playerMovement.SetSpeed(playerMovement.GetSpeed() / multipler);
            }
        }


        go.SetActive(true);
    }
}

A basic playermovement script with speed Get and Set methods.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

[RequireComponent(typeof(CharacterController))]
public class PlayerMovement : MonoBehaviour
{
    // Player Variables
    private CharacterController _characterController;
    private float _speed = 5.0f;
    private Vector2 _playerMovementInput; 

    public float GetSpeed() {
        return _speed;
    }
    public void SetSpeed(float speed) {
        _speed = speed;
    }

    // Start is called before the first frame update
    void Start()
    {
        _characterController = GetComponent<CharacterController>();
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        MovePlayer();
    }

    void MovePlayer() {
        Vector3 movement = new Vector3(_playerMovementInput.x, 0.0f , _playerMovementInput.y);

        _characterController.SimpleMove(movement * _speed);
        //_characterController.Move(movement * _speed * Time.deltaTime);
    }

    void OnMove(InputValue iv) {
        _playerMovementInput = iv.Get<Vector2>();
    }
}

You might also like