SFML自定义按钮控件
我们在开发游戏的过程中常常会涉及到按钮的设置,但是SFML不能像游戏引擎一样提供按钮控件,为了方便游戏开发,我们自定义一个按钮类,通过实例化这个类来方便地获得一个按钮。
定义按钮类
Button.h
#pragma once
class Button
{
//将需要用到Button的类定义为友员类,给app赋值
friend class StartScene;
friend class GameScene;
friend class Menu;
public:
Button():app(NULL),isActive(false),PreBehRel(false) {};
bool isActive;//按钮是否活跃状态,这个后面会解释
bool PreBehRel;//松开之前是否按下,这个后面会解释
void setTextrue(String s);//设置贴图路径
void setPosition(int x, int y);//位置
void setScale(float x, float y);//大小
void show();//显示按钮
bool onClick(Event& e);//按钮响应
Sprite s;//精灵
private:
Texture t;//贴图
RenderWindow* app;//在app窗口中显示按钮
};
类中方法的实现
Button.cpp
#include "Button.h"
void Button::setTextrue(String s)
{
this->t.loadFromFile(s);
this->s.setTexture(this->t);
}
void Button::setPosition(int x, int y)
{
this->s.setPosition(x, y);
}
void Button::setScale(float x, float y)
{
this->s.setScale(x, y);
}
bool Button::onClick(Event& e)
{
if (!isActive) //如果按钮不是活跃状态(不显示),不响应
return false;
bool flag = false;
FloatRect box = s.getGlobalBounds();//获取按钮的有效点击范围
if (Mouse::getPosition(*app).x >= box.left && Mouse::getPosition(*app).x <= (box.left + box.width) && Mouse::getPosition(*app).y >= box.top && Mouse::getPosition(*app).y <= (box.top + box.height))
{
if (e.type == Event::MouseButtonReleased && e.key.code == Mouse::Left && PreBehRel)
{
this->PreBehRel = false;//要先按下再松开才返回true,置于为什么要判断先按下,后面会讲
flag = true;
}
else
flag = false;
if (e.type == Event::MouseButtonPressed && e.key.code == Mouse::Left)
{
this->s.setColor(Color(125, 125, 0, 255));//按钮按下时的颜色和不透明度
this->PreBehRel = true;
}
else
this->s.setColor(Color(125, 125, 0, 100));//鼠标指着按钮但未按下时的颜色和不透明度
}
else
this->s.setColor(Color(255,255,255, 255));//默认状态的按钮颜色
return flag;
}
void Button::show()
{
isActive = true;//若要显示,则为活跃状态
(*app).draw(s);
}
部分变量的说明
(1)bool isActive:在由于我在判断鼠标是否在按钮里面是用的getGlobalBounds()方法,不管按钮是否被draw,只要设置了贴图精灵,都能获取按钮的响应范围,这就会导致按钮没有显示的情况下我在设置按钮的位置按下也会触发按钮点击事件,这就不合理,所以设置isActive布尔变量来记录按钮是否活跃(被绘制),所以在调用Button的程序里要把isActive重置为false,在绘制按钮时再设为true。
(2)bool PreBehRel:这个是为了防止场景切换时在同一位置两个场景都有按钮的情况下两个按钮的点击都被触发,本来按照sfml的MouseButtonReleased应该是鼠标松开后返回true,也就是说鼠标点击一下只会返回一次Release,但是在实现中发现如果一个按钮被点击后就在同一位置绘制另一个按钮,这回导致两个按钮的MouseButtonReleased都被返回为true,置于为什么会这样我也不知道,所以设置PreBehRel布尔变量来判断鼠标松开前是否被按下,从而避免了这一问题。另外也是防止鼠标在按钮外面按下不放然后移到按钮里面再松开导致触发按钮事件。
如何使用Button
举例代码如下
RenderWindow app;
Button bt;
bt.app=&app;
while(app.isOpen())
{
Event e;
while(app.pollEvent(e))
{
if(e.type==Event::Closed())
app.close();
}
bt.isActive=false;
bt.show();
if(bt.onClick(e))
{
cout<<"clicked!";
}
}