从0开发游戏引擎之游戏引擎中2D序列帧动画控制器的实现

简介: 需要的图片类似图1.1 会把所有的动作拼接到一张图上,这样做也是为了节省内存和减少DrawCall,切换动作的时候只需要重新计算图片的UV,然后把算出来的UV作为新区域贴在原来的那张纹理面片上即可。

这种序列帧动画要求每一帧的宽高必须一一致,否则动画播起来会出问题。


需要的图片类似图1.1 会把所有的动作拼接到一张图上,这样做也是为了节省内存和减少DrawCall,切换动作的时候只需要重新计算图片的UV,然后把算出来的UV作为新区域贴在原来的那张纹理面片上即可。

 

395331a801714fe892f7d7be1fad33db.jpg


Animate是Animation的一部分,一个Animation可以保存多个Animate,也可以理解成Animate只是一个动画片段,Animation是完整的动画控制器。这个结构其实有点像Unity的AnimateClip和Animator。


不多说,上代码,自己去看代码吧,实现不是很难,不多讲了。


程序1.1


Animate.h 完整代码


#pragma once
namespace U2D
{
  enum MovementEvent
  {
    START,
    COMPLETE,
  };
  class CAnimate :public CPicture
  {
    friend class CAnimation;
  private:
    char name[50];  //动画名
    UINT frameWidth;//每一帧的宽度
    UINT frameHeight;//每一帧的高度
    UINT rows;//总行数
    UINT cols;//总列数
    UINT startIndex;//开始的索引编号
    UINT endIndex;//结束的索引编号
    UINT curIndex;//当前的索引编号
    bool isPlaying;//是否播放
    bool isLoop;//是否循环
    UINT frameSpeed;//每一帧的速度
    UINT frameTimer;//每一帧的时间
    animate_selector listener_movementEvent; //动画事件监听
  public:
    CAnimate(char *fileName, UINT rows, UINT cols);
    CAnimate(CCTexture *tex, UINT rows, UINT cols);
    void setName(char *name) { strcpy(this->name, name); }
    char *getName() { return this->name; }
    void setFrameIndex(UINT startIndex, UINT endIndex)
    {
      this->startIndex = startIndex;
      this->endIndex = endIndex;
      curIndex = startIndex;
    }
    Vector2 getFrameSize() { return Vector2(frameWidth, frameHeight); }
    UINT getFrameCount() { return endIndex - startIndex + 1; }
    void play() { isPlaying = true; }
    void stop() { isPlaying = false; }
    void repeat(bool isLoop) { this->isLoop = isLoop; }
    void setDelayUnit(UINT frameSpeed) { this->frameSpeed = frameSpeed; }
    void setMovementEventCallFunc(animate_selector fun_movementEvent);//设置动画事件的回调函数
    void draw();
    void all_Anchor_0_0();
    void all_Anchor_05_05();
  public:
    CAnimate() {}
    ~CAnimate(void) {}
  };
}


程序1.2


Animate.cpp 完整代码


#include "Engine.h"
namespace U2D
{
  CAnimate::CAnimate(char *fileName, UINT rows, UINT cols)
    :CPicture(fileName)
  {
    strcmp(this->name, fileName);
    this->rows = rows;
    this->cols = cols;
    isPlaying = true;
    isLoop = true;
    frameSpeed = 10;
    frameWidth = pTexture->getWidth() / cols;
    frameHeight = pTexture->getHeight() / rows;
    startIndex = 0;
    endIndex = rows*cols - 1;
    curIndex = startIndex;
  }
  CAnimate::CAnimate(CCTexture *tex, UINT rows, UINT cols)
    :CPicture(tex)
  {
    strcmp(this->name, tex->getName());
    this->rows = rows;
    this->cols = cols;
    isPlaying = true;
    isLoop = true;
    frameSpeed = 10;
    frameWidth = tex->getWidth() / cols;
    frameHeight = tex->getHeight() / rows;
    startIndex = 0;
    endIndex = rows*cols - 1;
    curIndex = startIndex;
  }
  void CAnimate::setMovementEventCallFunc(animate_selector fun_movementEvent)
  {
    this->listener_movementEvent = fun_movementEvent;
  }
  void CAnimate::draw()
  {
    if (isPlaying)
    {
      if (frameTimer++%frameSpeed == 0)
      {
        if (curIndex == startIndex)
        {
          if (listener_movementEvent)
          {
            if (parent != NULL)
            {
              (parent->*listener_movementEvent)(this, MovementEvent::START);
            }
            else
              (parent->*listener_movementEvent)(this, MovementEvent::START);
          }
        }
        if (curIndex == endIndex + 1)
        {
          if (isLoop)
          {
            curIndex = startIndex;
          }
          else
          {
            isPlaying = false;
            curIndex = endIndex;
          }
          if (listener_movementEvent)
          {
            if (parent != NULL)
            {
              if (parent != NULL)
              {
                (parent->*listener_movementEvent)(this, MovementEvent::COMPLETE);
              }
              else
                (parent->*listener_movementEvent)(this, MovementEvent::COMPLETE);
            }
          }
        }
        (&srcRect,
          curIndex%cols*frameWidth,
          curIndex / cols*frameHeight,
          (curIndex%cols + 1)*frameWidth,
          (curIndex / cols + 1)*frameHeight);
        curIndex++;
      }
    }
    CPicture::draw();
  }
  void CAnimate::all_Anchor_0_0()
  {
  }
  void CAnimate::all_Anchor_05_05()
  {
  }
}


