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