简体   繁体   English

不使用XNA或其他第三方库的2d Sprite动画

[英]2d Sprite Animations without using XNA or other third-party libraries

I want to create a simple game, similar to what can be created with RPG Maker. 我想创建一个简单的游戏,类似于可以使用RPG Maker创建的游戏。 What I am primarily looking for at the moment is a tutorial which can guide me on how to accomplish it without using XNA or any other specific library. 目前,我主要寻找的是一个教程,该指南可以指导我如何在不使用XNA或任何其他特定库的情况下完成它。

The ideal would be a step-by-step tutorial or a good, easy-to-understand example. 理想的方法是分步教程或一个很好的,易于理解的示例。

My goal is to do it on my own, and come to an understanding of how the overall process works with regards to animation elements relating to one another. 我的目标是自己做,并了解整个过程如何处理彼此相关的动画元素。

I've already built a simple snake game in the past using a simple tutorial, but there was no movement animation in it and that's the primary thing I'm wanting to learn next. 过去,我已经使用简单的教程构建了一个简单的蛇游戏,但是其中没有动作动画,这是我接下来要学习的主要内容。

Edit: 编辑:

All of the tutorials I have found so far use third-party libraries. 到目前为止,我发现的所有教程都使用第三方库。 I did come across this link , but I'm looking for something which doesn't include XNA. 我确实遇到了此链接 ,但是我正在寻找不包含XNA的东西。

There are a number of ways to approach the topic you're describing. 有多种方法可以处理您正在描述的主题。 I'm going to give a bit of an overview, and then hopefully provide some resources which can give you examples to get you started. 我将提供一些概述,然后希望提供一些资源,这些资源可以为您提供示例以帮助您入门。

Essentially, sprite-based animations revolve around having a series of similar images which, when displayed sequentially, create the appearance of motion, similar to a flip-book. 本质上,基于子画面的动画围绕着拥有一系列相似的图像而展开,这些图像在顺序显示时会产生类似于翻书的运动外观。

The trick is to understand when your sprite is moving (and therefore should be animated) - and when it is standing still (and therefore should not be animated). 诀窍是要了解您的精灵何时移动(因此应设置动画)-何时静止(因此不应设置动画)。 In other words - assuming that your game's character is only supposed to move while you hold , , or , you need to detect when one of those keys starts and stops being pressed, so that you can start/stop your animation accordingly. 换句话说-假设你的游戏角色只应该移动,而你持有▲,▶,▼◀,你需要的时候按下这些键启动的一个并停止检测,这样就可以启动/相应停止动画。

Imagine that for simplicity, you only have 2 sprites. 想象一下,为简单起见,您只有2个精灵。 The first (left, below) represents your character standing still, and the second represents your character mid-step (right, below): 第一个(左下方)代表您的角色静止不动,第二个表示您的角色中间步骤(右下方):

马里奥

When the button is not pressed, you simply continually display the first image. 当不按按钮时,您只需连续显示第一张图像。 When the button is pressed, you toggle between the two every x milliseconds (depending on how fast you want the animation to appear). 按下 按钮,您的每两个之间切换x毫秒(这取决于你想如何快速的动画显示)。

An animated .gif is one format in which you can contain a series of simple image frames, which are intended to be displayed as a series (and therefore create the illusion of animation). 动画.gif是一种格式,您可以在其中包含一系列简单的图像帧,这些图像帧应按一系列显示(并因此产生动画的幻觉)。 If you were to create your sprites using this format, you could use code similar to that found in this SO discussion , which provides some example code for how to use C# to animate an animated .gif and control its start/stop. 如果要使用这种格式创建子画面,则可以使用与本SO讨论类似的代码,该讨论提供了一些示例代码,说明如何使用C#为动画.gif设置动画并控制其开始/停止。

Alternatively, if you wanted to use a sprite file (like the one I included above), you could use something similar to this CodeProject code , which focuses on GDI interaction with the Windows environment in order to extract and paint a portion of the sprite onto a target canvas. 另外,如果您想使用一个sprite文件(如我上面包含的文件),则可以使用与此CodeProject代码类似的内容, 该代码专注于与Windows环境的GDI交互,以便将sprite的一部分提取并绘制到目标画布。 By repainting every x milliseconds (as mentioned above), this can provide the same effect. 通过每x毫秒重绘一次(如上所述),可以提供相同的效果。

A few things to keep in mind: 请记住以下几点:

