从0开发游戏引擎之2D基础组件的实现(Image;Label;Button)

简介: 从0开发游戏引擎之2D基础组件的实现(Image;Label;Button)

UI_Image、UI_Label、Button、UI_Manage、是继承了我们之前写的CUI类,因为写的比较简单,所以就放在同一章去讲了


CUI的具体实现可以看第四篇文章

老样子先贴代码


Label.h


#pragma once
typedef char *  va_list;
#define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap)      ( ap = (va_list)0 )
namespace U2D
{
  class CUI_Label :public CUI
  {
  private:
    GLuint _base;
    UINT m_fontSize;
    string m_string;
  public:
    CUI_Label(const char *string, const char *fontName, float fontSize);
    void setString(char* string, ...);
    void drawCNString(const char *str);
    void draw();
    CUI_Label();
    ~CUI_Label();
  };
}


Label.cpp


#include "Engine.h"
namespace U2D
{
  CUI_Label::CUI_Label()
  {
  }
  CUI_Label::CUI_Label(const char *string, const char *fontName, float fontSize)
  {
    HDC hdc = CPlateForm::getInstance()->getHdc();
    HFONT font;
    font = CreateFont(-fontSize, 0, 0, 0, FW_BOLD, false, false, false, ANSI_CHARSET, OUT_TT_ONLY_PRECIS,
      CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FF_DONTCARE | DEFAULT_PITCH, CUser::getInstance()->CharToWchar(fontName));
    _base = glGenLists(96);
    HFONT oldfont = (HFONT)SelectObject(hdc, font);
    wglUseFontBitmaps(hdc, 32, 96, _base);
    SelectObject(hdc, oldfont);
    DeleteObject(font);
    m_fontSize = fontSize;
    m_string = string;
  }
  void CUI_Label::draw()
  {
    int len, i;
    wchar_t* wstring;
    HDC hDC = CPlateForm::getInstance()->getHdc();; //获取显示设备
    if (visible == false)
      return;
    //计算从局部到全局的转换矩阵
    Matrix3 scaleMatrix;
    Matrix3 rotateMatrix;
    Matrix3 transMatrix;
    scaleMatrix.Scale(scale.x, scale.y);//放缩
    if (flip == true)         //水平翻转
      scaleMatrix._11 *= -1;
    rotateMatrix.Rotate(angle);     //旋转
    transMatrix.Translate(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();
    }
    glPushMatrix();
    glPushAttrib(GL_LIST_BIT);
    glRasterPos2f(pos.x, pos.y + m_fontSize);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glColor4fv(world_color.color);
    len = 0;
    for (i = 0; m_string[i] != '\0'; ++i) //计算字符的个数
    {
      if (IsDBCSLeadByte(m_string[i]))  //如果是双字节字符的(比如中文字符),两个字节才算一个字符
        ++i;              //否则一个字节算一个字符
      ++len;
    }
    wstring = (wchar_t*)malloc((len + 1) * sizeof(wchar_t));//将混合字符转化为宽字符
    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, m_string.c_str(), -1, wstring, len);
    wstring[len] = L' ';// 只是转义符,它本身的类型是wchar_t
    for (i = 0; i < len; ++i)  // 逐个输出字符
    {
      wglUseFontBitmapsW(hDC, wstring[i], 1, _base);
      glCallList(_base);
    }
    //glListBase(_base - 32);
    //glCallLists(m_string.length(), GL_UNSIGNED_BYTE, m_string.c_str());
    glDisable(GL_BLEND);
    glDisable(GL_TEXTURE_2D);
    glPopAttrib();
    glPopMatrix();
    free(wstring);// 回收所有临时资源
    glDeleteLists(_base, 1);
  }
  void CUI_Label::setString(char* string, ...)
  {
    char temp[255];
    m_string = "";
    va_list ap;
    va_start(ap, string);
    while (0 != *string)
    {
      if ('%' != *string)
      {
        m_string += *string;
      }
      else
      {
        switch (*++string)
        {
        case 'd':
        {
          int val = va_arg(ap, int);
          _itoa(val, temp, 10);
          m_string += temp;
        }
        break;
        case 'c':
        {
          char val = va_arg(ap, char);
          m_string += val;
        }
        break;
        case 's':
        {
          char *str = va_arg(ap, char*);
          m_string += str;
        }
        break;
        case 'f':
        case '.':
        {
          double val = va_arg(ap, double);
          char fmt[10];
          char *lp = fmt;
          *lp++ = '%';
          while (*string != 'f')
          {
            *lp++ = *string++;
          }
          *lp++ = 'f';
          *lp = 0;
          sprintf(temp, fmt, val);
          m_string += temp;
        }
        break;
        case 'x':
        {
          int val = va_arg(ap, int);
          _itoa(val, temp, 16);
          m_string += temp;
        }
        break;
        default:
          break;
        }
      }
      string++;
    }
    va_end(ap);
  }
  void CUI_Label::drawCNString(const char* str)
  {
    int len, i;
    wchar_t* wstring;
    HDC hDC = CPlateForm::getInstance()->getHdc();; //获取显示设备
    GLuint list = glGenLists(1); //申请1个显示列表
                   //计算字符的个数
                   //如果是双字节字符的(比如中文字符),两个字节才算一个字符
                   //否则一个字节算一个字符
    len = 0;
    for (i = 0; str[i] != '\0'; ++i)
    {
      if (IsDBCSLeadByte(str[i]))
        ++i;
      ++len;
    }
    wstring = (wchar_t*)malloc((len + 1) * sizeof(wchar_t));// 将混合字符转化为宽字符
    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, wstring, len);
    wstring[len] = L' ';// 只是转义符,它本身的类型是wchar_t
    for (i = 0; i < len; ++i)  // 逐个输出字符
    {
      wglUseFontBitmapsW(hDC, wstring[i], 1, list);
      glCallList(list);
    }
    free(wstring);// 回收所有临时资源
    glDeleteLists(list, 1);
  }
  CUI_Label::~CUI_Label()
  {
    glDeleteLists(_base, 96);
  }
}


