功能实现

  1. 卡牌交互音效
  2. 卡牌拖拽

卡牌交互音效

在之前我们已经定义过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;
            }
        }
    }
}

最后来看下效果

Last modification:February 12th, 2021 at 06:14 am