Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/265.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#MemberwiseClone不';行不通_C#_Xna_Clone - Fatal编程技术网

C#MemberwiseClone不';行不通

C#MemberwiseClone不';行不通,c#,xna,clone,C#,Xna,Clone,我想做的是为我的游戏创建一个名为“项目”的类,它包含游戏中存在的所有项目。因为我正在制作一个星际飞船游戏,在我的班级里有像“星际飞船”和“武器”这样的例子。例如,当我初始化一个敌人时,我希望这个敌人的“星际飞船”实例的值与“物品”中列出的一个星际飞船的值相同。我试着写 this.Ship = Items.Testhip; 进入敌方阶级,但这是行不通的。因此,我在互联网上搜索了另一种可能性,找到了IClonable接口。但它对我来说不太合适。以下是一些重要的代码: 项目类别 public sta

我想做的是为我的游戏创建一个名为“项目”的类,它包含游戏中存在的所有项目。因为我正在制作一个星际飞船游戏,在我的班级里有像“星际飞船”和“武器”这样的例子。例如,当我初始化一个敌人时,我希望这个敌人的“星际飞船”实例的值与“物品”中列出的一个星际飞船的值相同。我试着写

this.Ship = Items.Testhip;
进入敌方阶级,但这是行不通的。因此,我在互联网上搜索了另一种可能性,找到了IClonable接口。但它对我来说不太合适。以下是一些重要的代码:

项目类别

public static class Items
{ 
    private static Starship _testship; 
    public static Weapon _testWeapon;
    public static List<Weapon> Weaponlist = new List<Weapon>();
    public static List<Weapon> WeaponList { get { if (!_initialized) return null; Weaponlist.RemoveAll(c => c.BulletTexture != null); Weaponlist.Add((Weapon) TestWeapon); return Weaponlist; } }
    private static bool _initialized;

    public static object Testship
    {
        get { if (!_initialized) return null; return _testship.Clone(); }
    }

    public static object TestWeapon
    {
        get { if (!_initialized) return null; return _testWeapon.Clone(); }
    }




    public static void Initialize()
    {
        _initialized = true; 
        _testWeapon = new Weapon(WeaponType.Projectil, Graphics.BulletTexture, 25, 250, 10000, 1000, 15000, 3000, 400, 1200, 4, new Vector2(0, 0));
        _testship = new Starship("test", 12000, 5000, Graphics.StarfighterXI, WeaponList, new Shield(), new Motor(), 1, 0, 0, 0, 0.1f, AttackAngle.Small);
    }
}
同样的情况也适用于敌舰,因为我希望他们都有一艘类似的坚固战舰用于测试:

public void Initialize()
    {
        Ship = (Starship) Items.Testship;
        Ship.Weapons.First(c => c.BulletTexture != null).Name = "ENEMY WEAPON!";
    }
来自星际飞船:

public class Starship : ICloneable
{
    public string Name { get; set; }
    public Vector3 LoadedWorld { get; set; }
    public Texture2D Texture { get; set; }
    public Vector2 Position { get; set; }
    public Vector2 Origin { get; private set; }
    public int MaxHP { get; set; }
    private int HP { get; set; }
    public int Cost { get; set; }

    public List<Weapon> Weapons = new List<Weapon>();
    public Shield Shield { get; set; }
    public Motor Motor { get; set; }
    public int MaxProjectilLaunchers { get; set; }
    public int MaxRocketLaunchers { get; set; }
    public int MaxPlasmaWeapons { get; set; }
    public int MaxHEWs { get; set; }
    public int ProjectilLaunchers { get; set; }
    public int RocketLaunchers { get; set; }
    public int PlasmaWeapons { get; set; }
    public int HEWs { get; set; }
    public float Rotation { get; set; } //Rotation, die das Schiff braucht, um sich zu bewegen
    public float FinalRotation { get; set; } // Rotation, die das Schiff aktuell hat
    public float RotationVelocity { get; set; } //Rotations-Velocity, um die sich die Rotation pro Frame ändern soll
    public bool? IsRotationg { get; set; }
    public float AttackAngle { get; set; }

