65.9K
CodeProject 正在变化。 阅读更多。
Home

Sprite Editor 2019:我的小体操运动员

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2019 年 1 月 24 日

CPOL

10分钟阅读

viewsIcon

5236

downloadIcon

144

用单个 classSprite 实例绘制不同外观的多个精灵

这是本系列文章中的第三篇,该系列始于 Sprite Editor 2017

引言

在本文中,我将向您展示如何使用单个 classSprite 实例绘制相同的精灵,以便屏幕上的每个精灵看起来都与前一个不同,方法是在运行时动态更改精灵四肢的图像。这是我的意思的截图。

我们已经在 Bugs 文章中了解了如何在屏幕上放置精灵。因此,今天我们将研究如何使用另一个专为此目的设计的类 classUniform 来更改精灵的外观。

实现方法

我将保持本文简短,因为还有其他项目我想进行。基本上,此应用程序所做的就是从其“资源”目录中获取图像,这些图像分为四类

  1. 发型 - 他们的发色图像
  2. 体操服 - 体操运动员穿着的体操服可以是各种颜色
  3. 肤色 - 有三种肤色:白色、黑色和浅肤色
  4. 通用 - 这些是任何前一类都不适用的图像

发型和通用类别相对简单。随机选择的发色图像从文件中加载并按原样使用,而舌头、眼睛和花束等通用图像对所有女孩都相同。当涉及到体操服和肤色时,就会出现复杂性,因为其中一些需要像发型一样随机选择,但它们必须动态地粘贴在一起以生成两者的组合图像。TorsoBottom 图像和大多数 SkinTone 图像本身都可以,但 TorsoTopArmLeftArmRight 四肢需要在运行时生成,以满足肤色/体操服颜色的随机组合。

原始源图像在应用程序加载时首先被旋转。它们是非常小的图像,旋转起来花费的时间很短,因此可以在运行时完成,而默认的体操运动员在屏幕上进行动画,以分散用户的注意力。这里的优点是您可以添加更多图像,任意数量的头发颜色、款式、不同的肤色和体操服。您甚至可以制作一个男孩体操运动员,或者一个警察,或者任何图像大小相同的类人动物。您只需要遵循此应用程序期望的标准源文件图像名称约定。我稍后会讲到这一点。classUniform 会列出所有源文件名和所有旋转后的图像文件名,比较这两个列表,然后加载并旋转任何不在已旋转图像文件名列表中的新源图像。这项工作是一个繁琐的过程,涉及按名称标签收集图像,将所有肤色与肤色、颜色与颜色进行收集。然后,它将发型与体操服分开,并管理按颜色排序的体操服零件列表。每个列表都有完整的相应肤色/发色/体操服类型。请注意,此时,应用程序实际加载的唯一图像是它必须旋转并保存到文件中的图像。这些列表只是排序后的文件名列表。完成此过程后,源数据已被排序,可以用于生成它们的随机组合并为我们的小体操运动员制作“服装”。只有那时,每个 formGymnast 实例才会加载适合其“服装”的图像。

到目前为止,我已经尝试了两次失败,试图包含一种快速简便地交换精灵图像的方法。问题在于,目前 classAnimation_Frame_LimbData 持有一个指向四肢的指针以及该帧定位四肢所需的变量,但我必须重写整个方案,并将 HingeContactsLimbImages 放在同一个类中,然后保持这些集合的顺序与每个服装的四肢相同。因此,一个精灵的铰链触点不再需要与同一精灵的下一个版本匹配 limbImages。同一精灵的每个版本的四肢图像都携带绘制精灵所需的 HingeContact 信息。这是可行的。我只是渴望发布这个项目作为一种宣泄。我会在完成这项任务时进行更新,并在第四篇文章中告知您。无论何时发生。

如何装扮您的精灵

一旦准备好四肢图像,其实没什么可做的。您需要的所有用于交换精灵外观的代码都可以在 formGymnastAnimate() 函数的前几行中找到。让我们看一下

classAnimation_Frame cFrame 
         = cData.cAnimationData.cAnimation.lstFrames[cData.cAnimationData.intFrameIndex];

setSpriteUniform(ref cFrame);

bmpImage = cData.cAnimationData.cSprite.draw_Animation_Frame(ref cData);
SetBitmap(bmpImage, (byte)255);

Point ptRelLimb 
         = (Point)cData.cDrawData_current.cAT_LimbPositions.Search(cFrame.Limb_DrawRelativeTo.Name);  
Location = cMath3.SubTwoPoints(cData.pt, ptRelLimb);

首先,我们将要绘制的帧加载到一个变量中,该变量可以用作对函数调用的指针

setSpriteUniform(ref cFrame);

这是图像被交换的地方。

public bool bol_I_Am_the_Loading_Sprite = false;
void setSpriteUniform(ref classAnimation_Frame cFrame)
{
    for (int intLimbCounter = 0; intLimbCounter < cFrame.lstDrawSequence.Count; intLimbCounter++)
    {
        classSprite_Limb cLimb = cFrame.lstDrawSequence[intLimbCounter];
        if (cLimb == null) return;

        List<classsprite_limb.classsprite_limb_images> lstImages = 
             (List<classsprite_limb.classsprite_limb_images>)
              cUniform.cAT_LimbImages_ByLimb.Search(cLimb.Name);
        if (lstImages != null)
            cLimb.lstImages = lstImages;
    }
}

