我正在使用XNA 3.0并试图创建一个sprite类,但不确定如何处理它。我在sprite类中执行动画吗?我的代码也一直收到错误
Game1.cs
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
Sprite.Draw(spriteBatch);
base.Draw(gameTime);
}
Sprite.cs
private static Texture2D rings;
Point rings_frameSize = new Point(75, 75);
Point rings_currentFrame = new Point(0, 0);
Point rings_sheetSize = new Point(6, 8);
int ms_elapsedRings = 0;
public static void setup_sprites(ContentManager Content)
{
rings = Content.Load<Texture2D>("Images/threerings");
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(rings,
new Vector2(0,0),
new Rectangle(rings_currentFrame.X * rings_frameSize.X, //X component of where to begin
rings_currentFrame.Y * rings_frameSize.Y, //Y component of where to begin
rings_frameSize.X, //cell width
rings_frameSize.Y), //cell height
Color.White,
0,
Vector2.Zero,
1,
SpriteEffects.None,
0);
}
返回
错误1非静态字段、方法或属性"WindowsGame1.Sprite.Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch)"C:\Users\XXXXXX\Documents\Visual Studio 2008\Projects\WindowsGame1\WindowsGame1\Game1.cs 107 13 WindowsGame1 需要对象引用
首先,第二个错误:"非静态字段、方法或属性需要对象引用"。
在面向对象编程中,程序通过类和继承等概念具有结构的优势,而不是历史命令式编程,在历史命令式程序中,"程序"由一系列基本指令组成,一个接一个。在面向对象编程中,类表示某种抽象实体。这样的实体可以是动物、汽车、电视。在这种情况下,你可以编写一个class Car
并"创建"许多Car
对象的"实例",其中一个可能被称为本田、另一辆宝马和另一辆劳斯莱斯。但有时,创建类的实例是没有意义的。如果你的课不是一辆车怎么办——如果它是"数学"怎么办。有一个"Math"类是完全有效的——事实上,.NET框架有一个Math类。但在这种情况下,拥有数学的"实例"是没有意义的。数学就是数学。这是一项研究,而且只有一项。
因此,非静态方法的访问方式如下:
Car honda = new Car();
honda.Drive();
说Car.Drive()是没有意义的,因为你指的是哪辆汽车?Car作为一个类,只是一个通用的蓝图——您想调用new Car()
来从该类蓝图中生成一些具体的对象。
另一方面,静态方法是可以访问的,比如:
Math.Add();
说Math myMath = new Math();
是没有意义的,这就是为什么Math是它自己的静态类。
现在,您已经制作了方法setup_sprites()
static
。您可能会认为这种设置方法应该是静态的,因为无论创建了多少个精灵,每个创建的精灵都将在设置过程中访问相同的纹理。如果你想用这种方式创建你的sprite类,那没关系,但你必须让你的整个sprite类都是静态的,因为静态方法和变量不能访问非静态方法和参数。
不过,一般来说,Sprite类并不是静态的。你可以在这里阅读更多关于静态与非静态的信息:http://msdn.microsoft.com/en-us/library/79b3xss3%28v=vs.80%29.aspx.
现在,你的第一个问题如何将动画集成到代码中完全取决于您。看起来您正在Draw()方法中嵌入动画代码。这没有错,但可能有更好的解决方案。
面向对象编程有几个原则来保持复杂性的优雅简洁,其中之一就是单一责任原则,简单地说,它建议程序员只给一个类一个责任。Sprite类应该简单地加载它的资源、绘制它自己并卸载它的资源。这就是精灵应该做的。
但是动画呢?这就是面向对象编程的用武之地——分担这一职责;您不必将所有内容都粘贴到Sprite类中。您有两种选择:您可以以继承自Sprite
类的AnimatedSprite
类的形式扩展Sprite
功能,也可以以Animatable
接口的形式扩展您的Sprite
功能。这里的设计问题是:通过类还是接口进行扩展?
你可以在这里阅读更多关于辩论的信息:http://www.codeproject.com/Articles/11155/Abstract-Class-versus-Interface
我从那篇文章中真正喜欢的是以下定义:抽象类定义核心函数,而接口描述外围属性。
精灵不仅可以设置动画,还可以移动。这些听起来更像是属性,而不是核心功能。它具有设置动画的能力。它有移动的能力。有些人认为接口具有"has-a"关系,而类则被认为具有"is-a就可以设置动画。
所以我认为您应该通过添加Animatable
接口来扩展Sprite
类。实际上,您希望将其称为IAnimatable
,以保留命名标准。
所以你可能会得到这样的东西(伪代码):
public class Sprite : IAnimatable
{
private Texture2D rings;
public void LoadContent(ContentManager Content)
{
// Call this method from Game.LoadContent()
rings = Content.Load<Texture2D>("Images/threerings");
}
public void Draw(SpriteBatch spriteBatch)
{
if (IsAnimating)
{
// Incorporate IAnimatable variables here to draw your animation
}
}
}
public interface IAnimatable
{
public bool IsAnimating {get; set;}
public int CurrentFrameIndex {get; set;}
public Point FrameSize {get; set;}
}
在未来,你甚至可能有:
public interface IMovable
{
public bool IsMoving {get; set;}
public Point CurrentLocation {get; set;}
public Point DestinationLocation {get; set;}
}
并将所有这些集成到:
public class NpcSprite : Sprite, IMovable, IAnimatable
{
}
的确,即使使用接口,您最终还是会在Sprite类中编写接口代码,但至少您已经在精灵、可设置动画的精灵和可移动的精灵之间建立了明确的契约。以后编辑和扩展会容易得多。