我正在尝试创建一个非常基本的精灵图像。
首先我有一个现有的图像(宽度=100px,高度=100px)。
我将在这张图片中循环 10 到 100 次,每次都将它放在上一张旁边的精灵上。
精灵被限制为 3000px 宽。
将图像彼此相邻放置很好,因为我可以用简单的方法将它们组合起来,但是,我需要将组合图像的宽度限制为 3000 像素,然后从新行开始。
我正在尝试创建一个非常基本的精灵图像。
首先我有一个现有的图像(宽度=100px,高度=100px)。
我将在这张图片中循环 10 到 100 次,每次都将它放在上一张旁边的精灵上。
精灵被限制为 3000px 宽。
将图像彼此相邻放置很好,因为我可以用简单的方法将它们组合起来,但是,我需要将组合图像的宽度限制为 3000 像素,然后从新行开始。
在下面的 MSDN 文章中有很多关于 2D-sprites 的信息:Rendering 2D sprites
这些示例基于Microsoft 的 XNA,这是一个可在 Visual Studio 中用于为 Windows、Windows Phone 和 XBOX 360 开发游戏的平台。
例如,要绘制精灵,可以使用以下 C# 代码(示例取自 MSDN 文章,已删除 XBOX 360 特定代码):
private Texture2D SpriteTexture;
private Rectangle TitleSafe;
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
SpriteTexture = Content.Load<Texture2D>("ship");
TitleSafe = GetTitleSafeArea(.8f);
}
protected Rectangle GetTitleSafeArea(float percent)
{
Rectangle retval = new Rectangle(
graphics.GraphicsDevice.Viewport.X,
graphics.GraphicsDevice.Viewport.Y,
graphics.GraphicsDevice.Viewport.Width,
graphics.GraphicsDevice.Viewport.Height);
return retval;
}
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
Vector2 pos = new Vector2(TitleSafe.Left, TitleSafe.Top);
spriteBatch.Draw(SpriteTexture, pos, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
你需要调用LoadContent()
来初始化它,然后你需要调用GetTitleSafeArea(100)
来获得安全的绘制区域(在本例中为 100%),最后你可以使用该Draw
方法。它接受一个包含GameTime
类实例的参数,该实例是游戏计时状态的快照,以可变步长(实时)或固定步长(游戏时间)游戏可以使用的值表示。
请让我知道这是否对您有帮助。
让我尝试一些伪代码:
Bitmap originalImage; // that is your image of 100x100 pixels
Bitmap bigImage; // this is your 3000x3000 canvas
int xPut = 0;
int yPut = 0;
int maxHeight = 0;
while (someExitCondition)
{
Bitmap imagePiece = GetImagePieceAccordingToSomeParameters(originalImage);
if (xPut + imagePiece.Width > 3000)
{
xPut = 0;
yPut += maxHeight;
maxHeight = 0;
}
DrawPieceToCanvas(bigImage, xPut, yPut, imagePiece);
xPut += imagePiece.Width;
if (imagePiece.Height > maxHeight) maxHeight = imagePiece.Height;
// iterate until done
}
在 3000 处声明一个变量,如果您放入一张宽度为 250 的图片,请将其从变量中取出,继续这样做,这也允许您通过查看数字是否在该行上留出足够的空间用于下一张图片left 大于下一张图片的宽度。每次从新行开始时,将变量设置回 3k 并重新开始。解决了
一种可行的方法是允许将精灵的帧放置在位图中的任何位置(这样可以使它们更紧凑),并为每个位图附上一个描述每个帧的位置、大小和原点的 (n xml) 文件和有所有动画的列表。像这样的东西:
<SpriteSheet>
<Frames>
<Frame id="0" location="20,40" size="64,64" origin="32,32" />
<Frame id="1" location="100,40" size="64,64" origin="32,32" />
<Frame id="2" location="164,40" size="64,64" origin="0,0" />
<Frame id="3" location="20,120" size="64,64" origin="32,32" />
</Frames>
<Animations>
<Animation name="walk left" >
<Keyframes>
<Keyframe frameId="0" duration="0:0:0.5" offset="-5,0" />
<Keyframe frameId="1" duration="0:0:0.5" offset="-5,0" />
<Keyframe frameId="2" duration="0:0:0.4" offset="-2,0" />
<Keyframe frameId="1" duration="0:0:0.5" offset="-5,0" />
</Keyframes>
</Animation>
<Animation name="walk right" >
<Keyframes>
<Keyframe frameId="5" duration="0:0:0.5" offset="5,0" />
<Keyframe frameId="6" duration="0:0:0.5" offset="5,0" />
<Keyframe frameId="2" duration="0:0:0.4" offset="2,0" />
<Keyframe frameId="6" duration="0:0:0.5" offset="5,0" />
</Keyframes>
</Animation>
</Animations>
</SpriteSheet>
通过这种方式,您可以在动画中重复使用帧(从而进一步优化位图大小)并通过简单地编辑 XML 文件来自定义动画。
您所要做的就是读取 XML 文件、读取位图并在开始动画时:启动一个定期计时的计时器。当它滴答作响时,您可以通过将关键帧的持续时间一一添加并在总和超过滴答时间时停止来计算动画中的正确关键帧;应该使用当前的关键帧。
在上面的 XML 文件中,我添加了诸如偏移之类的东西,它允许您在动画期间修改精灵的位置(您甚至可以对其进行插值以使其平滑移动)
剩下的就是从位图中抓取正确的帧。作为一种优化,您可以在加载 XML 文件时通过抓取帧来预处理位图,将它们保留为小位图,并丢弃大位图。当位图很大并且没有完全覆盖在帧中时,这可能会优化内存。
在其他情况下,您无需进行预处理,只需对帧进行 blit。
对于较大的应用程序(更多位图/动画/帧),我建议创建一个应用程序来创建和编辑 XML 文件。另一种选择可能是为您最喜欢的绘画程序创建一个插件(如果可能的话)