Unity C#中构造函数的解决方法

时间:2013-12-18 13:47:46

标签: c# unity3d

http://answers.unity3d.com/questions/32413/using-constructors-in-unity-c.html 这并不能完全解决以下问题:

  • 各种武器级别
  • 服务器 - 客户端架构
  • 服务器想要生成武器或射弹,但是之前想要设置射击的玩家,武器等级等等。
  • WeaponScript应该处理所有效果,例如Instantiation本身

我可以这样做

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);

但是如果我想让我的武器处理其外观/实例化的逻辑怎么办?对于实例,如果我有一个武器,其游戏对象直接产生在每个玩家的位置或只是agressor。失败。 我期待像... ...

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

有解决方法吗? 如果我让一个班级不继承Monobehaviour,那么我的更新方法就不见了。但我唯一需要的是自己处理实例化。

3 个答案:

答案 0 :(得分:3)

您可以从FireballBehavior继承MonoBehavior,并且Fireball对象不会从任何内容继承。

你的FireballBehavior将负责产生和杀死火球以及跟踪场景中的火球,另一方面,你的Fireball对象应完全由数据驱动并且只保留数据武器。

允许您在任何游戏对象上发送消息从服务器发送到FireballBehavior,说“实例化该对象:火球”

我清楚了吗?

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;

}

这样你就可以从网络发送消息到:

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

总结:根据数据和仅由服务器处理并从中发送的小类或结构中的所有数据执行更新和实例化的一般行为

这种方法的优势在于它是可以互换的,并且由于Fireball是一个稳定的状态对象,你可以将其序列化或将其存储在数据库中而不需要太多努力,只需进行一些更改就可以在FireballBehavior中更改Fireball对象在执行期间直接在不同时间拥有不同的火球......

这是一个源自其中一个视频的想法:(不记得哪一个......但两者都非常好看)

要完成答案,您甚至可以采用非常通用的方式:

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;

}

通过这种方式,您可以为要实例化的任何对象类型添加新类,并始终使用相同的behaviorComponent来启动更新并终止它们,甚至使用

保留anyObject类型的所有对象的通用列表
List<anyObject> myObjectList = new List<anyObject>() {fireball, carrot, chicken}

答案 1 :(得分:1)

一些想法:

  1. 您可以通过在虚拟游戏对象上使用委托来进行虚假的更新循环,该游戏对象只是在其自己的更新循环中调用委托。

  2. GameObject上使用通用扩展方法可以轻松解决构造函数不足的问题。例如,您可以使用.Create<T>(params ...)来隐藏所有丑陋,并为您进行实例化和初始化。

  3. 我使用类似的方法,我的所有武器都是从完全随机的'drop sheets'创建的。等等。

答案 2 :(得分:-1)

您还可以在自定义序列化类中实例化,而不需要FireBallBehaviour。 我发现最好的方法是创建一个自定义序列化的Player类,它包含一个具有Ammo类实例的Weapon类的实例。

Player类看起来像这样:

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;
    }
}

你的武器类:

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
}

你的弹药课程:

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
}

然后你会有一个Monoconhaviour的PlayerController来处理所有输入和碰撞检测: 我这里只给出一个动作示例,因为它已经在这里获得了很多代码,但我想你可以想象你将如何对武器做同样的事情。因为你的武器可以通过播放器实例访问,作为player.currentWeapon或弹药通过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);
        }
    }
}

在多人游戏中,玩家从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);
    }
}

最后一件事@GéryArduino:我看不出你的例子是如何通用的?它在任何地方都不是类型安全的,因为您提交的是实际的数据类型。关于泛型的参考阅读this