    //-----------------------------------------------------------------------------------------------------
    public Starship(string name, int cost, int baseHP, Texture2D texture, List<Weapon> weapons, Shield shield, Motor motor, int maxProjectilLaunchers, int maxRocketLaunchers, int maxPlasmaWeapons, int maxHEWs, float rotationVelocity, AttackAngle attackAngle)
    {
        Name = name;
        Cost = cost;
        MaxHP = baseHP;
        Position = new Vector2(0, 0); //todo: position muss richtig gesetzt werden, auch wenn das schiff feindlich ist!!!
        Texture = texture;
        Weapons = weapons;
        Shield = shield;
        Motor = motor;
        MaxProjectilLaunchers = maxProjectilLaunchers;
        MaxRocketLaunchers = maxRocketLaunchers;
        MaxPlasmaWeapons = maxPlasmaWeapons;
        MaxHEWs = maxHEWs;
        RotationVelocity = rotationVelocity;
        IsRotationg = null;
        AttackAngle = attackAngle == StarshipsRevolution.AttackAngle.Small ? 1.0f : 1.5f;
        Origin = new Vector2(Texture.Width / 2, Texture.Height / 2);

        foreach (var item in weapons)
        {
            if (item.WeaponType == WeaponType.Projectil) ProjectilLaunchers++;
            if (item.WeaponType == WeaponType.Rocket) RocketLaunchers++;
            if (item.WeaponType == WeaponType.Plasma) PlasmaWeapons++;
            if (item.WeaponType == WeaponType.HEW) HEWs++;
            MaxHP += item.MaxHP; //todo wenn die waffe gewechselt wird wert verändern
        }

        if (ProjectilLaunchers > MaxProjectilLaunchers || RocketLaunchers > MaxRocketLaunchers || PlasmaWeapons > MaxPlasmaWeapons || HEWs > MaxHEWs)
            throw new Exception(String.Format("Das Raumschiff {0} wurde mit zu vielen Waffen initialisiert.", name));

        HP = MaxHP;
    }

    //-----------------------------------------------------------------------------------------------------
    public void Update(GameTime gameTime)
    {
        foreach (var item in Weapons)
            item.Update(gameTime);

        //Schild und Motor updaten
    }

    //-----------------------------------------------------------------------------------------------------
    public void Shoot(WeaponType weaponType, Vector2 position)
    {
        Vector2 direction = Position + Origin - position; //todo muss eventuell noch in die schleife verschoben werden, weil man sonst vielleicht nach hinten schiessen kann
        direction.Normalize();
        float rotation = (float)Math.Atan2(-direction.X, direction.Y);
        if (rotation >= Rotation - AttackAngle && rotation <= Rotation + AttackAngle)
        {
            foreach (var item in Weapons.Where(c => c.WeaponType == weaponType && c.FirerateTimer >= c.Firerate))
                item.Shoot(position);
        }
    }

    /// <summary>
    /// Sets a new Position for the ship or rotate it if it doesn't look into the right direction.
    /// </summary>
    /// <param name="position">The position the ship should be set at</param>
    /// <returns>True, if it could directly set a new position, and false, if it had to rotate</returns>
    public bool RotateOrMove(Vector2 position)
    {
        //Rotation setzen, die das Raumschiff am Ende haben soll
        if (IsRotationg == null)
        {
            Vector2 direction = Position - position;
            direction.Normalize();
            FinalRotation = (float)Math.Atan2(-direction.X, direction.Y);
            IsRotationg = true;
        }

        //Wenn die Rotation erreicht wurde, setze FinalRotation auf null
        if (Equals(FinalRotation, Rotation))
            IsRotationg = false;

        //Wenn FinalRotation auf null ist, darf die Position gesetzt werden, da die Rotation ja dann stimmt
        if (IsRotationg == false)
        {
            Position = position;
            return true;
        }
        else
        { //Wenn 
            Rotation = CurveAngle(Rotation, FinalRotation, RotationVelocity);
            return false;
        }


    }