程序1.3


Animation.h 完整代码


#pragma once
namespace U2D {
  class CAnimation :public CElement
  {
    friend class CPlayer;
  protected:
    list<CAnimate*> animateList;          //动画的链表用名字判断,有就返回,没有就new一个
    CAnimate *animate;                //当前播放的动画
    animation_selector listener_movementEvent;    //动画集事件监听
    void animateEvent(CAnimate* animate, MovementEvent type);
    UINT rows;
    UINT cols;
    char*fileName;
  public:
    CAnimation();
    CAnimate* addAnimate(char *animName, char *fileName, UINT rows, UINT cols);
    CAnimate* addAnimate(char *animName, CCTexture *tex, UINT rows, UINT cols);
    CAnimate* findAnimate(char *animName);
    void setAnimate(char *animName);
    Vector2 getFrameSize() { return animate->getFrameSize(); }
    UINT getFrameCount() { return animate->getFrameCount(); }
    void play() { animate->play(); }
    void stop() { animate->stop(); }
    void repeat(bool isLoop) { animate->repeat(isLoop); }
    void setDelayUnit(UINT frameSpeed) { animate->setDelayUnit(frameSpeed); }
    void setFrameIndex(UINT startIndex, UINT endIndex) { return animate->setFrameIndex(startIndex, endIndex); }
    void setName_FrameIndex(char*name, UINT startIndex, UINT endIndex);
    void setMovementEventCallFunc(animation_selector fun_movementEvent);
    void draw();
    void setCurrentAllanchor(float ox, float oy);
    RECT getBoundBox();
    ~CAnimation();
  };
}


程序1.4


Animation.cpp 完整代码


