Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

How should I put this together?

Discussion in 'Scripting' started by Not_Sure, May 26, 2016.

  1. Not_Sure

    Not_Sure

    Joined:
    Dec 13, 2011
    Posts:
    3,541
    I'm really struggling with structure and would love to know how you would do this scenario.

    Super basic stuff.


    So you've got a player object and a mob object.

    The player object has a controller to take player input, while the mob has an AI controller.

    Both are character class which contain stats variables. For the sake of conversation we'll say the stats are "healthPoints" and "attackDamage".

    Now how would I go about making a global attack function that both objects can use and input their stats and then alter them?

    Where would I place the script that declares the global attack function?

    How should I fit in the fact that they're both characters, but have different controllers?

    And where should I declare the values of the stats?

    Thank you in advance for any help you can offer.
     
    Last edited: May 26, 2016
  2. traderain

    traderain

    Joined:
    Jul 7, 2014
    Posts:
    108
    So if I were you I would create a singleton which holds my stats for the player and I would have a function to update the current enemy's stats to the singleton object. Then in FixedUpdate(), let's say we have a method calles Attack()
    so do something like this:
    Code (CSharp):
    1.  
    2. void FixedUpdate()
    3. {
    4.    if(input.GetKey(mouse1)
    5.    {
    6.       getenemystats();
    7.       Attack();
    8.    }
    9. }
    10.  
    https://msdn.microsoft.com/en-us/library/ff650316.aspx


    ps.: the code is just a POC
     
  3. RavenOfCode

    RavenOfCode

    Joined:
    Apr 5, 2015
    Posts:
    869
    I assume your attacks are done via Raycasts or Colliders? If so then you can just call something like this:
    Code (CSharp):
    1. OnTriggerEnter (Collider other)
    2. {
    3. if (other.gameObject.tag == "Enemy")
    4. {
    5. EnemyController eC = other.gameObject.GetComponent<EnemyController>();
    6. eC.TakeDamage(//some damage);
    7. }
    8. }
    If not make a singleton/static function for the players stats.
     
    traderain likes this.
  4. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    Make an interface that both player and monster inherit, so that the "attack" can access this.
    Even a global singleton can use that interface
     
    RavenOfCode likes this.
  5. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    EverQuest Next was planned to use something like this :) but unfortunately the game is canceled.
     
  6. traderain

    traderain

    Joined:
    Jul 7, 2014
    Posts:
    108
    Were you the developer of that? :eek:
     
  7. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    No :) , i am working a scifi RPG online game. with a small team of 3 people, and there is no plans on canceling this project.
     
    Last edited: May 26, 2016
  8. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    I think this is a great concept "Not_Sure" let me know if you want a code example of what i suggested
     
  9. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,663
    I suppose it depends how you implement the stats themselves. Like do the enemy stats depend on/are decided based on player stats? If so, you could just keep everything in one singleton, have your "randomness" decide how much stronger or weaker than the player the enemy is, assign that to some variable for later references, then as your player attack is called, ask the singleton/game master how much damage the player does, how much defense the enemy has, and so forth. Ideally the player would just have his script control the animation and detecting if he is alive and such.

    I don't have any code to share but there's my two cents, and since I know your projects are quality stuff that perhaps benefits more than yourself, I feel urged to try and help however I can, even if just some rambling advice :p
     
    RavenOfCode likes this.
  10. traderain

    traderain

    Joined:
    Jul 7, 2014
    Posts:
    108
  11. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,663
    That's interesting @traderain but I've always just done singletons with static instancing, and a few public methods and variable getters and setters, but your alternative does seem to be more fool proof. Perhaps would prevent accidental clones of game master scripts and stuff like that I suppose.
     
  12. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
  13. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,663
    Ahh yes, those are very similar!
     
  14. traderain

    traderain

    Joined:
    Jul 7, 2014
    Posts:
    108
  15. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,663
    Nothing necessarily wrong with having alternative implementations available publicly for learning from, that's for sure.
     
    Ironmax likes this.
  16. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,533
    There are a lot of questions going on your original post, @Not_Sure.

    If you just need a global attack function, there's no need for a singleton. Just make it a static class, and not a MonoBehaviour, with a method to process the attack:
    Code (csharp):
    1. public static class MyGlobalAttackClass {
    2.     public static void ComputeAttack(Stats attacker, Stats defender) {...}
    3. }
    When the attacker registers a hit on the defender, call the method:
    Code (csharp):
    1. MyGlobalAttackClass.ComputeAttack(myStats, targetStats);
    Is your Stats class different from your Controller class(es)? If so, I don't see how the global attack function needs to be concerned about the controller at all. (Well, I can imagine possibilities such as for animation feedback, knockback, etc.)

    But let's say each character has at least three MonoBehaviours:
    • Stats
    • Weapon
    • Controller (perhaps with subclasses for PlayerController and AIController)
    You could isolate Stats from Controller like this: (very abbreviated for illustration)

    Controller:
    Code (csharp):
    1. void Update() {
    2.     if (Input.GetButtonDown("Attack")) {
    3.         GetComponent<Weapon>().Attack(target);
    4.     }
    5. }
    Weapon:
    Code (csharp):
    1. public void Attack(GameObject target) {
    2.     if (/*your code to detect hit*/) {
    3.         MyGlobalAttackClass.ComputeAttack(GetComponent<Stats>(), target.GetComponent<Stats>());
    4.     }
    5. }
     
    RavenOfCode and Not_Sure like this.
  17. ezjm427

    ezjm427

    Joined:
    May 17, 2014
    Posts:
    100
    I can give you my example of how I've been doing things, after trying to organize things as best as possible I've come to this sort of structure -

    Player,Enemy, Combat, Ability, AbilityProjectile, EnemyAI

    Player.cs contains generic control of the player, movement, controls, etc, with references to combat and other components

    Combat.cs is a class that any entity that can possibly be involved in combat uses, containing health, damage, other stats, as well as functions like 'useAttack(str/int)/useAbility(str/int)', 'addDamage(int)', 'isAlive()', etc. Combat also contains a list of abilities that can be spells or any type of attacks used by the player or enemies or items

    Ability.cs contains definition of abilities/skills, and has stuff like 'abilityType', 'abilityPower', 'abilityDuration', 'cooldownRemaining, cooldownMax' etc, and contains CoRoutines useAbility() that will use the ability

    AbilityProjectile.cs is generated/instantiated any time an ability is used (whether its actually melee or projectile), and its collision is used to detect if an attack hits or not, upon collision 'applyAbilityEffects(enemyCombatCs,baseAbility)' is called upon the collided object's script

    Enemy.cs contains generic control of the enemy, references to combat.cs and enemyAI.cs and everything is updated from update()

    enemyAI.cs contains AI parameters (aggressiveness, patrolling, passive, patrol radius/paths, etc.) and functions updateAI that will update the enemy's movement and attack based on its current AI states/commands that are continuously updated, but updateAI is called thru enemy.cs's reference to this AIclass


    This system is not perfect but it gives a general idea of how things can work
     
    RavenOfCode likes this.