    //-----------------------------------------------------------------------------------------------------
    public void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Draw(Texture, Position + Origin, null, Color.White, Rotation, Origin, 1, SpriteEffects.None, 0);
    }

    private float CurveAngle(float from, float to, float step)
    {
        if (step == 0) return from;
        if (from == to || step == 1) return to;

        Vector2 fromVector = new Vector2((float)Math.Cos(from), (float)Math.Sin(from));
        Vector2 toVector = new Vector2((float)Math.Cos(to), (float)Math.Sin(to));

        Vector2 currentVector = Slerp(fromVector, toVector, step);

        return (float)Math.Atan2(currentVector.Y, currentVector.X);
    }

    private Vector2 Slerp(Vector2 from, Vector2 to, float step)
    {
        if (step == 0) return from;
        if (from == to || step == 1) return to;

        double theta = Math.Acos(Vector2.Dot(from, to));
        if (theta == 0) return to;

        double sinTheta = Math.Sin(theta);
        return (float)(Math.Sin((1 - step) * theta) / sinTheta) * from + (float)(Math.Sin(step * theta) / sinTheta) * to;
    }

    public object Clone()
    {
        return MemberwiseClone();
    }
}
正如你在上面看到的,玩家的武器在初始化时被命名为“玩家武器”。敌人的武器被命名为“敌人的武器”。但是在那之后,玩家的武器也会有“敌人武器”的名字,所以我猜这些值是参考值?顺便说一下,当其他实例更改所有属性和成员以及所有内容时,它们的值都会更改


希望你能理解我的问题并知道该怎么做:)

这是因为
MemberwiseClone
创建的是浅拷贝,而不是“深”拷贝

从:

MemberwiseClone
方法通过创建一个新对象,然后将当前对象的非静态字段复制到新对象,从而创建一个浅拷贝

这是因为对象本身的字段被克隆,而不是它可能引用的任何对象的字段


这里有一个关于在C#::中创建对象的深度副本的问题。