Image.h


#pragma once
namespace U2D {
  class CUI_Image :public CUI
  {
  protected:
    CCTexture *texture;
  public:
    CUI_Image(char *imageName);
    void draw();
    void drawDebug() {};
    CUI_Image();
    ~CUI_Image();
  };
}


Image.cpp


#include "Engine.h"
namespace U2D
{ 
  CUI_Image::CUI_Image()
  {
  }
  CUI_Image::CUI_Image(char *imageName)
  {
    texture = CTextureManager::getInstance()->addTexture(imageName);
    int wid = texture->getWidth();
    int hei = texture->getHeight();
    cornerPoint[0] = Vector2(-wid*anchor.x, -hei*anchor.y);
    cornerPoint[1] = Vector2(-wid*anchor.x, hei*(1 - anchor.y));
    cornerPoint[2] = Vector2(wid*(1 - anchor.x), hei*(1 - anchor.y));
    cornerPoint[3] = Vector2(wid*(1 - anchor.x), -hei*anchor.y);
  }
  void CUI_Image::draw()
  {
    if (visible == false)
      return;
    //计算从局部到全局的转换矩阵
    Matrix3 scaleMatrix;
    Matrix3 rotateMatrix;
    Matrix3 transMatrix;
    //放缩
    scaleMatrix.Scale(scale.x, scale.y);
    //水平翻转
    if (flip == true)
      scaleMatrix._11 *= -1;
    //旋转
    rotateMatrix.Rotate(angle);
    //平移
    transMatrix.Translate(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();
    }
    glPushMatrix();
    glLoadMatrixf(world_matrix.mat);
    glEnable(GL_BLEND);
    glEnable(GL_TEXTURE_2D);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glBindTexture(GL_TEXTURE_2D, texture->getTextureID());
    glColor4fv(world_color.color);
    glBegin(GL_TRIANGLE_STRIP);
    int wid = texture->getWidth();
    int hei = texture->getHeight();
    glTexCoord2f(0, 1);   glVertex2f(-wid*anchor.x, -hei*anchor.y);
    glTexCoord2f(0, 0);   glVertex2f(-wid*anchor.x, hei*(1 - anchor.y));
    glTexCoord2f(1, 1);   glVertex2f(wid*(1 - anchor.x), -hei*anchor.y);
    glTexCoord2f(1, 0);   glVertex2f(wid*(1 - anchor.x), hei*(1 - anchor.y));
    glEnd();
    glDisable(GL_BLEND);
    glDisable(GL_TEXTURE_2D);
    glPopMatrix();
  }
  CUI_Image::~CUI_Image()
  {
  }
}


