2

http://answers.unity3d.com/questions/32413/using-constructors-in-unity-c.html That does not exactly solve the following problem:

  • Various Weapon Levels
  • Server-Client Architecture
  • Server wants to spawn a weapon or projectile, but BEFORE wants to set which player shot, which level the weapon has etc.
  • WeaponScript should handle all Effects, like Instantiation themselves

I could do it like so

GameObject fireball = (GameObject)GameObject.Instantiate(pfFireball, p.Position, p.Rotation);
FireBall fb = (FireBall)fireball.GetComponent(typeof(FireBall));
fb.agressorId = pId;
fb.weaponLevel = p.Controller.WeaponLevel;
networkView.RPC("ShootClientWeapon", RPCMode.All, (int)w, p.PlayerId);

But what if I wanted to let my weapons handle the logic of their appearance/ Instantiation. For Instance if I have a weapon whose gameobject either spawns directly at the position of every player or just the agressor. Fail. I expected something like...

 fireball fb = new FireBall();
 fb.gameObject = prefabFireball;
 fb.agressorId = pId;
 fb.weaponLevel = p.Controller.WeaponLevel;
 fb.Fire();

Is there a workaround? If I make a class not inheriting Monobehaviour then my update method is gone I guess. But the only thing that I need is to handle Instantiation myself.

3 Answers 3

3

You could have a FireballBehavior inheriting from MonoBehavior AND a Fireball Object not inheriting from anything.

Your FireballBehavior would take care of spawning and killing Fireballs as well as keeping track of those on scene, on the other hand your Fireball Object should be completely data driven and only hold the data weapon.

Allowing you to send message from the server to the FireballBehavior on any gameObject saying "instanciate that object : Fireball"

Am I clear?

class FireballBehavior : MonoBehavior {

    Fireball fireball;
    public void startFireball(Fireball frb) {
        fireball = frb;
        createFireball(); //instanciation and stuff
    }
    //your functions handling creation update and killing

}

class Fireball {

    GameObject gameObject = prefabFireball;
    Int agressorId = pId;
    Int weaponLevel = p.Controller.WeaponLevel;

}

That way you could just send messages from the network to :

 gameobject.GetComponent<FireballBehavior>().startFireball(frbFromServer);

To sum-up : A generic behavior doing the updates and instanciation according to the data and all the data in a small class or struct handled only by the server and sent from it

The advantage with this approach is that it is interchangeable, and as Fireball is a steady state object you can serialize him or store him in database with not too much effort, with just a few changes you could event change Fireball object in FireballBehavior directly during execution to have different fireball at different times...

This is an idea derivated from one of those videos : (dont remember which one... but both are very good to watch)

To complete the answer you could even have this done a very generic way :

class AnyObjectBehavior : MonoBehavior {

    AnyObject Object1;
    public void startFireball(anyObject frb) {
        Object1 = frb;
        initiateAnyObject (); //instanciation and stuff

    }
    //your functions handling creation update and killing

    private void initiateAnyObject () {

         myObjectList.add(Object1) //that way you do not have to 
                                   // use for loops to edit some objects
         //instanciation stuff
    }

}

class AnyObject {
    //Generic properties
    GameObject gameObject = prefabFireball;

}

class Fireball : AnyObject
{
    //fireball specific properties
    Int agressorId = pId;
    Int weaponLevel = p.Controller.WeaponLevel;

}

That way you could just add new classes for any object type you want to instantiate and always use the same behaviorComponent to start update and kill them, and even keep a generic list of all your objects of anyObject type with

List<anyObject> myObjectList = new List<anyObject>() {fireball, carrot, chicken}
Sign up to request clarification or add additional context in comments.

3 Comments