你能显示你的
星际飞船的代码吗?@VsevolodGoloviznin done:)我尝试了线程中某个人制作的使用序列化的Copier类,但我在formatter.Serialize(流,源)收到了这个错误消息;“Microsoft.Xna.Framework.Graphics.Texture2D”类型在汇编“Microsoft.Xna.Framework.Graphics,Version=4.0.0,Culture=neutral,PublicKeyToken=842cf8be1de50553”中没有标记为可序列化。”但我在“武器”和“星际飞船”上面写了[serializable],那有什么不对呢(@Terrenay:嗯,您自己的类可能是[可序列化的],但是如果所提到的类型
Microsoft.Xna.Framework.Graphics.Texture2D
不是,那么您的类中就不能有此类型的任何属性,或者您必须将其从序列化中排除。不过,这意味着它不会被复制到克隆实例。
public class Starship : ICloneable
{
    public string Name { get; set; }
    public Vector3 LoadedWorld { get; set; }
    public Texture2D Texture { get; set; }
    public Vector2 Position { get; set; }
    public Vector2 Origin { get; private set; }
    public int MaxHP { get; set; }
    private int HP { get; set; }
    public int Cost { get; set; }

    public List<Weapon> Weapons = new List<Weapon>();
    public Shield Shield { get; set; }
    public Motor Motor { get; set; }
    public int MaxProjectilLaunchers { get; set; }
    public int MaxRocketLaunchers { get; set; }
    public int MaxPlasmaWeapons { get; set; }
    public int MaxHEWs { get; set; }
    public int ProjectilLaunchers { get; set; }
    public int RocketLaunchers { get; set; }
    public int PlasmaWeapons { get; set; }
    public int HEWs { get; set; }
    public float Rotation { get; set; } //Rotation, die das Schiff braucht, um sich zu bewegen
    public float FinalRotation { get; set; } // Rotation, die das Schiff aktuell hat
    public float RotationVelocity { get; set; } //Rotations-Velocity, um die sich die Rotation pro Frame ändern soll
    public bool? IsRotationg { get; set; }
    public float AttackAngle { get; set; }

    //-----------------------------------------------------------------------------------------------------
    public Starship(string name, int cost, int baseHP, Texture2D texture, List<Weapon> weapons, Shield shield, Motor motor, int maxProjectilLaunchers, int maxRocketLaunchers, int maxPlasmaWeapons, int maxHEWs, float rotationVelocity, AttackAngle attackAngle)
    {
        Name = name;
        Cost = cost;
        MaxHP = baseHP;
        Position = new Vector2(0, 0); //todo: position muss richtig gesetzt werden, auch wenn das schiff feindlich ist!!!
        Texture = texture;
        Weapons = weapons;
        Shield = shield;
        Motor = motor;
        MaxProjectilLaunchers = maxProjectilLaunchers;
        MaxRocketLaunchers = maxRocketLaunchers;
        MaxPlasmaWeapons = maxPlasmaWeapons;
        MaxHEWs = maxHEWs;
        RotationVelocity = rotationVelocity;
        IsRotationg = null;
        AttackAngle = attackAngle == StarshipsRevolution.AttackAngle.Small ? 1.0f : 1.5f;
        Origin = new Vector2(Texture.Width / 2, Texture.Height / 2);

        foreach (var item in weapons)
        {
            if (item.WeaponType == WeaponType.Projectil) ProjectilLaunchers++;
            if (item.WeaponType == WeaponType.Rocket) RocketLaunchers++;
            if (item.WeaponType == WeaponType.Plasma) PlasmaWeapons++;
            if (item.WeaponType == WeaponType.HEW) HEWs++;
            MaxHP += item.MaxHP; //todo wenn die waffe gewechselt wird wert verändern
        }

        if (ProjectilLaunchers > MaxProjectilLaunchers || RocketLaunchers > MaxRocketLaunchers || PlasmaWeapons > MaxPlasmaWeapons || HEWs > MaxHEWs)
            throw new Exception(String.Format("Das Raumschiff {0} wurde mit zu vielen Waffen initialisiert.", name));

        HP = MaxHP;
    }

    //-----------------------------------------------------------------------------------------------------
    public void Update(GameTime gameTime)
    {
        foreach (var item in Weapons)
            item.Update(gameTime);

        //Schild und Motor updaten
    }

    //-----------------------------------------------------------------------------------------------------
    public void Shoot(WeaponType weaponType, Vector2 position)
    {
        Vector2 direction = Position + Origin - position; //todo muss eventuell noch in die schleife verschoben werden, weil man sonst vielleicht nach hinten schiessen kann
        direction.Normalize();
        float rotation = (float)Math.Atan2(-direction.X, direction.Y);
        if (rotation >= Rotation - AttackAngle && rotation <= Rotation + AttackAngle)
        {
            foreach (var item in Weapons.Where(c => c.WeaponType == weaponType && c.FirerateTimer >= c.Firerate))
                item.Shoot(position);
        }
    }

    /// <summary>
    /// Sets a new Position for the ship or rotate it if it doesn't look into the right direction.
    /// </summary>
    /// <param name="position">The position the ship should be set at</param>
    /// <returns>True, if it could directly set a new position, and false, if it had to rotate</returns>
    public bool RotateOrMove(Vector2 position)
    {
        //Rotation setzen, die das Raumschiff am Ende haben soll
        if (IsRotationg == null)
        {
            Vector2 direction = Position - position;
            direction.Normalize();
            FinalRotation = (float)Math.Atan2(-direction.X, direction.Y);
            IsRotationg = true;
        }

        //Wenn die Rotation erreicht wurde, setze FinalRotation auf null
        if (Equals(FinalRotation, Rotation))
            IsRotationg = false;

        //Wenn FinalRotation auf null ist, darf die Position gesetzt werden, da die Rotation ja dann stimmt
        if (IsRotationg == false)
        {
            Position = position;
            return true;
        }
        else
        { //Wenn 
            Rotation = CurveAngle(Rotation, FinalRotation, RotationVelocity);
            return false;
        }


    }

    //-----------------------------------------------------------------------------------------------------
    public void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Draw(Texture, Position + Origin, null, Color.White, Rotation, Origin, 1, SpriteEffects.None, 0);
    }

    private float CurveAngle(float from, float to, float step)
    {
        if (step == 0) return from;
        if (from == to || step == 1) return to;

        Vector2 fromVector = new Vector2((float)Math.Cos(from), (float)Math.Sin(from));
        Vector2 toVector = new Vector2((float)Math.Cos(to), (float)Math.Sin(to));

        Vector2 currentVector = Slerp(fromVector, toVector, step);

        return (float)Math.Atan2(currentVector.Y, currentVector.X);
    }

    private Vector2 Slerp(Vector2 from, Vector2 to, float step)
    {
        if (step == 0) return from;
        if (from == to || step == 1) return to;

        double theta = Math.Acos(Vector2.Dot(from, to));
        if (theta == 0) return to;

        double sinTheta = Math.Sin(theta);
        return (float)(Math.Sin((1 - step) * theta) / sinTheta) * from + (float)(Math.Sin(step * theta) / sinTheta) * to;
    }

    public object Clone()
    {
        return MemberwiseClone();
    }
}
public object Clone()
    {
        return MemberwiseClone();
    }