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

Creating a solid fps weapon class

Discussion in 'Scripting' started by CyberFox01, Oct 6, 2012.

  1. CyberFox01

    CyberFox01

    Joined:
    Oct 5, 2012
    Posts:
    23
    So i ran into a brick wall here. I'm trying to create a solid class system for my weapons in an fps game. Because i want the players inventory to be a list of the weapon classes in creating derived classes from a class called "weapon". The weapon class is derived from the MonoBehaviour class.

    now to create the base inventory i pull something like this this:
    Code (csharp):
    1. // an array of blank weapons
    2. weapons=new List<weapon>();
    3. weapons.Add(new knife());
    4. weapons.Add(new handgun());
    5. weapons.Add(new shotgun());
    6. weapons.Add(new grenade());
    7. weapons.Add(new rocketlauncher());
    8. weapons.Add(new minigun());
    9. weapons.Add(new railgun());
    10. weapons.Add(new bombBlaster());
    Unity keeps flaming me because I'm not allowed to construct a new MonoBehavoir. Which obviously happens cause i derived from the MonoBehaviour class.
    Now the question would be: How to get around this? Wat to do?

    also the other relevant files if u care to read further:
    weapon.cs
    Code (csharp):
    1. public abstract class weapon:MonoBehaviour{
    2.     public enum type{
    3.         knife,
    4.         handgun,
    5.         shotgun,
    6.         grenade,
    7.         rocketlauncher,
    8.         minigun,
    9.         railgun,
    10.         bombBlaster
    11.     }
    12.     public int ammo {get; set;}
    13.     public bool rdy {get; set;}
    14.     public float fireInterval   {get; set;}
    15.     public int maxAmmo  {get; set;}
    16.     public GameObject model {get; set;}
    17.     public Vector3 offset   {get; set;}
    18.     public Transform parent {get{return this.gameObject.transform.parent;}}
    19.     public virtual void init(){}
    20.     public virtual void fire(){}
    21.     public virtual void pullOut(){} // hurhh hurhh
    22. }
    23.  
    handgun.cs (this is the only class i've actaully written, the others are just placeholders)
    Code (csharp):
    1. public class handgun:weapon {
    2.     public override void init(){
    3.         ammo=100;
    4.         rdy=true;
    5.         fireInterval=0.1f;
    6.     }
    7.    
    8.     public override void fire(){
    9.         RaycastHit hit;
    10.         var fwd = parent.TransformDirection(Vector3.forward);
    11.         if (Physics.Raycast(parent.position, fwd, out hit, 100.0f)){
    12.             if(hit.collider.tag=="Player"){
    13.                 playerControl player=hit.collider.GetComponent<playerControl>();
    14.                 player.life-=10;
    15.             }
    16.         }
    17.     }
    18.    
    19.     public override void pullOut(){
    20.        
    21.     }
    22. }
    23.  
     
  2. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,516
    If you want to derive from MonoBehaviour (which may or may not be a good idea, depending completely on how you're designing things) then instead of calling new to create your objects, use AddComponent<...>() on the object which should own them. Remember that when you're finished with them you have to then Destroy(...) them, not just null out your references.

    Other than that, don't derive from MonoBehaviour. You don't have to, and it's perfectly alright to have non-MonoBehaviour classes instantiated and used by MonoBehaviour classes. You do lose some niceness, such as being able to set them up directly in the default Inspector (you could always make a custom one for the owner object if you wished, or something along those lines). You also won't have Start, Update, etc. called automagically, but this probably isn't a big deal since the owner object has references to its weapons so you can presumably use them through there - either call Update on the current weapon yourself, or have the class simply store data which is used by the owner class anyway.
     
  3. kingcharizard

    kingcharizard

    Joined:
    Jun 30, 2011
    Posts:
    1,137
    I know this is completely not helpful to you and while I'm not gonna be able to help you at all with your problem I do have a question I'm hoping you'd feel generous enough to answer... What is the point of using getters and setters and What exactly are they? Are they classes? Methods? Or something like function prototypes? I highly doubt the last one I'm just seeing answers.
     
  4. Vanamerax

    Vanamerax

    Joined:
    Jan 12, 2012
    Posts:
    937
    I would say to better split the weapon attributes and the monobehaviour things. For example:

    Code (csharp):
    1.  
    2. public class Weapon {
    3.     //stuff like recoil, damage, range, firerate etc in here
    4. }
    5.  
    and a monobehaviour on every weapon you will be holding ( so on the prefab for example ) getting your weapon stats from the seperate Weapon class ( store a reference to the Weapon in your player script ). The monobehaviour will handle movement of the weapon when for example shooting etc.
     
  5. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,516
    They're methods made to look like public variables.

    Instead of making a variable public, you instead make a property that references it (in this case the variable itself is implied) and fill in the guts of a get method and a set method. The 'get' is always parameterless and the 'set' always takes one parameter of the variable's type identified as 'value'. If you use the defaults like above (ie: don't provide the content of the methods yourself) it is equivalent to making the variable public except that you have the ability to specify either get or set or both. If you fill in the functions you can get them to do other things at the same time - like check or clamp values as they are set, or whatever.

    Keep in mind that if you implement something as a property then it looks like a variable, so you're best off making sure it can be treated like a variable. That is, don't do anything non trivial in there, and if you have to then you should make it an explicit function instead, else it bites someone later on.
     
  6. CyberFox01

    CyberFox01

    Joined:
    Oct 5, 2012
    Posts:
    23
    I did the addComponent<>() thing and i think I've almost nailed it.
    the model property luckily pops op on the inspector. In the handgun.cs script i can assign the handgun prefab. Which i did. But then when i try to instantiate it i get this: "ArgumentException: The prefab you want to instantiate is null.". I've also tried just assigning it in the init() method with Resources.Load() typing the entire path to the prefab. No luck. It keeps being null even tho its assigned, or atleast should be.


    related stuff...
    calling sequence of methods
    Code (csharp):
    1. weapons[(int)currentWeapon].init();
    2. weapons[(int)currentWeapon].pullOut(weaponPoint);
    handgun.init()
    Code (csharp):
    1. public override void init(){
    2.     maxAmmo=100;
    3.     ammo=100;
    4.     rdy=true;
    5.     hidden=false;
    6.     fireInterval=0.1f;
    7.     timer=0;
    8.     //didnt work anyways
    9.     //model=(GameObject)Resources.Load("3d/objects/weapons/handgun/handgun");
    10.     offset=new Vector3(0,0,0);
    11. }
    12.  
    weapon.pullOut()
    Code (csharp):
    1. public virtual void pullOut(Transform container){
    2.     gameobjectHandle=(GameObject)Instantiate(
    3.         model,
    4.         container.position+offset,
    5.         Quaternion.identity
    6.     );
    7.     this.gameObject.transform.parent=container;
    8. }
     
  7. CyberFox01

    CyberFox01

    Joined:
    Oct 5, 2012
    Posts:
    23
    uh, bump? I've still got no idea why it comes out as null...
     
  8. Raigex

    Raigex

    Joined:
    Jul 6, 2012
    Posts:
    154
    well where do you create your model (from INstantaiate(model,..,..);)
    you get that error because you are trying to INstantiate (kinda like clone) a null object.
     
  9. hcwork

    hcwork

    Joined:
    Sep 11, 2012
    Posts:
    72
    Just a note, is this path "3d/objects/weapons/handgun/handgun" under a Resources folder? It has to be. That tripped me up for a while, I was always getting null until I put it under a Resources folder I created
     
  10. CyberFox01

    CyberFox01

    Joined:
    Oct 5, 2012
    Posts:
    23
    Yeah i figured that part.
    In the project pane when i click on a script, if there is any Transform or GameObject properties it'll show up right above sample text and without having to assign them to in hierarchy i can assign default values in the project pane. In this case i dragged the handgun prefab there. Thats awesome, zept i doesn't work.
    I found that if i assigned the same prefab to the playerController and then assigned the weapon classes property to the object I'm calling init() and pullOut() from then it works.

    The sad thing is i wanted the derived classes of the weapon for example the handgun class to be kinda self aware. Like it should know which model its attached to and i keep wondering why default inpector assignment didn't work and more surprisingly Resources.Load(); didn't work either.

    So the solution i have right now is the playerController has an array of gameobjects where i assign all of the prefabs in a very specific sequence.
    and then:
    Code (csharp):
    1. weapons[(int)currentWeapon].init();
    2. weapons[(int)currentWeapon].model=weaponPrefabs[(int)currentWeapon];
    3. weapons[(int)currentWeapon].pullOut(weaponPoint);
    But this solution makes me cry at night.

    I've tried googling and I've found this fella with similar problems:
    http://forum.unity3d.com/threads/54708-Default-Reference-returning-null-value
    The thing I'm trying to do in creating a "Default Reference" for my weapons models

    @hcwork i have no idea what a "Reasources" folder is. The handgun prefab is located in a folder called handgun. I checked the path for errors a bit too many times.
     
    Last edited: Oct 9, 2012
  11. Raigex

    Raigex

    Joined:
    Jul 6, 2012
    Posts:
    154
    The resources folder is a folder you create yourself (usually for things that are not in the scene but you want to instantiate yourself later) which is what you should do, as stated by hcwork
     
  12. CyberFox01

    CyberFox01

    Joined:
    Oct 5, 2012
    Posts:
    23
    annoys me i have to name a folder resources. it messes up my naming conventions. o well.

    I found a way around it.. somewhat.
    i created a MonoBehavoir class, attached it to an empty gameobject. in this class i have a few lists. 1 containing references to all the weapon prefabs, another to the particles. I think I'm gonna need to create a resources folder cause this grows tedious for every weapon extension i make.

    Question tho': If i put my assets in the Resources folder would that also solve the problem with Default References?