功能实现
- 卡牌交互音效
- 卡牌拖拽
卡牌交互音效
在之前我们已经定义过SoundBuffer对象以及Sound对象,接下来对其进行绑定
void Game::loadMediaData() {
//加载音频
victorSb.loadFromFile("data/sound/victor.ogg");
defeatSb.loadFromFile("data/sound/defeat.ogg");
attackSb.loadFromFile("data/sound/attack.ogg");
hoverSb.loadFromFile("data/sound/hover.ogg");
pressSb.loadFromFile("data/sound/press.ogg");
releaseSb.loadFromFile("data/sound/release.ogg");
victorSd.setBuffer(victorSb);
defeatSd.setBuffer(defeatSb);
attackSd.setBuffer(attackSb);
hoverSd.setBuffer(hoverSb);
pressSd.setBuffer(pressSb);
releaseSd.setBuffer(releaseSb);
}
然后我们再Button类中添加多个属性,方便我们对音效进行管理
因为我们是多张卡牌操作同一个音效
而且我们的卡牌有三种音效,其中释放时的音效是一定会播放的,所以不用管理
悬浮或按下的音效都是在“鼠标在卡牌上”的前提下,需要用bool变量来判断可否播放
class Button :public Sprite { //继承SFML的Sprite类
public:
bool hoverSd; //是否播放音效 悬浮时的音效
bool pressSd; //按下时的音效
};
然后在战斗场景的交互函数中
void Game::fightInput(Vector2i mousePosition, Event event) {
for (int i = 0; i < humanPlayer.handCardNums; i++) {
if (humanPlayer.handCards[i]->cardState != humanPlayer.handCards[i]->null) {
switch (humanPlayer.handCards[i]->checkMouse(mousePosition, event)) { //卡片事件
case 0:
humanPlayer.handCards[i]->hoverSd = true; //如果卡片为普通状态 比如 鼠标移到卡牌外 原地释放卡牌
humanPlayer.handCards[i]->pressSd = true;
if (humanPlayer.handCards[i]->mouseContain(mousePosition)) { //如果鼠标在卡牌上
} else if (mousePosition.x > (300 + (humanPlayer.handCardNums - 1) * 150 + 200) || mousePosition.x < 300 || mousePosition.y>800 || mousePosition.y < 500) { //鼠标在手牌区外
pressSd.stop(); //按下时的音效
hoverSd.stop(); //悬浮时的音效
}
break;
case 1:
pressSd.stop();
if (humanPlayer.handCards[i]->hoverSd) { //如果悬浮音效可播放
hoverSd.play(); //播放悬浮音效
humanPlayer.handCards[i]->hoverSd = false; //不可播放悬浮音效
}
break;
case 2:
hoverSd.stop();
if (humanPlayer.handCards[i]->pressSd) {
pressSd.play();
humanPlayer.handCards[i]->pressSd = false;
}
break;
case 3:
pressSd.stop();
releaseSd.play();
humanPlayer.handCards[i]->hoverSd = true; //释放卡牌,音效可播放
humanPlayer.handCards[i]->pressSd = true;
break;
default:
break;
}
}
}
}
但是我们发现,当鼠标移到上面卡牌和下面卡牌重叠的部分时,两张卡牌都会交互,所以我们重载按钮类的鼠标检测函数,只需要为其设定两个偏移量即可
button.h
bool mouseContain(Vector2i, int, int); //检测鼠标是否在精灵内
int checkMouse(Vector2i, Event, int, int); //检查鼠标状态
button.cpp
bool Button::mouseContain(Vector2i mouse, int xOffset, int yOffset) {
return (mouse.x > getPosition().x && mouse.x < getPosition().x + getTexture()->getSize().x - xOffset) &&(mouse.y > getPosition().y && mouse.y < getPosition().y + getTexture()->getSize().y - yOffset) ? true : false;
}
int Button::checkMouse(Vector2i mouse, Event event, int xOffset, int yOffset) {
//判断鼠标是不是在按钮内,前提是放正的矩形,一般情况下都是这样,如果是奇形怪状的需要再写别的方法
if (mouseContain(mouse, xOffset, yOffset)) {
////
}
}
最后稍微修改下之前的交互函数
for (int i = 0; i < humanPlayer.handCardNums; i++) {
if (humanPlayer.handCards[i]->cardState != humanPlayer.handCards[i]->null) {
if (i != humanPlayer.handCardNums - 1) { //如果不是最后一张手牌(在最上面)
cardOffset.x = 50;
cardOffset.y = 0;
} else {
cardOffset.x = 0;
cardOffset.y = 0;
}
switch (humanPlayer.handCards[i]->checkMouse(mousePosition, event, cardOffset.x, cardOffset.y)) {
//卡片事件
////
}
}
}
看一下现在的效果
卡牌拖拽
基本原理就是在卡牌按下前记录鼠标的初始位置以及卡牌初始位置,然后每帧判断鼠标初始与现在位置的坐标差(偏移量),在给卡牌设置初始位置加上偏移量即可
在Player.h中设定一个属性
int cardSelect; //与哪个卡牌正在交互
Card.h中定义一些属性
void move(Vector2i); //卡牌移动
Vector2f originPosition; //初始位置
Vector2i originMouse; //初始鼠标位置
卡牌移动
void Card::move(Vector2i mouse) {
setPosition(originPosition.x + mouse.x - originMouse.x, originPosition.y + mouse.y - originMouse.y);
}
Game.cpp中
卡牌绘制
void Game::drawCard() {
for (int i = 0; i < humanPlayer.handCardNums; i++) {
if (humanPlayer.handCards[i]->btnState == humanPlayer.handCards[i]->CLICK) { //如果为按下的状态
humanPlayer.handCards[i]->move(Mouse::getPosition(window)); //卡牌移动事件
} else {
humanPlayer.handCards[i]->setPosition(300 + i * 150, 500); //默认位置
humanPlayer.handCards[i]->originPosition = humanPlayer.handCards[i]->getPosition(); //设置默认位置
humanPlayer.handCards[i]->originMouse = Mouse::getPosition(window); //设定按下鼠标前鼠标的位置
}
window.draw(*humanPlayer.handCards[i]);
}
window.display(); //展示屏幕
}
优化一下战斗场景的交互
void Game::fightInput(Vector2i mousePosition, Event event) {
for (int i = 0; i < humanPlayer.handCardNums; i++) {
if (humanPlayer.handCards[i]->cardState != humanPlayer.handCards[i]->null) {
if (humanPlayer.handCards[i]->mouseContain(mousePosition, cardOffset.x, cardOffset.y)) {
humanPlayer.cardSelect = i; //与第i张卡牌进行交互
}
switch (humanPlayer.handCards[i]->checkMouse(mousePosition, event, cardOffset.x, cardOffset.y)) { //卡片事件
case 0:
humanPlayer.handCards[i]->hoverSd = true; //如果卡片为普通状态 比如 鼠标移到卡牌外 原地释放卡牌
humanPlayer.handCards[i]->pressSd = true;
if (humanPlayer.cardSelect != -1) { //如果鼠标在与卡牌进行交互
} else if (mousePosition.x > (300 + (humanPlayer.handCardNums - 1) * 150 + 200) || mousePosition.x < 300 || mousePosition.y>800 || mousePosition.y < 500) { //鼠标在手牌区外
pressSd.stop(); //按下时的音效
hoverSd.stop(); //悬浮时的音效
}
break;
case 1:
//
case 2:
//
case 3:
pressSd.stop();
releaseSd.play();
humanPlayer.handCards[i]->setState(humanPlayer.handCards[i]->NORMAL); //释放后设定为普通状态
humanPlayer.cardSelect = -1; //没有在与卡牌进行交互
humanPlayer.handCards[i]->hoverSd = true; //释放卡牌,音效可播放
humanPlayer.handCards[i]->pressSd = true;
break;
default:
break;
}
}
}
}
最后来看下效果