You'll need to handle transparency in your sprites (the Mario sprite above, as an example, has a transparent background) - so that the background of your game environment shows through. 您需要处理子画面的透明性(例如,上面的Mario子画面具有透明的背景)-这样才能透彻游戏环境的背景。 If using GDI - this all has to do with how you call the painting methods. 如果使用GDI-这与您如何调用绘画方法有关。 If using an animated .gif - the method to use depends on how you display it on your window. 如果使用动画的.gif-使用的方法取决于您在窗口上显示的方式。

For some additional resources / examples / references, check out the following resources: 有关其他资源/示例/参考,请查看以下资源:

And for Sprite development: 对于Sprite开发:

I threw together than example of what I think it is that you were after. 我举了一个例子,证明我所追求的是你所追求的。 This example can be applied to buttons or picture boxes. 此示例可以应用于按钮或图片框。 I chose this way of out of simplicity. 我出于简单性而选择了这种方式。

Each instance of an animation holds a timer, and a list of images. 动画的每个实例都包含一个计时器和一个图像列表。 Updating the image of the target control whenever the timer fires its event. 每当计时器触发其事件时,更新目标控件的图像。

I have uploaded my project file here. 我已经在这里上传了我的项目文件。 http://mcspazzy.com/code/ParTest.zip http://mcspazzy.com/code/ParTest.zip

Hopefully it is enough to help. 希望有足够的帮助。 Just ask if you need more explanation. 请问您是否需要更多说明。

The class 班级

public class Animation
{
    readonly Timer _animtimer = new Timer();

    public List<Image> Frames;

    public int FrameIndex;

    private Button _target;
    private PictureBox _ptarget;

    public void Target(PictureBox target)
    {
        _ptarget = target;
    }

    public void Target(Button target)
    {
        _target = target;
    }

    public int FrameSpeed
    {
        get { return _animtimer.Interval; }
        set { _animtimer.Interval = value; }
    }

    public Animation()
    {
        Frames  = new List<Image>();
        _animtimer.Interval = 100;
        _animtimer.Tick += Update;
    }

    public void Play()
    {
        _animtimer.Start();
    }

    public void AddFrame(string file)
    {
        Frames.Add(Image.FromFile(file));
    }

    public void Stop()
    {
        _animtimer.Stop();
    }

    private void Update(object sender, EventArgs eventArgs)
    {
        FrameIndex++;

        if (FrameIndex == Frames.Count)
        {
            FrameIndex = 0;
        }
        _target.Image = Frames[FrameIndex];
        _ptarget.Image = Frames[FrameIndex];
    }

    public static implicit operator Image(Animation a)
    {
        return a.Frames[a.FrameIndex];
    }
}

This was in my Form load. 这是在我的表单加载中。 Can really go anywhere that stuff is initialized. 真的可以到初始化任何东西的地方。

    private void Form1Load(object sender, EventArgs e)
    {

        _testAnim.AddFrame(@"F:\Im\Black.png");
        _testAnim.AddFrame(@"F:\Im\Blue.png");
        _testAnim.AddFrame(@"F:\Im\Green.png");
        _testAnim.AddFrame(@"F:\Im\Orange.png");
        _testAnim.AddFrame(@"F:\Im\Red.png");



        _testAnim.Target(ButtonTest);
        _testAnim.Target(PicBox);


        _testAnim.Play();


    }

On quick search I found this example . 在快速搜索中,我找到了这个示例 I'm not very experienced in c# graphics, but here are few points I have learned working with non-graphic oriented languages: 我对c#图形不是很有经验,但是在使用非图形语言时,我学到了以下几点:

  • Declare where/what you want to draw 声明要在哪里/要画什么
  • Create a loop to run until abort/event to end the loop (like object colliding with something) 创建一个循环,直到中止/事件结束循环为止(例如对象与某物碰撞)
  • In the loop: wait, clear the old drawing area, recalculate new position, draw in new position 在循环中:等待,清除旧绘图区域,重新计算新位置,绘制新位置
  • If needed you can change the image to draw too, but then you need separate images for each "frame" you want to have 如果需要,您也可以更改图像以进行绘制,但是对于每个要拥有的“框架”,您都需要单独的图像
  • multithreading is a good idea, so you can separate running the graphics from other game logic 多线程是一个好主意,因此您可以将运行图形与其他游戏逻辑分开
  • try keeping the time from clearing the drawing area and re-drawing as short as possible to prevent flickering 尽量避免清理绘图区域并尽可能缩短绘图时间,以防止闪烁
  • Keep track of the size of objects you draw, makes it easier to check for collision (like center of the sprite + radius, then you can easily calculate a circle area around it to check if two sprites are too close to each other) 跟踪绘制对象的大小,使其更容易检查碰撞(例如精灵的中心+半径,然后您可以轻松地计算围绕它的圆形区域以检查两个精灵是否彼此太近)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM