SDL游戏之路(十一)--按钮制作



按钮制作

按钮我们定义三种状态, 1.按钮区域外,2.按钮区域内,3.按钮被点下

对三种状态可以分别显示不同的图片。


#ifndef SKBUTTON_H_
#define SKBUTTON_H_

#include "SkComm.h"
#include "SkImage.h"

#include <vector>
#include <string>
using namespace std;
namespace sk_park {

typedef enum _SkButtonStatus {
	SK_BUTTON_STATUS_OUT = 1,
	SK_BUTTON_STATUS_IN = 2,
	SK_BUTTON_STATUS_PRESSED = 3,
} SkButtonStatus;

class SkButton {
public:
	/**按钮的位置信息,只作为成员属性,按钮绘制的位置需要在绘制时候指定**/
	Sint32 m_iPosX;
	Sint32 m_iPosY;
	/**按钮是否显示**/
	bool m_bShow;
	/**按钮是否监听事件**/
	bool m_bListen;
	/**鼠标在按钮内的显示**/
	SkSurface m_effectIn;
	/**鼠标在按钮外的显示**/
	SkSurface m_effectOut;
	/**鼠标在按钮按下的显示**/
	SkSurface m_effectPressed;
	/**鼠标当前状态**/
	SkButtonStatus m_status;
	/**按钮标识**/
	int m_iId;
	string m_sName;
	/**按钮覆盖区域-多边形**/
	SkArea m_area;

	SkButton();
	~SkButton();
	void setShow(SkSurface & effectIn, SkSurface & effectOut,
			SkSurface & effectPressed);
	/**处理事件,iPosX+iPosY:按钮当前位置,pData:外传数据**/
	bool handleEvent(Sint32 iPosX, Sint32 iPosY, SkEvent & stEvent,
			void * pData);
	/**回调函数**/
	void setFuncPressed(void (*func_pressed)(void *, SkButton *));
	SkSurface * getShow(Sint64 iTime);
	void setPosition(Sint32 x, Sint32 y);

private:
	bool bPointIn(Sint32 iX, Sint32 iY);
	void (*m_func_pressed)(void *, SkButton * pButton);
};

}

extern sk_park::SkButton g_SkButton;

#endif /* SKBUTTON_H_ */


具体实现

#include "pch.h"

#include "SkButton.h"
using namespace sk_park;

SkButton::SkButton() {
	m_bShow = true;
	m_bListen = true;
	m_status = SK_BUTTON_STATUS_OUT;
	m_func_pressed = NULL;
	m_iId = 0;
}

SkButton::~SkButton() {

}
void SkButton::setFuncPressed(void (*func_pressed)(void *, SkButton *)) {
	m_func_pressed = func_pressed;
}
void SkButton::setShow(SkSurface & effectIn, SkSurface & effectOut,
		SkSurface & effectPressed) {
	m_effectIn = effectIn;
	m_effectOut = effectOut;
	m_effectPressed = effectPressed;
}
bool SkButton::bPointIn(int32_t iX, int32_t iY) {
	return m_area.bPointIn(iX, iY);
}
void SkButton::setPosition(Sint32 x, Sint32 y) {
	m_iPosX = x;
	m_iPosY = y;
}
bool SkButton::handleEvent(int32_t iPosX, int32_t iPosY, SkEvent & stEvent,
		void * pData) {
	//g_SkComm.log("[%s][%d]posx:%d posy:%d ex:%d ey:%d", __FILE__, __LINE__,
	//		iPosX, iPosY, stEvent.iX, stEvent.iY);
	if (!m_bListen) {
		return false;
	}

	bool bRet = false;
	if (stEvent.type.type == SDL_MOUSEMOTION) {
		int32_t iX = stEvent.iX - iPosX;
		int32_t iY = stEvent.iY - iPosY;
		if (m_status == SK_BUTTON_STATUS_IN
				|| m_status == SK_BUTTON_STATUS_OUT) {
			if (bPointIn(iX, iY)) {
				m_status = SK_BUTTON_STATUS_IN;
				bRet = true;
			} else {
				m_status = SK_BUTTON_STATUS_OUT;
			}
		} else if (m_status == SK_BUTTON_STATUS_PRESSED) {
			if (!bPointIn(iX, iY)) {
				m_status = SK_BUTTON_STATUS_OUT;
			}
		}

	} else if (stEvent.type.type == SDL_MOUSEBUTTONDOWN) {
		int32_t iX = stEvent.iX - iPosX;
		int32_t iY = stEvent.iY - iPosY;
		if (bPointIn(iX, iY)) {
			m_status = SK_BUTTON_STATUS_PRESSED;
			bRet = true;
		}
	} else if (stEvent.type.type == SDL_MOUSEBUTTONUP) {
		SkButtonStatus oldStatus = m_status;
		int32_t iX = stEvent.iX - iPosX;
		int32_t iY = stEvent.iY - iPosY;
		if (bPointIn(iX, iY)) {
			m_status = SK_BUTTON_STATUS_IN;
			bRet = true;
		} else {
			m_status = SK_BUTTON_STATUS_OUT;
		}
		if (oldStatus == SK_BUTTON_STATUS_PRESSED) {
			if (m_func_pressed != NULL) {
				m_func_pressed(pData, this);
				bRet = true;
			}
		}
	}
	return bRet;
}

SkSurface * SkButton::getShow(Sint64 iTime) {
	if (m_status == SK_BUTTON_STATUS_IN) {
		return &m_effectIn;
	} else if (m_status == SK_BUTTON_STATUS_PRESSED) {
		return &m_effectPressed;
	} else {
		return &m_effectOut;
	}
}

SkButton g_SkButton;


按钮的点击区域,设一个区域类来管理

class SkArea {
public:
	SkArea();
	~SkArea();
	void clear();
	/**判断点是否在面积内部**/
	bool bPointIn(float fX, float fY);
	/**多边型添加点**/
	void addPoint(float fX, float fY);
private:
	int m_iNum;
	float * m_pFX;
	float * m_pFY;
	/**禁止拷贝构造**/
	SkArea(SkArea & obj);
};

SkArea::SkArea() {
	m_iNum = 0;
	m_pFX = NULL;
	m_pFY = NULL;
}
SkArea::~SkArea() {
	if (m_pFX != NULL) {
		delete[] m_pFX;
		m_pFX = NULL;
	}
	if (m_pFY != NULL) {
		delete[] m_pFY;
		m_pFY = NULL;
	}
	m_iNum = 0;
}
void SkArea::clear() {
	if (m_pFX != NULL) {
		delete[] m_pFX;
		m_pFX = NULL;
	}
	if (m_pFY != NULL) {
		delete[] m_pFY;
		m_pFY = NULL;
	}
	m_iNum = 0;
}
bool SkArea::bPointIn(float fX, float fY) {
	int i, j;
	bool inside = false;
	double polygon_area = 0;
	double trigon_area = 0;

	for (i = 0, j = m_iNum - 1; i < m_iNum; j = i++) {
		polygon_area += m_pFX[i] * m_pFY[j] - m_pFX[j] * m_pFY[i];
		trigon_area += abs(
				fX * m_pFY[i] - fX * m_pFY[j] - m_pFX[i] * fY
						+ m_pFX[i] * m_pFY[j] + m_pFX[j] * fY
						- m_pFX[j] * m_pFY[i]);
	}

	trigon_area *= 0.5;
	polygon_area = abs(polygon_area * 0.5);
	if (fabs(trigon_area - polygon_area) < 1e-7)
		inside = true;
	return inside;
}
void SkArea::addPoint(float fX, float fY) {
	float * pFx = new float[m_iNum + 1];
	float * pFy = new float[m_iNum + 1];
	for (int i = 0; i < m_iNum; i++) {
		pFx[i] = m_pFX[i];
		pFy[i] = m_pFY[i];
	}
	pFx[m_iNum] = fX;
	pFy[m_iNum] = fY;
	if (m_pFX != NULL) {
		delete[] m_pFX;
		m_pFX = NULL;
	}
	if (m_pFY != NULL) {
		delete[] m_pFY;
		m_pFY = NULL;
	}
	m_pFX = pFx;
	m_pFY = pFy;
	m_iNum++;
}


使用示例:

SkImage pic_ch_1;
	SkImage pic_ch_2;

	pic_ch_1.load("pic/ch1.png");
	pic_ch_2.load("pic/ch2.png");
	m_testButton.setShow(pic_ch_1.m_skSurface, pic_ch_1.m_skSurface,
			pic_ch_2.m_skSurface);
	m_testButton.m_area.addPoint(0, 0);
	m_testButton.m_area.addPoint(0, pic_ch_1.m_iHeight);
	m_testButton.m_area.addPoint(pic_ch_1.m_iWidth, pic_ch_1.m_iHeight);
	m_testButton.m_area.addPoint(pic_ch_1.m_iWidth, 0);
	m_testButton.setPosition(400, 400);


此时按钮显示已经做完了,我们需要在屏幕的点击和移动事件中,调用事件处理函数。

void ViewFirst::doEvent(SkEvent & stSkEvent, Sint64 iCurMTime) {
	bool bRet = m_testButton.handleEvent(m_testButton.m_iPosX,
			m_testButton.m_iPosY, stSkEvent, NULL);
	if (bRet) {
		return;
	}
}


效果如下:


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值