如何创建一个精灵图像

7
我正在尝试创建一个非常基本的精灵图像。
首先,我有一张现有的图片(宽度为100像素,高度为100像素)。
我将循环遍历此图像10到100次,每次将其放置在前一个图像旁边。
精灵限制为3000像素宽。
将图像放在一起是可以的,因为我可以用简单的方法将它们合并,但是,我需要将组合图像的宽度限制在3000像素以内,然后开始新行。

听起来很简单;在总图像长度小于3000px的情况下,循环追加图像。 - KeithS
1
http://stylemeltdown.com/image-sprite-navigation-with-css/ - Sully
这就是我想的,但是你可以看到,当精灵总宽度达到3000像素时,我必须从“新行”开始。 - stoic
1
嗨,@DustyRoberts,关于你的问题,我走在正确的轨道上吗? - Daniel Mošmondor
抱歉问题表述不够清晰,我指的不是游戏开发者所知道的精灵,而是网页开发者和HTML人员所知道的图像精灵。@Matt,你的回答很完整,所以赏金给了你,但是Daniel,我将你的回答标记为最佳答案,因为你确实理解了我的问题 :) - stoic
4个回答

7
以下MSDN文章中有关2D图像精灵的信息非常丰富:渲染2D图像精灵
这些示例都是基于Microsoft's 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 类的实例,该实例是游戏时间状态的快照,以值的形式表示,可用于变量步长(实时)或固定步长(游戏时间)游戏。如果这对您有帮助,请让我知道。

2
嗨,马特,StackOverflow的答案通常包括链接内容的摘要或针对问题特别回答的亮点。SE网站的目标是成为未来数年的知识和答案资源。使用仅链接的答案,原始问题必须查阅其他资源以找到可能不确定的答案。最重要的是,如果您的链接随着时间的推移而破损(微软经常这样做),您的答案对于未来访问此页面的任何人都没有用。考虑编辑您的答案以添加更多细节。祝你好运! - Jeremy Thompson
3
嗨Jeremy,我同意,因此我添加了更多细节。问候,马特 - Matt

3

让我试着用一些伪代码:

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
}

2

在3000处声明一个变量,如果插入一张宽度为250的图片,则从该变量中减去该宽度,并重复此步骤。这也可以让你决定是否在该行上留有足够的空间来容纳下一张图片,方法是检查剩余数字是否大于下一张图片的宽度。每次开始新行时,请将变量重置为3k并重新开始。问题已解决。


2
一种可行的方法是允许将精灵帧放置在位图的任何位置(这样可以使它们更加紧凑),并且每个位图都附带一个(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文件、读取位图,当开始动画时:启动一个定时器以固定的时间间隔触发。当它触发时,您通过逐一添加Keyframe的持续时间并在总和超过触发时间时停止来计算动画中的正确Keyframe;应该使用当前Keyframe。
在上面的XML文件中,我添加了一些东西,例如偏移量,允许您在动画期间修改精灵的位置(甚至可以进行插值以使其平滑移动)。
剩下的就是从位图中获取正确的帧。作为优化,您可以在加载XML文件时预处理位图,通过抓取帧并将其保留为微小位图,丢弃大位图。当位图较大且没有完全覆盖帧时,这可能会优化内存。
在其他情况下,您不进行预处理,只需复制帧。
对于较大的应用程序(更多的位图/动画/帧),我建议创建一个应用程序来创建和编辑XML文件。另一个选择可能是为您喜爱的绘画程序创建插件(如果可能)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接