Button.h


#pragma once
namespace U2D
{
  class Button :public CUI
  {
    bool m_bPressed;//鼠标按着
    bool m_bMouseIn;//鼠标在范围里
    GLPolygon goly;//按钮的形状
    CCTexture *normalTexture;//一般(没有按)状态下的图片
    CCTexture *mouseInTexture;//进入按钮的范围
    CCTexture *pressTexture;//按着按钮
    CCTexture *currentTexture;//当前状态
  public:
    Button();
    Button(Vector2 point[4]);
    Button(char *normalImage);
    Button(char *normalImage, char *pressImage);
    Button(char *normalImage, char *mouseInImage, char *pressImage);
    void draw();
    bool MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    ~Button();
  };
}


Button.cpp


#include "Engine.h"
namespace U2D
{
  Button::Button()
  {
  }
  Button::Button(Vector2 point[4])
  {
    m_bPressed = false;
    m_bMouseIn = false;
    normalTexture = NULL;
    mouseInTexture = NULL;
    pressTexture = NULL;
    for (int i = 0; i < 4; i++)
    {
      cornerPoint[i] = point[i];
    }
  }
  Button::Button(char *normalImage)
  {
    m_bPressed = false;
    m_bMouseIn = false;
    normalTexture = CTextureManager::getInstance()->addTexture(normalImage);
    int wid = normalTexture->getWidth();
    int hei = normalTexture->getHeight();
    cornerPoint[0] = Vector2(-wid*anchor.x, -hei*anchor.y);
    cornerPoint[1] = Vector2(-wid*anchor.x, hei*(1 - anchor.y));
    cornerPoint[2] = Vector2(wid*(1 - anchor.x), hei*(1 - anchor.y));
    cornerPoint[3] = Vector2(wid*(1 - anchor.x), -hei*anchor.y);
    mouseInTexture = normalTexture;
    pressTexture = mouseInTexture;
  }
  Button::Button(char *normalImage, char *pressImage)
  {
    m_bPressed = false;
    m_bMouseIn = false;
    normalTexture = CTextureManager::getInstance()->addTexture(normalImage);
    int wid = normalTexture->getWidth();
    int hei = normalTexture->getHeight();
    cornerPoint[0] = Vector2(-wid*anchor.x, -hei*anchor.y);
    cornerPoint[1] = Vector2(-wid*anchor.x, hei*(1 - anchor.y));
    cornerPoint[2] = Vector2(wid*(1 - anchor.x), hei*(1 - anchor.y));
    cornerPoint[3] = Vector2(wid*(1 - anchor.x), -hei*anchor.y);
    mouseInTexture = normalTexture;
    pressTexture = CTextureManager::getInstance()->addTexture(pressImage);
  }
  Button::Button(char *normalImage, char *mouseInImage, char *pressImage)
  {
    m_bPressed = false;
    m_bMouseIn = false;
    normalTexture = CTextureManager::getInstance()->addTexture(normalImage);
    int wid = normalTexture->getWidth();
    int hei = normalTexture->getHeight();
    cornerPoint[0] = Vector2(-wid*anchor.x, -hei*anchor.y);
    cornerPoint[1] = Vector2(-wid*anchor.x, hei*(1 - anchor.y));
    cornerPoint[2] = Vector2(wid*(1 - anchor.x), hei*(1 - anchor.y));
    cornerPoint[3] = Vector2(wid*(1 - anchor.x), -hei*anchor.y);
    mouseInTexture = CTextureManager::getInstance()->addTexture(mouseInImage);
    pressTexture = CTextureManager::getInstance()->addTexture(pressImage);
  }
  void Button::draw()
  {
    Gizmo::drawGLPolygon(goly, sColor(1, 0, 0, 1));
    if (visible == false)
      return;
    //计算从局部到全局的转换矩阵
    Matrix3 scaleMatrix;
    Matrix3 rotateMatrix;
    Matrix3 transMatrix;
    //放缩
    scaleMatrix.Scale(scale.x, scale.y);
    //水平翻转
    if (flip == true)
      scaleMatrix._11 *= -1;
    //旋转
    rotateMatrix.Rotate(angle);
    //平移
    transMatrix.Translate(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 (m_bPressed)
    {
      currentTexture = pressTexture;
    }
    else if (m_bMouseIn)
    {
      currentTexture = mouseInTexture;
    }
    else
    {
      currentTexture = normalTexture;
    }
    glPushMatrix();
    glLoadMatrixf(world_matrix.mat);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glBindTexture(GL_TEXTURE_2D, currentTexture->getTextureID());
    glColor4fv(world_color.color);
    glBegin(GL_TRIANGLE_STRIP);
    int wid = currentTexture->getWidth();
    int hei = currentTexture->getHeight();
    cornerPoint[0] = Vector2(-wid*anchor.x, -hei*anchor.y);
    cornerPoint[1] = Vector2(-wid*anchor.x, hei*(1 - anchor.y));
    cornerPoint[2] = Vector2(wid*(1 - anchor.x), hei*(1 - anchor.y));
    cornerPoint[3] = Vector2(wid*(1 - anchor.x), -hei*anchor.y);
    Vector2 ver[4];
    for (int i = 0; i < 4; i++)
    {
      Vec2TransformCoord(ver[i], cornerPoint[i], world_matrix);
    }
    goly.Set(ver, 4);
    glTexCoord2f(0, 1);   glVertex2f(-wid*anchor.x, -hei*anchor.y);
    glTexCoord2f(0, 0);   glVertex2f(-wid*anchor.x, hei*(1 - anchor.y));
    glTexCoord2f(1, 1);   glVertex2f(wid*(1 - anchor.x), -hei*anchor.y);
    glTexCoord2f(1, 0);   glVertex2f(wid*(1 - anchor.x), hei*(1 - anchor.y));
    glEnd();
    glDisable(GL_BLEND);
    glDisable(GL_TEXTURE_2D);
    glPopMatrix();
  }
  bool Button::MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  {
    if (visible == false)
      return false;
    switch (uMsg)
    {
    case WM_LBUTTONDOWN:
    {
      Vector2 mousePos = Vector2(LOWORD(lParam), HIWORD(lParam));
      if (Collider::Intersects(mousePos, goly))
      {
        m_bPressed = true;
        //鼠标移动出客户区,你也可以接受到鼠标消息
        SetCapture(hWnd);
        return true;
      }
    }
    break;
    case WM_MOUSEMOVE:
    {
      Vector2 mousePos = Vector2(LOWORD(lParam), HIWORD(lParam));
      if (Collider::Intersects(mousePos, goly))
      {
        if (m_bPressed == false)
          m_bMouseIn = true;
        return true;
      }
      else
      {
        m_bPressed = false;
        m_bMouseIn = false;
        //必须与SetCapture配对
        ReleaseCapture();
      }
    }
    break;
    case WM_LBUTTONUP:
    {
      Vector2 mousePos = Vector2(LOWORD(lParam), HIWORD(lParam));
      if (m_bPressed == true)
      {
        m_bPressed = false;
        //必须与SetCapture配对
        ReleaseCapture();
        if (Collider::Intersects(mousePos, goly))
        {
          // 鼠标弹起时发送消息
          sendEvent(Event::MOUSE_UP);
          return true;
        }
      }
    }
    break;
    }
    return false;
  }
  Button::~Button()
  {
  }
}


UI_Manager.h


#pragma once
namespace U2D
{
  class CUI_Manage
  {
    class ZOrder_Op
    {
    public:
      bool operator()(CUI*a, CUI*b);
    };
  protected:
    //friend class CPlateForm;
    list<CUI*> uiList;//UI的链表
    static CUI_Manage*instance;
  public:
    static CUI_Manage*getInstance();
    void _draw();
    void MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    void addUI(CUI* ui, int z = 0);
    void addUI(char *name, CUI*ui, int z = 0);
    CUI *findUI(char *name);
    CUI_Manage();
    virtual ~CUI_Manage();
  };
}


UI_Manage.cpp


#include "Engine.h"
namespace U2D
{
  CUI_Manage*CUI_Manage::instance = NULL;
  bool CUI_Manage::ZOrder_Op::operator()(CUI*a, CUI*b)
  {
    if (a->zOrder < b->zOrder)
      return true;
    return false;
  }
  CUI_Manage*CUI_Manage::getInstance()
  {
    if (instance == NULL)
    {
      instance = new CUI_Manage;
    }
    return instance;
  }
  CUI_Manage::CUI_Manage()
  {
  }
  void CUI_Manage::_draw()
  {
    uiList.sort(ZOrder_Op());
    for (auto iter = uiList.begin(); iter != uiList.end(); iter++)
    {
      (*iter)->draw();
    }
  }
  void CUI_Manage::MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  {
    //用逆迭代器的目的:后面的最后画。所以最后画出来是在最上面,如果点击了最上面的按钮就跳出,这样就不会消息穿透到下面的按钮!
    list<CUI*>::reverse_iterator rev_iter;//iterator
    for (rev_iter = uiList.rbegin(); rev_iter != uiList.rend(); rev_iter++)
    {
      if ((*rev_iter)->MsgProc(hWnd, uMsg, wParam, lParam))
        break;
    }
  }
  void CUI_Manage::addUI(CUI* ui, int z)
  {
    //CUI*temp = findUI(ui->name);
    //if (temp != NULL)
    //  return;
    ui->setZorder(z);
    ui->setParent((CNode*)(CScene*)this);
    uiList.push_back(ui);
  }
  void CUI_Manage::addUI(char *name, CUI*ui, int z)
  {
    ui->setName(name);
    addUI(ui, z);
  }
  CUI* CUI_Manage::findUI(char *name)
  {
    for (auto iter = uiList.begin(); iter != uiList.end(); iter++)
    {
      if (strcmp((*iter)->name, name) == 0)
      {
        return (*iter);
      }
    }
    return NULL;
  }
  CUI_Manage::~CUI_Manage()
  {
  }
}


先把代码贴出来,等有时间再回过头来重点讲解。

相关文章
|
7月前
|
前端开发
UniApp 中的 image 属性讲解
UniApp 中的 image 属性讲解
886 2
|
7月前
|
小程序
【微信小程序】-- 其它常用组件介绍 -- button & image(八)
【微信小程序】-- 其它常用组件介绍 -- button & image(八)
|
7月前
【鸿蒙4.0】ArkUI组件-Image
【鸿蒙4.0】ArkUI组件-Image应用及需要注意的问题
422 3
|
3月前
|
小程序 容器
微信小程序常用组件的简单使用 view,scroll-view,swiper,swiper-item,text,rich-text,button,image
本文介绍了微信小程序中常用组件的使用方法,包括view、scroll-view、swiper与swiper-item、text与rich-text、button以及image组件。详细解释了各组件的功能、属性以及如何在小程序页面中进行使用。
微信小程序常用组件的简单使用 view,scroll-view,swiper,swiper-item,text,rich-text,button,image
|
2月前
|
小程序 前端开发 JavaScript
小程序入门之认识view和text组件
小程序入门之认识view和text组件
89 0
|
7月前
|
小程序 前端开发
【微信小程序】-- 常用的基础内容组件介绍 -- text & rich-text & progress & icon(七)
【微信小程序】-- 常用的基础内容组件介绍 -- text & rich-text & progress & icon(七)
|
5月前
|
开发者
小而美的IKUN-UI组件库源码学习(按钮 Button)
小而美的IKUN-UI组件库源码学习(按钮 Button)
35 0
|
7月前
|
API
【鸿蒙软件开发】ArkTS基础组件之DataPanel(数据面板)、DatePicker(日期选择)
【鸿蒙软件开发】ArkTS基础组件之DataPanel(数据面板)、DatePicker(日期选择)
274 0
|
7月前
HBuilderX使用uniapp中的video标签开发视频应用APP,出现视频覆盖<view>图层无法遮住等问题如何解决?
HBuilderX使用uniapp中的video标签开发视频应用APP,出现视频覆盖<view>图层无法遮住等问题如何解决?
|
前端开发 开发者
stencilJs学习之构建 Drawer 组件
在之前的文字了我们一起学习了StencilJs的基础知识,现在我们就一起来实现一个组件吧!
72 0