TurboSprite:.NET Framework 2.0的简单2D Sprite引擎(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/turbosprite-a-simple-2d-sprite-engine-for-net-fram-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 15 分钟阅读 - 7454 个词 阅读量 0TurboSprite:.NET Framework 2.0的简单2D Sprite引擎(译文)
原文地址:https://www.codeproject.com/Articles/26382/TurboSprite-A-Simple-2D-Sprite-Engine-for-NET-Fram
原文作者:Dion Kurczek
译文由本站 robot-v1.0 翻译
前言
A simple, object-oriented 2D Sprite Engine for .NET 2.0.
用于.NET 2.0的简单,面向对象的2D Sprite Engine.
介绍(Introduction)
TurboSprite是一组组件,它们为.NET应用程序提供完整的2D动画精灵引擎. “精灵"是游戏或支持动画的其他应用程序中的可移动对象.在TurboSprite中,可以使用几种不同类型的Sprite,并创建自己的派生类型以精确显示所需的外观和行为. TurboSprite完全用C#托管代码编写.主要组成部分是:(TurboSprite is a set of components that provide a complete 2D animation sprite engine to your .NET applications. A “sprite” is a movable object in a game or other application that supports animation. In TurboSprite, you can use several different types of sprites, and create your own derived types to exhibit exactly the appearance and behavior you need. TurboSprite is written completely in C# managed code. The primary components are:)
SpriteSurface
-进行精灵动画的可视画布.(- The visual canvas that the sprite animation takes place on.)Sprite
-封装精灵的抽象基类. TurboSprite包含几个具体的后代Sprite类,例如(- An abstract base class that encapsulates a sprite. TurboSprite contains several concrete descendant sprite classes, like)BitmapSprite
,(,)PolygonSprite
和(, and)AnimatedBitmapSprite
.(.)SpriteEngine
-将精灵添加到(- Sprites the are added to a)SpriteEngine
将出现在(will appear on the)SpriteSurface
.的(. The)SpriteEngine
通知您精灵之间的碰撞.的后代(notifies you of collisions between sprites. Descendant classes of)SpriteEngine
允许您定义它们包含的精灵的不同移动功能.的(allow you to define different movement capabilities of the sprites that they contain. The)DestinationSpriteMover
TurboSprite中包含的后代可以使Sprite以不同的速度移动到目标点.(descendant that is included in TurboSprite allows you to move sprites to a destination point at varying speeds.)
背景(Background)
TurboSprite始于1990年代中期,当时是用Borland Delphi编写的Windows Sprite引擎.当时,在Windows中生成响应动画非常困难,TurboSprite依靠特殊的汇编语言编码功能直接绘制到图像缓冲存储器中.现在,计算机变得更快了,TurboSprite的最新化身利用GDI +的绘制功能来执行其渲染.这使我能够完全使用C#托管代码开发该程序包.简单的2D游戏和其他应用程序的性能是可以接受的! .NET的TurboSprite保留了原始库的简单,面向对象的设计模式.(TurboSprite began back in the mid 1990s as a Windows sprite engine written in Borland Delphi. At the time, generating responsive animation in Windows was very difficult, and TurboSprite relied an special assembly language coded functions to draw directly into the image buffer memory. Now that computers are much faster, the newest incarnation of TurboSprite leverages the drawing capability of GDI+ to perform its rendering. This enabled me to develop the package completely in C# managed code. The performance is very acceptable for simple 2D games and other applications! TurboSprite for .NET has kept the simple, object-oriented design pattern of the original library.)
TurboSprite组件(TurboSprite Components)
精灵表面(SpriteSurface)
SpriteSurface
是精灵移动并发生其他动画效果的可见动画表面.放置后(is the visible animation surface where sprites move and other animated effects occur. After placing a) SpriteSurface
在表格上,设置(on a form, set the) DesiredFPS
属性可确定您希望获得的动画每秒帧数.在您的代码中,设置(property to establish the number of frames per second of animation that you wish to achieve. In your code, set the) Active
财产(property to) true
开始动画.您可以随时检查实际的(to begin animation. At any time, you can examine the actual animation rate of the) SpriteSurface
通过检查(by examining the) ActualFPS
属性.(property.)
您可以使用以下方法通过多种途径制作动画(You can produce animation through a number of different avenues, using) SpriteSurface
.一种方法是使用(. One way is to use) SpriteEngine
和(s and) Sprite
s(请参阅下文).当您连接时(s (see below). When you connect) SpriteEngine
到一个(s to a) SpriteSurface
,包含在(, the sprites contained in the) SpriteEngine
会在上渲染和处理(s will be rendered and processed on the) SpriteSurface
.(.)
SpriteSurface
还提供了事件和属性,您可以处理这些事件和属性以在各个点进入动画循环.一些事件使用(also provides events and properties you can handle to tap into the animation cycle at various points. Some of the events use) PaintEventArgs
,因此您可以使用(, so you can use the) Graphics
事件中包含的对象以在表面上绘制.请记住,下面的事件序列在每个动画周期内发生.基本上,您每个周期都在绘制完整的框架.您在每帧中绘制的内容都会稍作改动,即可产生动画效果.(object that is contained in the event to draw on the surface. Keep in mind that the sequence of events below occurs during each animation cycle. You are basically drawing your complete frame during every cycle. It is the slight alteration of what you draw in each frame that can produce animation effects.)
- 的(The)
BeforeAnimationCycle
事件在动画的每一帧之前发生.(event occurs before each frame of animation.) - 如果您设定(If you set the)
AutoBlank
财产(property to)true
,在每个动画周期内发生的第一件事是使用(, the first thing that happens during each animation cycle is for the surface to be cleared using the)AutoBlankColor
属性.(property.) - 的(The)
BeforeSpriteRender
事件在将任何精灵渲染到曲面之前,但在AutoBlank处理之后发生.使用(event occurs before any sprites are rendered to the surface, but after the AutoBlank processing. Use the)Graphics
对象,以在每个动画帧期间对表面执行任何自定义渲染.(object to perform any custom rendering to the surface during each animation frame.) - 的(The)
AfterSpriteRender
渲染精灵后发生事件,可让您使用(event occurs after the sprites have been rendered, and allows you to draw to the surface using the)Graphics
对象通过.(object passed.) 一种(A)SpriteSurface
有个(has a)Width
和一个(and a)Height
属性与任何其他Windows Forms控件一样,但也具有"虚拟"大小的概念,其中控件的可见部分是进入整个虚拟区域的视口.要启用此功能,请设置(property like any other Windows Forms control, but it also has the concept of a “virtual” size, where the visible portion of the control is a viewport into the full virtual area. To enable this feature, set the)UseVirtualSize
财产(property to)true
,然后使用(, and set the virtual size using the)VirtualSize
属性.虚拟尺寸模式生效后,您可以使用(property. When the virtual size mode is in effect, you use the)OffsetX
和(and)OffsetY
属性以读取并设置左上角到虚拟空间的偏移量.使用虚拟尺寸时,请记住,精灵的X和Y坐标是在整个虚拟空间中表示的,而不是在虚拟空间的可见部分中表示的.(properties to read and set the offsets of the upper left hand corner into the virtual space. When using virtual size, remember that a sprite’s X and Y coordinates are expressed in the full virtual space, not the visible portion of the)SpriteSurface
.(.) 有许多属性可以在其中显示选择光标(There are a number of properties that expose a selection cursor in)SpriteSurface
.如果(. If)CursorVisible
是(is)true
,无论您在表面上单击什么位置,光标都将显示为矩形.光标的外观由(, the cursor will appear as a rectangle wherever you click on the surface. The cursor’s appearance is controlled by the)CursorColor
和(and)CursorWidth
属性及其位置(properties, and its location by the)CursorX
和(and)CursorY
属性.(properties.) 此外,当您在(Additionally, a selection band will appear when you drag the mouse on the)SpriteSurface
如果(, if)SelectionBandVisible
是(is)true
.选择条带的颜色由(. The color of the selection band is controlled by the)SelectionBandColor
属性.当用户确实绘制选择带时,(property. When the user does draw a selection band, the)SpriteSurface
触发(triggers the)RangeSelected
事件.(event.) 的(The)Wraparound
属性确定如果精灵对象移到虚拟尺寸之外时会发生什么情况(property determines what happens if sprite objects move outside the virtual size of the)SpriteSurface
.如果(. If)Wraparound
是(is)false
,允许子图形移动到实际尺寸之外,只是不渲染它们.如果(, sprites are allowed to move outside of the actual dimensions, they are just not rendered. If)true
,则移动超出表面一个边缘的精灵将出现在另一边缘,从而有效地环绕表面.(, then a sprite moving beyond one edge of the surface will appear at the other edge, effectively wrapping around the surface.)
雪碧(Sprite)
的(The) Sprite
类定义了可以移动并呈现到对象上的对象(class defines an object that can be moved around and rendered onto a) SpriteSurface
.(.) Sprite
是定义一个(is an abstract class that defines a) Position
财产(property, a) Width
和(and) Height
,以及所有子画面共有的一些其他属性. TurboSprite包含许多具体的派生Sprite类:(, and some other properties that are common to all sprites. TurboSprite contains a number of concrete derived sprite classes:)
-
BitmapSprite
使用一个(uses a)Bitmap
渲染自己.(to render itself.) -
AnimatedBitmapSprite
从(descends from)BitmapSprite
,并允许您指定一组(, and allows you to specify a set of)Bitmap
定义用于渲染精灵的动画帧.(s that define the frames of animation that are used to render the sprite.) -
PolygonSprite
根据您定义的一组点进行渲染,并支持围绕其轴的旋转.(renders itself based on a set of points that you define, and supports rotation around its axis.) -
ParticleExplosionSprite
生成基于粒子的爆炸,使您可以控制大小,速度和颜色范围.(generates a particle based explosion, allowing you to control the size, speed, and color range.) -
ShockwaveSprite
产生由向外辐射的圆组成的爆炸效果.(generates an explosive effect composed of outwardly radiating circles.) -
StarFieldSprite
再现经典的街机游戏星空超空间效果.(reproduces the classic arcade game star-field hyperspace effect.) 鼓励您使用这些作为示例并创建自己的示例(You are encouraged to use these as examples and create your own)Sprite
-后代类.(-descendant classes.) 的(The)Sprite
该类包含两个重要的方法,需要在此处进行进一步讨论:(class contains two important methods that warrant further discussion here:) -
的(The)
Process
方法是虚拟的,如果希望在具体的后代类中使用,则可以选择覆盖它. TurboSprite调用精灵的(method is virtual, and you can choose to override it if you wish in a concrete descendant class. TurboSprite calls a sprite’s)Process
动画的每一帧之前的方法,无论子图形是否在虚拟区域的可见部分内.在这里,您可以在每个动画帧期间执行希望应用于精灵的任何处理.这可能包括粒子散布,减少寿命计数器等.(method prior to each frame of animation, whether the sprite is within the visible portion of the virtual area or not. Here, you can perform any processing that you wish to apply to the sprite during each frame of animation. This can include things like particle dispersal, decrementing a life counter, etc.) -
的(The)
Render
方法是抽象的,因此必须在派生类中实现.它包含将小精灵实际绘制到(method is abstract, so it must be implemented in derived classes. It contains the code that actually draws the sprite onto the)SpriteSurface
.(.)Render
提供一个(provides a)Graphics
用于渲染精灵的对象.(object that you should use to render the sprite.) 渲染精灵时,请使用精灵的(When rendering a sprite, use the sprite’s)Location
,减去当前(, minus the current)OffsetX
和(and)OffsetY
的(of the)SpriteSurface
确定在哪画(to determine where to draw it on the)Graphics
目的.下面的例子是(object. The example below is the)Render
的方法(method of)BitmapSprite
,它使用一个(, which uses a)Bitmap
渲染自己.请注意,该代码还会减去(to render itself. Note that the code also subtracts half the size of the)Bitmap
渲染时,请确保(when rendering, ensuring that the)Bitmap
以小精灵的实际位置为中心.(is centered on the sprite’s actual position.)
//Render it on the sprite surface
protected internal override void Render(Graphics g)
{
g.DrawImage(Bitmap, X - WidthHalf - Surface.OffsetX,
Y - HeightHalf - Surface.OffsetY);
}
X
和(and) Y
是的属性(are properties of the) Sprite
类,让您可以访问其位置.如上所示,(class, giving you access to its location. As you can see above, the) Sprite
类提供对它的访问(class provides access to its) SpriteSurface
通过(via the) Surface
属性.(property.)
在(In) Sprite
派生的类,重要的是告诉TurboSprite Sprite有多大. TurboSprite结合使用此信息和Sprite的(-derived classes, it is important to tell TurboSprite how large the sprite is. TurboSprite uses this information, in combination with the sprite’s) Position
,以确定是否需要在每个动画帧期间进行渲染.精灵的(, to determine if it needs to be rendered during each animation frame. The sprite’s) Shape
财产((property (a) RectangleF
)应该分配给() should be assigned in a) Sprite
派生的类来定义其大小.的(-derived class to define its size. The) Shape
属性的设置应与精灵的位置无关.例如,如果一个精灵的大小为20x20像素,(property should be set irrespective of the sprite’s location. For example, if a sprite is 20x20 pixels in size, its) Shape
属性应设置为新(property should be set to a new) RectangleF
(-10,-10\10\10);这将使精灵的形状围绕其位置居中.您应该设置((-10, -10, 10, 10); this centers the sprite’s shape around its location. You should set the) Shape
属性,使其大致与您在(property so that it roughly corresponds to the image that you draw during the) Render
方法.(method.)
在下面,我们看到(Below, we see that the) BitmapSprite
设置(sets the) Shape
财产时(property when the) Bitmap
被安排了:(is assigned:)
//The bitmap used to render the sprite
public Bitmap Bitmap
{
get
{
return _bitmap;
}
set
{
_bitmap = value;
if (_bitmap != null)
Shape = new RectangleF(-_bitmap.Width / 2, -_bitmap.Height / 2,
_bitmap.Width, _bitmap.Height);
}
}
TurboSprite支持单击精灵并通过以下方式通知客户端(TurboSprite supports the clicking of sprites and notifying the client through a) SpriteClicked
事件.您并不总是希望精灵的可见绘制区域来确定点击时定义的精灵区域.因此,(event. You don’t always want a sprite’s visible drawn region to determine the area of the sprite that defines when it is clicked. Because of this, the) Sprite
类也有一个(class also has a) ClickShape
如果希望使可点击区域与(property that you can set if you wish to make the clickable region different than the) Shape
.默认情况下,(. By default,) ClickShape
假设任何(assumes the value of whatever the) Shape
属性设置为.(property was set to.)
的(The) Sprite
类还定义了一些描述旋转的属性,包括(class also defines some properties that describe rotation, including) FacingAngle
,(,) Spin
和(, and) SpinSpeed
.如果(. If) Spin
设定为(is set to) SpinType.ClockWise
要么(or) SpinType.CounterClockwise
,然后TurboSprite将自动调整精灵的(, then TurboSprite will automatically adjust the sprite’s) FacingAngle
在每个动画周期中.取决于派生(during each animation cycle. It is up to the derived) Sprite
类来利用(classes to utilize the) FacingAngle
当他们渲染精灵时.要查看执行此操作的示例,请检查(when they render the sprite. To see an example of one that does, examine the code for the) PolygonSprite
类.(class.) PolygonSprite
维护一个内部点列表,这些点定义了精灵的多边形形状.在此期间(maintains an internal list of points that define the polygon shape of the sprite. During the) Process
方法,根据精灵的角度旋转点(method, the points are rotated based on the sprite’s) FacingAngle
:(:)
//Process the sprite on each animation cycle - handle rotation
protected internal override void Process()
{
//Process rotation of shape
if (FacingAngle != _lastAngle)
{
float sin = Sprite.Sin(FacingAngle);
float cos = Sprite.Cos(FacingAngle);
_lastAngle = FacingAngle;
for (int p = 0; p < _points.Length; p++)
{
_points[p].X = _unrotated[p].X * cos - _unrotated[p].Y * sin;
_points[p].Y = _unrotated[p].Y * cos + _unrotated[p].X * sin;
}
//This causes Shape to be correctly recalculated
Points = _points;
}
}
作为附带说明,(As a side note, the) Sprite
类创建正弦和余弦值的静态查找表,以减少动画周期中的计算开销,并且(class creates static lookup tables of sin and cos values that reduce calculation overhead during the animation cycle, and) PolygonSprite
在上面的代码中利用了这些查找表.(makes use of these lookup tables in the code above.)
精灵引擎(SpriteEngine)
要让您的精灵出现在(To have your sprites appear on the) SpriteSurface
,必须将它们添加到(, they must be added to a) SpriteEngine
.(.) SpriteEngine
是管理小精灵运动和碰撞检测的非可视组件.(is a non-visual component that manages sprite movement and collision detection.) SpriteEngine
有个(has a) Surface
属性应设置为(property which should be set to the) SpriteSurface
它的精灵将被吸引.你可以用几个(that its sprites will be drawn on. You can use several) SpriteEngine
连接到相同的(s connected to the same) SpriteSurface
为同一表面上的不同组的精灵提供不同的行为.(to provide different behaviors to different groups of sprites on the same surface.)
的(The) SpriteEngine
的(’s) Priority
属性确定多个对象时精灵的渲染顺序(property determines the order in which sprites are rendered when multiple) SpriteEngine
s连接到(s are connected to a) SpriteSurface
.(.)
精灵之间的碰撞检测是通过设置(Collision detection among sprites is handled by setting the) SpriteEngine
的(’s) DetectCollisionSelf
和(and) DetectCollisionFlag
属性.的(properties. If) DetectCollisionSelf
是(is) true
,(, the sprites within the) SpriteEngine
将检测彼此之间的冲突.当多个(will detect collisions among themselves. When multiple) SpriteEngine
使用,具有相同值的(s are used, the ones that have the same values for) DetectCollisionFlag
将检测彼此之间的冲突.当检测到精灵碰撞时,(will detect collisions amongst themselves. When a sprite collision is detected, the) SpriteSurface
触发一个(triggers a) SpriteCollision
事件,将两个传递给您(event, passing you the two) Sprite
碰撞的物体.(objects that collided.)
移动精灵(Moving Sprites)
除非有某种使它们运动的方法,否则精灵几乎一文不值!在TurboSprite中,这由从(Sprites are hardly worth anything unless there is some way of putting them into motion! In TurboSprite, this is handled by components that descend from) SpriteEngine
.的(. The) SpriteEngine
提供用于定义精灵运动的设计模式.派生组件可以利用此模式创建移动精灵的不同方法. TurboSprite包含一个这样的后代,即(provides a design pattern for defining a sprite’s movement. Derived components can utilize this pattern to create different ways to move sprites. TurboSprite contains one such descendant, the) SpriteEngineDestination
组件,将精灵以特定的速度移向特定的目的地.(component, which moves sprites at a specific speed towards a specific destination.)
这里的设计利用了特殊的标记属性(The design here utilizes a special tag property in the) Sprite
类称为(class called) MovementData
.一种(. A) SpriteEngine
派生的组件可以将所需的任何对象分配给此属性,以跟踪和/或控制精灵的运动,只要它认为合适即可.设置此值的位置在(-derived component can assign whatever object it needs to this property to track and/or control the movement of the sprite, as it sees fit. The place to set this value is in the) InitializeSprite
的方法(method of) SpriteEngine
,应在派生类中覆盖它.的(, which should be overridden in derived classes. The) SpriteEngineDestination
覆盖此方法以创建一个实例(overrides this method to create an instance of a) DestinationMover
对象,并将其分配给(object, and assigns it to the) Sprite
的(’s) MovementData
属性:(property:)
//Create a DestinationMove object and attach it to the sprite
protected override void InitializeSprite(SCG.TurboSprite.Sprite sprite)
{
sprite.MovementData = new DestinationMover(sprite);
}
SpriteEngineDestination
提供了一个称为(provides a public method called) GetMover
返回的实例(which returns the instance of the) DestinationMover
给客户一个特定的(to the client for a particular) Sprite
目的.的(object. The) DestinationMover
类本身包含一些属性,这些属性描述了精灵的速度和目标以及精灵到达目的地后是否应该停止移动.因此,客户端代码可以通过设置(class itself contains properties that describe a sprite’s speed and destination and whether or not the sprite should stop moving once it reaches its destination. The client code can thus cause a sprite to move by setting the) DestinationMover
对象的(object’s) Speed
和(and) Destination
属性.(properties.)
TurboSprite调用时会执行运动逻辑(TurboSprite executes the movement logic when it calls the) SpriteEngine
的(’s) MoveSprite
方法.这在每个动画周期内发生.(method. This happens during each animation cycle.) SpriteEngineDestination
覆盖(overrides the) MoveSprite
方法,并采用其自定义移动逻辑.请参阅代码(method and employs its custom movement logic. See the code for the) SpriteEngineDestination
以及其中包含的注释,以便更全面地了解精灵运动设计模式.尽管看起来很麻烦,但是它为将来可以添加的不同运动行为提供了一定程度的灵活性.(and the comments contained, for a more thorough understanding of the sprite movement design pattern. Although it may seem cumbersome, it provides a level of flexibility for different movement behaviors that can be added in the future.)
TurboSprite演示应用(The TurboSprite Demo App)
源代码中包含一个完整的演示应用程序,该应用程序说明了如何创建精灵并将其添加到(Included in the source code is a full demo application that illustrates creating sprites, adding them to) SpriteEngine
并移动它们.它还涉及了TurboSprite附带的其他一些优点,例如(s, and moving them. It also touches on some of the other goodies that come with TurboSprite, like the) GamePieceBitmapFactory
组件,使您可以轻松访问单个Sprite图形,这些图形可以包含在单个较大的图形中(component that lets you easily access individual sprite graphics that can be contained in a single larger) Bitmap
,甚至将它们着色为任何特定的颜色.(, and even colorize them to any specific color.)
这是单击"位图Sprite"按钮时执行的代码.这创建了一个(Here is the code that executes when the “Bitmap Sprite” button is clicked. This creates a) BitmapSprite
实例,并将其应用于(instance, and puts it into action on the) SpriteSurface
.(.)
private void btnAddSprite_Click(object sender, EventArgs e)
{
//Create a BitmapSprite
BitmapSprite s = new BitmapSprite((Bitmap)picGlyph.Image);
s.Bitmap.MakeTransparent(Color.Black);
//Center it on the SpriteSurface
s.Position = new Point(surface.Width / 2, surface.Height / 2);
//Add it to the SpriteEngine
engineDest.AddSprite(s);
//Set its speed and destination
DestinationMover dm = engineDest.GetMover(s);
dm.Speed = rnd.Next(10) + 1;
dm.Destination = new Point(rnd.Next(surface.Width), rnd.Next(surface.Height));
dm.StopAtDestination = false;
}
TurboSprite在行动(TurboSprite in Action)
TurboSprite是我的免费实时策略游戏中使用的动画引擎,(TurboSprite is the animation engine used in my freeware real-time strategy game,) 太阳复仇(Solar Vengeance) . Solar Vengeance使用了此处描述的许多TurboSprite功能,其中的一些功能已包含在包装中,但本文并未涉及:(. Solar Vengeance uses many of the TurboSprite features described here, and some that are included in the package but not touched on in this article:)
- 使用一些自定义(Uses a number of custom)
Sprite
派生类,以呈现StarShips和Star Systems.(-derived classes to render StarShips and StarSystems.) - 使用(Uses the)
AnimatedBitmapSprite
类来渲染虫洞.(class to render Wormholes.) - 使用(Uses the)
ParticleExplosionSprite
和(and)ShockwaveSprite
进行爆炸.(s to render explosions.) - 使用(Uses the)
SquareGridSpriteSurface
作为主表面.这是从基本(as the main surface. This is a component that derives from the basic)SpriteSurface
,但提供了其他功能,可让您使用正方形网格.(, but provides additional functionality that allows you to work with square grids.) - 使用(Uses the)
SpriteEngineDestination
在运动场上移动精灵.(to move sprites on the playing field.) 前往(Visit the) 硅指挥官游戏(Silicon Commander Games) 网站,以了解有关TurboSprite,Solar Vengeance以及我们的开源.NET多人游戏和聊天组件包的更多信息,(website to learn more about TurboSprite, Solar Vengeance, and our open-source .NET multiplayer gaming and chat component package,) 棱镜服务器(PrismServer) .(.)
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
C# .NET .NET2.0 GDI+ Dev 新闻 翻译