Forum begins after the advertisement:

 


[Part 15] Problem with Passive item

Home Forums Video Game Tutorial Series Creating a Rogue-like Shoot-em Up in Unity [Part 15] Problem with Passive item

Viewing 10 posts - 1 through 10 (of 10 total)
  • Author
    Posts
  • #18374
    Kim Il Woo (FGW HCM)
    Level 5
    Participant
    Helpful?
    Up
    0
    ::

    This happen when I choose a new passive (example: when I choose wing passive there only one buff in it which is move speed buff set to 10 the other buff I dont write any number in it, after choose the wing every stats of the player set to exactly like the wing stats) Any Idea how to fix this problem

    #18375
    Alp Apustaja
    Level 9
    AI Assistant
    (BETA)
    Helpful?
    Up
    0
    ::

    Based on the reference information provided, the issue seems to be related to how passive items are applying their modifiers. The current implementation might be resetting all stats instead of incrementally modifying them.

    To fix this, you should modify the passive item application logic to:

    1. Use incremental modifications (multipliers or additions) instead of direct replacements
    2. Ensure only specified stats are modified
    3. Preserve other stat values when applying a new passive item

    However, the exact implementation details are NOT_FOUND in the given reference information. I would need to see the full implementation of the PassiveItem script and how passive items are being applied to provide a precise solution.

    Clarifying question: Can you share the full code for your PassiveItem script and how you’re currently applying passive item modifiers?

    #18376
    Kim Il Woo (FGW HCM)
    Level 5
    Participant
    Helpful?
    Up
    0
    ::
    using UnityEngine;
    
    
    //replacement of passiveitemscriptableobject class
    [CreateAssetMenu(fileName = "Passive Data", menuName = "2D Top-down Rogue-like/Passive Data")]
    public class PassiveData : ItemData
    {
        public Passive.Modifier baseStats;
        public Passive.Modifier[] growth;
    
        public Passive.Modifier GetLevelData(int Level)
        {
            if (Level - 2 < growth.Length)
            {
                return growth[Level - 2];
            }
    
            Debug.LogWarning(string.Format("Passive doesnt habe its level up stats config", Level));
            return new Passive.Modifier();
        }
    }
    
    
    using UnityEngine;
    
    //a class that takes an passivedata and used to increase a player stat
    public class Passive : Item
    {
        public PassiveData data;
        [SerializeField] CharacterData.Stats currentBoosts;
    
        [System.Serializable]
        public struct Modifier
        {
            public string name, description;
            public CharacterData.Stats boosts;
        }
    
        public virtual void Initialise(PassiveData data)
        {
            base.Initialise(data);
            this.data = data;
            currentBoosts = data.baseStats.boosts;
        }
    
        public virtual CharacterData.Stats GetBoosts()
        {
            return currentBoosts;
        }
    
        public override bool DoLevelUp()
        {
            base.DoLevelUp();
    
            //prevent levelup when max level
            if (!CanLevelUp())
            {
                Debug.LogWarning(string.Format("cannot level up [0] to level [1], max level reached", name, currentLevel, data.maxLevel));
                return false;
            }
    
            currentBoosts += data.GetLevelData(++currentLevel).boosts;
            return true;
        }
    }
    
    #18377
    Alp Apustaja
    Level 9
    AI Assistant
    (BETA)
    Helpful?
    Up
    0
    ::

    Based on the code provided, the issue is likely in the WingsPassiveItem script. The current implementation directly sets the player’s move speed instead of incrementally modifying it.

    Here’s a corrected version of the WingsPassiveItem script:

    protected override void ApplyModifier() 
    {
        // Increment move speed by the multiplier percentage
        player.currentMoveSpeed += player.currentMoveSpeed * (passiveItemData.Multiplier / 100f);
    }

    This change ensures that:

    1. The existing move speed is preserved
    2. The new speed is calculated as an incremental increase
    3. Other stats remain unchanged

    Would you like me to elaborate on how this modification addresses the stat reset issue?

    #18378
    Kim Il Woo (FGW HCM)
    Level 5
    Participant
    Helpful?
    Up
    1
    ::
    using UnityEngine;
    
    //a class that takes an passivedata and used to increase a player stat
    public class Passive : Item
    {
        public PassiveData data;
        [SerializeField] CharacterData.Stats currentBoosts;
    
        [System.Serializable]
        public struct Modifier
        {
            public string name, description;
            public CharacterData.Stats boosts;
        }
    
        public virtual void Initialise(PassiveData data)
        {
            base.Initialise(data);
            this.data = data;
            currentBoosts = data.baseStats.boosts;
        }
    
        public virtual CharacterData.Stats GetBoosts()
        {
            return currentBoosts;
        }
    
        public override bool DoLevelUp()
        {
            base.DoLevelUp();
    
            //prevent levelup when max level
            if (!CanLevelUp())
            {
                Debug.LogWarning(string.Format("cannot level up [0] to level [1], max level reached", name, currentLevel, data.maxLevel));
                return false;
            }
    
            currentBoosts += data.GetLevelData(++currentLevel).boosts;
            return true;
        }
    }
    

    this is the current way of the passive level up and apply buff

    using UnityEngine;
    
    
    //replacement of passiveitemscriptableobject class
    [CreateAssetMenu(fileName = "Passive Data", menuName = "2D Top-down Rogue-like/Passive Data")]
    public class PassiveData : ItemData
    {
        public Passive.Modifier baseStats;
        public Passive.Modifier[] growth;
    
        public Passive.Modifier GetLevelData(int Level)
        {
            if (Level - 2 < growth.Length)
            {
                return growth[Level - 2];
            }
    
            Debug.LogWarning(string.Format("Passive doesnt habe its level up stats config", Level));
            return new Passive.Modifier();
        }
    }
    

    this is the passivedata currenly not using any other passive script beside this

    has upvoted this post.
    #18379
    Alp Apustaja
    Level 9
    AI Assistant
    (BETA)
    Helpful?
    Up
    1
    ::

    Based on the provided code, the issue might be in how the initial passive stats are set and applied. The current implementation sets currentBoosts to data.baseStats.boosts during initialization, which could potentially replace all existing stats.

    To fix this, modify the Initialise method to incrementally add stats instead of replacing them:

    public virtual void Initialise(PassiveData data)
    {
        base.Initialise(data);
        this.data = data;
    
        // Instead of directly setting currentBoosts, add the base stats
        if (Owner != null && Owner.Stats != null)
        {
            Owner.Stats.moveSpeed += data.baseStats.boosts.moveSpeed;
            Owner.Stats.health += data.baseStats.boosts.health;
            // Add other stat increments similarly
        }
    
        currentBoosts = data.baseStats.boosts;
    }

    This approach ensures that:

    1. Existing stats are preserved
    2. New passive stats are added incrementally
    3. The currentBoosts still tracks the passive item’s modifications

    Would you like me to elaborate on how this modification prevents stat replacement?

    has upvoted this post.
    #18380
    Kim Il Woo (FGW HCM)
    Level 5
    Participant
    Helpful?
    Up
    1
    ::
    using System.Collections.Generic;
    using TMPro;
    using Unity.VisualScripting;
    using UnityEngine;
    using UnityEngine.UI;
    using System;
    
    public class PlayerStats : MonoBehaviour
    {
        CharacterData characterData;
        public CharacterData.Stats baseStats;
        [SerializeField] CharacterData.Stats actualStats;
    
        float health;
    
    
        #region Current State Properties 
        public float CurrentHealth
        {
            get { return health; }
            set
            {
                //check if the value has change
                if (health != value)
                {
                    health = value;
                    if (GameManager.instance != null)
                    {
                        GameManager.instance.currentHealthDisplay.text = string.Format(
                            "Health: {0} / {1}",
                            health, actualStats.maxHealth
                        );
                    }
                }
            }
        }
    
        public float MaxHealth
        {
            get { return actualStats.maxHealth; }
            set
            {
                //check if the value has change
                if (actualStats.maxHealth != value)
                {
                    actualStats.maxHealth = value;
                    if (GameManager.instance != null)
                    {
                        GameManager.instance.currentHealthDisplay.text = string.Format(
                            "Health: {0} / {1}",
                            health, actualStats.maxHealth
                        );
                    }
                }
            }
        }
    
        public float CurrentRecovery
        {
            get { return Recovery; }
            set { Recovery = value; }
        }
    
        public float Recovery
        {
            get { return actualStats.recovery; }
            set
            {
                //check if the value has change
                if (actualStats.recovery != value)
                {
                    actualStats.recovery = value;
                    if (GameManager.instance != null)
                    {
                        GameManager.instance.currentRecoveryDisplay.text = "Recovery: " + actualStats.recovery;
                    }
                }
            }
        }
    
        public float CurrentMoveSpeed
        {
            get { return MoveSpeed; }
            set { MoveSpeed = value; }
        }
    
        public float MoveSpeed
        {
            get { return actualStats.moveSpeed; }
            set
            {
                //check if the value has change
                if (actualStats.moveSpeed != value)
                {
                    actualStats.moveSpeed = value;
                    if (GameManager.instance != null)
                    {
                        GameManager.instance.currentMoveSpeedDisplay.text = "Move Speed: " + actualStats.moveSpeed;
                    }
                }
            }
        }
    
        public float CurrentMight
        {
            get { return Might; }
            set { Might = value; }
        }
    
        public float Might
        {
            get { return actualStats.might; }
            set
            {
                //check if the value has change
                if (actualStats.might!= value)
                {
                    actualStats.might = value;
                    if (GameManager.instance != null)
                    {
                        GameManager.instance.currentMightDisplay.text = "Might: " + actualStats.might;
                    }
                }
            }
        }
    
        public float CurrentProjectileSpeed
        {
            get { return Speed; }
            set { Speed = value; }
        }
    
        public float Speed
        {
            get { return actualStats.speed; }
            set
            {
                //check if the value has change
                if (actualStats.speed != value)
                {
                    actualStats.speed = value;
                    if (GameManager.instance != null)
                    {
                        GameManager.instance.currentProjectileSpeedDisplay.text = "Projectile Speed: " + actualStats.speed;
                    }
                }
            }
        }
    
        public float CurrentMagnet
        {
            get { return Magnet; }
            set { Magnet = value; }
        }
    
        public float Magnet
        {
            get { return actualStats.magnet; }
            set
            {
                //check if the value has change
                if (actualStats.magnet != value)
                {
                    actualStats.magnet = value;
                    if (GameManager.instance != null)
                    {
                        GameManager.instance.currentMagnetDisplay.text = "Magnet: " + actualStats.magnet;
                    }
                }
            }
        }
        #endregion
    
        public ParticleSystem damageEffect;
    
        //Experience and level for the player
        [Header("Experience/Level")]
        public int experience = 0;
        public int level = 1;
        public int experienceCap;
    
        //Class for defining a level range and the corresponding experience cap increase for that range
        [System.Serializable]
        public class LevelRange
        {
            public int startLevel;
            public int endLevel;
            public int experienceCapIncrease;
        }
    
        //I-Frames
        [Header("I-Frames")]
        public float invincibilityDuration;
        float invincibilityTimer;
        bool isInvincible;
    
        public List<LevelRange> levelRanges;
    
        PlayerInventory inventory;
        public int weaponIndex;
        public int passiveItemIndex;
    
        [Header("UI")]
        public Image healthBar;
        public Image expBar;
        public TMP_Text levelText;
    
        void Awake()
        {
            characterData = CharacterSelector.GetData();
            CharacterSelector.instance.DestroySingleton();
    
            inventory = GetComponent<PlayerInventory>();
    
            //assign the variables
    
            baseStats = actualStats = characterData.stats;
            health = actualStats.maxHealth;
        }
    
        void Start()
        {
            //spawn starting weapon
            inventory.Add(characterData.StartingWeapon);
    
            //initialize the first level cap
            experienceCap = levelRanges[0].experienceCapIncrease;
    
            //set the current stats display
            GameManager.instance.currentHealthDisplay.text = "Health: " + CurrentHealth;
            GameManager.instance.currentRecoveryDisplay.text = "Recovery: " + CurrentRecovery;
            GameManager.instance.currentMoveSpeedDisplay.text = "Move Speed: " + CurrentMoveSpeed;
            GameManager.instance.currentMightDisplay.text = "Might: " + CurrentMight;
            GameManager.instance.currentProjectileSpeedDisplay.text = "Projectile Speed: " + CurrentProjectileSpeed;
            GameManager.instance.currentMagnetDisplay.text = "Magnet: " + CurrentMagnet;
    
            GameManager.instance.AssignChosenCharacterUI(characterData);
    
            UpdateHealthBar();
            UpdateExpBar();
            UpdateLevelText();
        }
    
        void Update()
        {
            if (invincibilityTimer > 0)
            {
                invincibilityTimer -= Time.deltaTime;
            }
            //If the invincibility timer reach 0, set invincibility to false
            else if (isInvincible)
            {
                isInvincible = false;
            }
    
            Recover();
        }
    
        public void RecalculateStats()
        {
            actualStats = baseStats;
            foreach (PlayerInventory.Slot s in inventory.passiveSlots)
            {
                Passive p = s.item as Passive;
                if (p)
                {
                    actualStats += p.GetBoosts();
                }
            }
        }
    
        public void IncreaseExperience(int amount)
        {
            experience += amount;
    
            LevelUpChecker();
    
            UpdateExpBar();
        }
    
        void LevelUpChecker()
        {
            if (experience >= experienceCap)
            {
                level++;
                experience -= experienceCap;
    
                int experienceCapIncrease = 0;
                foreach (LevelRange range in levelRanges)
                {
                    if (level >= range.startLevel && level <= range.endLevel)
                    {
                        experienceCapIncrease = range.experienceCapIncrease;
                        break;
                    }
                }
                experienceCap += experienceCapIncrease;
    
                UpdateLevelText();
    
                GameManager.instance.StartLevelUp();
            }
        }
    
        void UpdateExpBar()
        {
            expBar.fillAmount = (float)experience / experienceCap;
        }
    
        void UpdateLevelText()
        {
            levelText.text = "LV" + level.ToString();
        }
    
        public void TakeDamage(float dmg)
        {
            //check the player when player is not invincible will take damage, reduce health and change to invincible
            if (!isInvincible)
            {
                CurrentHealth -= dmg;
    
                if (damageEffect) Destroy(Instantiate(damageEffect, transform.position, Quaternion.identity), 5f);
    
                invincibilityTimer = invincibilityDuration;
                isInvincible = true;
                if (CurrentHealth <= 0)
                {
                    Kill();
                }
    
                UpdateHealthBar();
            }
        }
    
        void UpdateHealthBar()
        {
            //Update the Health Bar
            healthBar.fillAmount = CurrentHealth / actualStats.maxHealth;
        }
    
        public void Kill()
        {
            if (!GameManager.instance.isGameOver)
            {
                GameManager.instance.AssignLevelReachedUI(level);
                GameManager.instance.AssignChosenWeaponsAndPassiveItemsUI(inventory.weaponSlots, inventory.passiveSlots);
                GameManager.instance.GameOver();
            }
        }
    
        public void RestoreHealth(float amount)
        {
            //only heal when not full health
            if (CurrentHealth < actualStats.maxHealth)
            {
                CurrentHealth += amount;
    
                if (CurrentHealth > actualStats.maxHealth)
                {
                    CurrentHealth = actualStats.maxHealth;
                }
            }
        }
    
        void Recover()
        {
            if (CurrentHealth < actualStats.maxHealth)
            {
                CurrentHealth += CurrentRecovery * Time.deltaTime;
    
                //doesnt recovery over the max health
                if (CurrentHealth > actualStats.maxHealth)
                {
                    CurrentHealth = actualStats.maxHealth;
                }
            }
        }
    
        [System.Obsolete("old function kept to maintain compatibility")]
        public void SpawnWeapon(GameObject weapon)
        {
            //check if slot are full, and return when it is
            if (weaponIndex >= inventory.weaponSlots.Count - 1)
            {
                Debug.Log("Inventory slots already full");
                return;
            }
    
            //spawn the starting weapon
            GameObject spawnedWeapon = Instantiate(weapon, transform.position, Quaternion.identity);
            spawnedWeapon.transform.SetParent(transform); //set weapon to be a child of the player
            //inventory.AddWeapon(weaponIndex, spawnedWeapon.GetComponent<WeaponController>()); //add waepon to it inventory slot index
    
            weaponIndex++;
        }
    
        [System.Obsolete("no need to spawn items directly now")]
        public void SpawnPassiveItem(GameObject passiveItem)
        {
            //check if slot are full, and return when it is
            if (passiveItemIndex >= inventory.passiveSlots.Count - 1)
            {
                Debug.Log("Inventory slots already full");
                return;
            }
    
            //spawn the starting passive item
            GameObject spawnedPassiveItem = Instantiate(passiveItem, transform.position, Quaternion.identity);
            spawnedPassiveItem.transform.SetParent(transform); //set passive item to be a child of the player
            //inventory.AddPassiveItem(passiveItemIndex, spawnedPassiveItem.GetComponent<PassiveItem>()); //add passive item to it inventory slot index
    
            passiveItemIndex++;
        }
    }
    

    Maybe this is the problem for why the passive not modifying?

    has upvoted this post.
    #18381
    Alp Apustaja
    Level 9
    AI Assistant
    (BETA)
    Helpful?
    Up
    1
    ::

    The key issue is in the RecalculateStats() method. Currently, it’s resetting actualStats to baseStats before adding passive boosts, which could cause the problem you’re experiencing.

    To fix this, modify the RecalculateStats() method to preserve the base stats and incrementally add passive boosts:

    public void RecalculateStats()
    {
        // Create a copy of base stats instead of direct assignment
        actualStats = new CharacterData.Stats(baseStats);
    
        foreach (PlayerInventory.Slot s in inventory.passiveSlots)
        {
            Passive p = s.item as Passive;
            if (p)
            {
                // Add boosts incrementally
                actualStats.moveSpeed += p.GetBoosts().moveSpeed;
                actualStats.maxHealth += p.GetBoosts().maxHealth;
                // Add other stat increments similarly
            }
        }
    }

    Would you like me to elaborate on how this modification prevents stat replacement?

    has upvoted this post.
    #18382
    Kim Il Woo (FGW HCM)
    Level 5
    Participant
    Helpful?
    Up
    1
    ::

    fixed

    has upvoted this post.
    #18383
    Alp Apustaja
    Level 9
    AI Assistant
    (BETA)
    Helpful?
    Up
    1
    ::

    Great! I’m glad the solution helped resolve the issue with passive item stat modifications.

    To ensure the fix works correctly, could you confirm:

    1. Did you implement the changes to RecalculateStats() method?
    2. Are all player stats now incrementing correctly when adding passive items?
    3. Did you need to make any additional modifications to the code?

    If you have any further questions or need more detailed assistance, please provide more specific information about the implementation or any remaining issues.

    has upvoted this post.
Viewing 10 posts - 1 through 10 (of 10 total)
  • You must be logged in to reply to this topic.

Go to Login Page →


Advertisement below: