6.游戏引擎中2D基础组件的实现(Image;Label;Button)

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

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

4.引擎2D基类CUI类实现_天才小熊猫oo的博客-CSDN博客实现了引擎基础组件中的基类CUI类https://blog.csdn.net/qq_33531923/article/details/126716404

老样子先贴代码

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()
	{
	}

}

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

猜你喜欢

转载自blog.csdn.net/qq_33531923/article/details/126811541
今日推荐