由于所有女孩都有自己的“服装”,因此每个体操运动员都必须将自己的图像复制到已经存在于 classSprite 中的图像,而 setSpriteUniform() 函数是所有操作发生的地方。这基本上就是您需要做的所有操作来更改精灵的外观。加载四肢,搜索服装的 LimbImage alphaTree 以获取该四肢的图像,并将结果转换为列表。然后,当您知道您的 LimbImages 列表没问题时,您只需让该四肢的 lstImages 指向这组新图像即可。很简单。

当应用程序离开此函数时,它会返回到 Animate() 函数,从 classSprite 获取输出图像,然后将其放置在屏幕上,就像前一篇文章的 Bugs 应用程序中的 formCreepyCrawler 所做的那样。

有限状态机

虽然 FSM 不是本文的主题,但我还是要说几句。基本上,它跟踪体操运动员正在做什么。它主要在随机预定的次数内循环播放相同的动画。当它完成该动画的最后一帧时,它会进入 Switch/Case 来决定要做什么。如果其当前 FSM 状态是 Frolick,那么它将随机选择另一个动画并重复任意次数。但是,如果被告知 Wrap_It_Up,那么她的 FSM 状态将被切换到 Waving。完成该动画后,她会再次通过 Switch/Case,但现在她处于 Waving 的 FSM 状态,所以这次她的 FSM 状态被设置为 Exiting,她开始走离屏幕。当她再次到达同一个 Switch/Case 时,她会问自己是否已经离开屏幕。如果不是,她将继续行走动画的另一个循环,并且最终会在 Exiting 动画的结尾到达屏幕外的某个点,她的 FSM 状态将被设置为退出。此时,父调用窗体将检测到它并处理 formGymnast 的该实例。

所有这些工作都在 FSM 属性和 Animate() 函数中的 Switch/Cases 中完成。这是一个非常基础的有限状态机。

为体操运动员添加图像

当然,您也可以创建和添加自己的图像。您必须牢记体操运动员应用程序期望的文件命名约定。

  • 有三种类型的图像组。为了让您的图像包含在应用程序中,它所属的组必须是完整的。该集合中的所有图像都必须存在,才能包含其中的任何图像。

  • 上面列出了包含在三个集合中的图像的基本文件名。
  • 您添加到应用程序的所有文件都必须具有唯一的标识符名称标签添加到其基本名称中。(例如,Hair_PinkPonytail_Pink 构成一个完整的集合)
  • 肤色必须以“Skinned”一词结尾,以区分它们与体操服图像,其中 ArmLeft_ArmRIght_TorsoTop_ 同时出现在 LeotardSkintone 列表中。仔细查看“资源”目录中已有的文件列表可能有助于您为图像命名。(例如,ArmLeft_BlackSkinned 是一个 skintone,而 ArmLeft_Pink 是一个 leotard,当随机组合这两者时,您将拥有一个穿着粉色体操服的黑肤色体操运动员。)
  • 您不限于原始源材料中代表的发型。最简单的方法是使用现有图像的副本并更改颜色。更改图像形状更难,因为应用程序会相对于图像中心对其进行定位。Hair_MohawkBlack.bmp 图像是一个您可以使用的示例,其中图像垂直向上拉伸以适合莫西干发型,因此必须垂直向下拉伸相同的量,以便头发能够正确地出现在精灵上。

为了生成您想要的图像并确保您拥有完成集合所需的所有图像,最简单的方法是创建一个单独的目录,复制您想要模仿的图像,并确保在您的工作目录中有一个完整的集合。然后,逐一检查每个图像并调整其颜色和样式。您可以制作一个鲍勃·马利(Bob Marley)的体操服。什么都可以。当您对新图像满意时,将它们复制到资源目录中,并使用适合其外观的新名称,并遵循上述规则。当您再次运行应用程序时,您的图像应该会被包含,您将拥有新的发型和体操服可以欣赏。

请记住,图像在包含到项目中后会存储在 .rot 文件中,因此仅更改现有文件的 .bmp 文件将不会被 App 识别,直到您删除具有相应名称的 .rot 扩展名的文件。

例如,如果您编辑“Resources”目录中已有的 Hair_Pink.bmp 文件并将其保存为相同名称。在删除同名的 Hair_Pink.rot 文件之前,您的更改不会加载到 App 中。

下一步

在撰写这些文章时,回顾 SpriteEditor、Bugs 和 Gymnasts 应用程序的过程中,我意识到我可以做一些事情来提高性能

  1. 审查缓存图像时测试 LimbImage 名称的必要性
  2. 绘制每个帧的单个全尺寸图像,仅调整输出图像和四肢位置变量的大小,而不是调整每个单独四肢的大小。
  3. 重新思考帧定位四肢的方式,以便有一个新类,它同时包含四肢图像和四肢铰链触点。维护一个与四肢列表顺序相同的此类列表,整个 limbImages 和触点铰链列表可以与一个可变的弹药筒(如可更换弹药筒)一起加载,这将允许创建描述通用生物类型的精灵,如类人动物或六足昆虫,它们共享相同的动画,但加载它们自己的“弹药筒”图像及其附带的铰链触点,极大地提高了整个类的灵活性和通用性。

不过,目前,我很高兴将这件事放在一边,回到我的 LatinProject。

谢谢,如果您愿意,也许我们会再次这样做。再见!

© . All rights reserved.