#include "Engine.h"
namespace U2D
{
  CAnimation::CAnimation()
  {
    animate = NULL;
    listener_movementEvent = NULL;
  }
  CAnimate* CAnimation::addAnimate(char *animName, char *fileName, UINT rows, UINT cols)
  {
    CAnimate* anim = findAnimate(animName);//查找这个动画名字,如果找不到就会返回空
    if (anim != NULL)           //如果不为空就说明找到了
      return anim;
    this->rows = rows;
    this->cols = cols;
    this->fileName = fileName;
    anim = new CAnimate(fileName, rows, cols); //如果为空就new一个对象压进去。并且把名字设置好
    anim->setName(animName);          //设置动画名字
    anim->setParent(this);            //CAnimation是CNode的子类,子类拥有父类的所有数据,所以压入CAnimation就等同于压入了CNode。
    anim->setMovementEventCallFunc(animate_selector(&CAnimation::animateEvent));//回调函数
    animateList.push_back(anim);        //压进链表
    setAnimate(animName);           //设置动画
    return animateList.back();          //把刚压进去的对象返回出去
  }
  CAnimate* CAnimation::addAnimate(char *animName, CCTexture *tex, UINT rows, UINT cols)
  {
    CAnimate* anim = findAnimate(animName);
    if (anim != NULL)
      return anim;
    this->rows = rows;
    this->cols = cols;
    anim = new CAnimate(tex, rows, cols);
    anim->setName(animName);
    anim->setParent(this);
    anim->setMovementEventCallFunc(animate_selector(&CAnimation::animateEvent));
    animateList.push_back(anim);
    setAnimate(animName);
    return animateList.back();
  }
  CAnimate* CAnimation::findAnimate(char *animName)
  {
    list<CAnimate*>::iterator iter;
    for (iter = animateList.begin(); iter != animateList.end(); iter++)
    {
      if (strcmp((*iter)->name, animName) == 0)
      {
        return *iter;
      }
    }
    return NULL;
  }
  void CAnimation::setAnimate(char *animName)
  {
    animate = findAnimate(animName);
    animate->startIndex = animate->startIndex;//这个写的不对、明天去参考伟哥的写法
    //animate->curIndex = animate->startIndex;
    animate->isPlaying = true;
    animate->frameTimer = 0;
  }
  void CAnimation::setName_FrameIndex(char*name, UINT startIndex, UINT endIndex)
  {
    CAnimate* anim = findAnimate(name);
    anim = new CAnimate(fileName, rows, cols);        //如果为空就new一个对象压进去。并且把名字设置好
    anim->setName(name);                //设置动画名字
    anim->setParent(this);                //CAnimation是CNode的子类,子类拥有父类的所有数据,所以压入CAnimation就等同于压入了CNode。
    anim->setFrameIndex(startIndex, endIndex);
    anim->frameTimer = 0;
    animateList.push_back(anim);            //压进链表
    setAnimate(name);                 //设置动画
  }
  void CAnimation::draw()
  {
    Matrix3 scaleMatrix;
    Matrix3 rotateMatrix;
    Matrix3 transMatrix;
    //放缩图片
    Scale(scaleMatrix, scale.x, scale.y);
    //水平翻转
    if (flip == true)
      scaleMatrix._11 *= -1;
    //旋转图片
    Rotate(rotateMatrix, angle);
    // 平移图片到我们的指定位置
    Translate(transMatrix, pos.x, pos.y);
    local_matrix = scaleMatrix*rotateMatrix*transMatrix;
    if (parent == NULL)
    {
      world_color = local_color;
      world_matrix = local_matrix;
    }
    else
    {
      sColor col = parent->getWorldColor();
      world_color.r = local_color.r*col.r;
      world_color.g = local_color.g*col.g;
      world_color.b = local_color.b*col.b;
      world_color.a = local_color.a*col.a;
      world_matrix = local_matrix*parent->getWorldMatrix();
    }
    if (visible == false)
      return;
    animate->draw();
  }
  void CAnimation::setCurrentAllanchor(float ox, float oy)
  {
  }
  void CAnimation::setMovementEventCallFunc(animation_selector fun_movementEvent)
  {
    listener_movementEvent = fun_movementEvent;
  }
  void CAnimation::animateEvent(CAnimate* animate, MovementEvent type)
  {
    if (listener_movementEvent)
    {
      if (parent != NULL)
        (parent->*listener_movementEvent)(this, type, animate->name);
      else
        (this->*listener_movementEvent)(this, type, animate->name);
    }
  }
  RECT CAnimation::getBoundBox()
  {
    return animate->getBoundBox();
  }
  CAnimation::~CAnimation()
  {
  }
}


谢谢大家

相关文章
|
11月前
|
人工智能 算法 图形学
Unity 动画系统基本概念
Unity 动画系统基本概念
109 0
|
存储 传感器 C#
从零开始做一款Unity3D游戏<二>——移动,相机控制与碰撞(一)
从零开始做一款Unity3D游戏<二>——移动,相机控制与碰撞
从零开始做一款Unity3D游戏<二>——移动,相机控制与碰撞(一)
|
存储 安全 C#
从零开始做一款Unity3D游戏<二>——移动,相机控制与碰撞(二)
从零开始做一款Unity3D游戏<二>——移动,相机控制与碰撞
从零开始做一款Unity3D游戏<二>——移动,相机控制与碰撞(二)
|
负载均衡 安全 vr&ar
【Unity渲染】一文看懂!Unity通用渲染管线URP介绍
Unity 的渲染管线包含内置渲染管线、SRP、URP和HDRP。自从Unity2019.3开始,Unity将轻量级渲染管线修改为了通用渲染管线,这是一种快速、可扩展的渲染管线,支持所有的移动设备,适用于 2D、3D、虚拟现实 (VR) 和增强现实 (AR) 项目。
|
图形学
Unity Metaverse(二)、Mixamo & Animator 混合树与动画融合
Blend Tree混合树的使用与动画融合的实现
310 1
Unity Metaverse(二)、Mixamo & Animator 混合树与动画融合
从0开发游戏引擎之碰撞检测模块底层实现
从0开发游戏引擎之碰撞检测模块底层实现
|
vr&ar 图形学
【Unity3D 灵巧小知识点】☀️ | Unity 四元数、欧拉角 与 方向向量 之间转换
Unity 小科普 老规矩,先介绍一下 Unity 的科普小知识: Unity是 实时3D互动内容创作和运营平台 。 包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者,借助 Unity 将创意变成现实。
|
iOS开发 开发者
iOS开发CoreGraphics核心图形框架之四——变换函数
iOS开发CoreGraphics核心图形框架之四——变换函数
147 0
|
物联网 API
ThingJS:仅需不到5行代码,实现炫酷3D动画
在物联网领域,Thing都有哪些动效呢?