This is a very nice approach. Using non-monobehaviour classes with references to their gameobjects.
Indeed (it's not mine i'll add the source in edit) and you can even make a list of those objects to be able to access them 2 ways (gameobject to fireball or fireball to gameobject) without having to do a foreach loop
If someone can improve the second part of my answer with Interfaces that would maybe be a better answer (i'm not yet extremely confident with interfaces less than with inheritance)
1

A few ideas :

  1. You can have a fake update loop by using delegates on a dummy gameobject that simply invokes the delegate in it's own update loop.

  2. Lack of constructors can be considered an inconvenience that is easily solved with a generic extension method on GameObject. You can for instance have a .Create<T>(params ...) that will essentially hide all the ugliness and do the instantiation and initialization for you.

I use a similar approach and all my weapons are created from 'drop sheets' that are completely random and so on.

Comments

-1

You can also Instantiate in your custom serialized class you don't need the FireBallBehaviour. Best way to do it i found is making a custom serialized Player class that has instances of your Weapon class which has an instance of an Ammo class.

the Player class could look something like this:

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

[System.Serializable]
public class PlayerCharacter
{
    //public NetworkPlayer newtWorkPlayer;
    public int playerID;
    public GameObject characterObject;
    public string characterName;
    public float walkSpeed;
    public int health;
    public Vector3 spawnPosition;

    public List<Weapon> weapons = new List<Weapon>();
    public Weapon equipedWeapon;

    public PlayerCharacter()
    {
        playerID = 0;
        characterObject = null;
        characterName = "";
        walkSpeed = 0;
        health = 0;
    }

     public PlayerCharacter(/*NetworkPlayer nP,*/ int pID, GameObject cO, string cN, float wS, int h, Vector3 sP)
    {
         //newtWorkPlayer = nP;
         playerID = pID;
         characterObject = Network.Instantiate(cO, sP, Quaternion.identity, 0)as GameObject;//GameObject.Instantiate(cO,sP,Quaternion.identity)as GameObject;
        characterName = cN;
        walkSpeed = wS;
        health = h;
        spawnPosition = sP;
    }

    public void TakeDamage (int takeDamage)
    {
        health -= takeDamage;
    }

    public void Movement (Vector3 target)
    {
        characterObject.transform.position += target;
    }
}

Your Weapon class:

using UnityEngine;
using System.Collections;

[System.Serializable]
public class Weapon 
{
    public GameObject weaponObject;
    public WeaponType typeOfWeapon;
    public Ammo ammo;

    public Weapon (GameObject wO, WeaponType tOW, Ammo a)
    {
        weaponObject = wO;
        typeOfWeapon = tOW;
        ammo = a;
    }

    public void UseWeapon()
    {
        switch(typeOfWeapon)
        {
        case WeaponType.FireBall:
            //some weapon code here
            break;
        case WeaponType.RidiculousHugeGun:
            //some weapon code here
            break;
        case WeaponType.MegaAwesomeMagicPower:
            //some weapon code here
            break;
        case WeaponType.Knife:
            //some weapon code here
            break;
        }
    }
}
public enum WeaponType
{
    FireBall,
    RidiculousHugeGun,
    MegaAwesomeMagicPower,
    Knife
}

Your Ammo class:

using UnityEngine;
using System.Collections;

[System.Serializable]
public class Ammo 
{
    public GameObject ammoObject;
    public int damage;
    public float moveSpeed;

    public Ammo(GameObject aO, int d, float mS)
    {
        ammoObject = GameObject.Instantiate(aO)as GameObject;
        damage = d;
        moveSpeed = mS;
    }
    public IEnumerator Movement (Vector3 target)
    {
        while(ammoObject != null)
        {
            ammoObject.transform.position = ammoObject.transform.forward+target*moveSpeed*Time.deltaTime;

            yield return null;
        }

    }
}
public enum AmmoType
{
    FireBallBall,
    RidiculousHugeBullet,
    MegaAwesomeMagicPowerEffect,
    None
}

Then you would have a PlayerController thats Monobehaviour to handle all the Input and Collision detection: I only give a movement example here because its getting to much code here already, but i guess you can imagine how you would do the same with the weapons. Since you're weapon is accessible through the player instance as player.currentWeapon or the ammo through player.currentWeapon.ammo

using UnityEngine;
using System.Collections;

public class PlayerController : MonoBehaviour {

    public PlayerCharacter player;

    void Update () 
    {
        if(Input.GetAxis("Horizontal") != 0 || Input.GetAxis("Vertical") != 0)
        {
            player.Movement(new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"))*player.walkSpeed*Time.deltaTime);
        }
    }
}

In multiplayer the player gets his instance from the GameServer:

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

public class GameServer : MonoBehaviour 
{
    public List<PlayerCharacter> players = new List<PlayerCharacter>();
    private int playerCount = 0;

    void OnPlayerConnected(NetworkPlayer player) 
    {
        networkView.RPC("CreatePlayer", player);
        Debug.Log("Player " + playerCount + " connected from " + player.ipAddress + ":" + player.port);
    }

    [RPC]
    void CreatePlayer()
    {
        playerCount++;
        PlayerCharacter playerChar = new PlayerCharacter(/*player,*/ playerCount, (GameObject)Resources.Load("Player"), "Player"+playerCount, 5, 100, Vector3.zero);
        playerChar.characterObject.AddComponent<PlayerController>().player = playerChar;
        players.Add(playerChar);
    }
}

one last thing @ Géry Arduino : I don't see how your example is generic at all? It's not typesafe anywhere, since you are committing the actual data type. for reference about generics read this

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.