vs2008编译QT开源项目--太阳神三国杀源码分析(五) 分牌及出牌

游戏开始时选择武将后,服务端统一控制向玩家分发初始手牌,并向客户端发生绘制手牌的命令.跟踪的流程如下:服务端向客户端发送命令drawCards及随后的一串使用加号(+)连接起来的牌编号(drawCards 91+50+112+100+42+133+43+78).客户端解析这个命令串后调用drawCards函数(原理在上面的系列分析中已经阐述),并使用后面的字符串作为参数,在drawCards函数中解析出牌的编号,根据牌的编号得到Card对象实例,加入到cards列表及ClientPlayer类型全局对象(Self)的手牌列表.接着触发cards_drawed信号.

void Client::drawCards(const QString &cards_str){
    QList<const Card*> cards;
    QStringList card_list = cards_str.split("+");
    foreach(QString card_str, card_list){
        int card_id = card_str.toInt();
        const Card *card = Sanguosha->getCard(card_id);
        cards << card;
        Self->addCard(card, Player::Hand);
    }

    pile_num -= cards.length();
    updatePileNum();

    emit cards_drawed(cards);
}

roomScene类的构造函数中关联了cards_drawed信号:connect(ClientInstance, SIGNAL(cards_drawed(QList<const Card*>)), this, SLOT(drawCards(QList<const Card*>)));在这个信号处理函数中,遍历每张牌,生成新的CardItem对象.注意,Card类是一个从QObject继承的,而CardItem是从QGraphicsObject继承而来,因此CardItem可以加入到场景中并在视图中显示.接着设置显示位置和使能,加入到玩家的控制区域(dashboard,翻译为仪表盘),最后写日志信息.

void RoomScene::drawCards(const QList<const Card *> &cards){
    foreach(const Card * card, cards){
        CardItem *item = new CardItem(card);
        item->setPos(room_layout->drawpile);
        item->setEnabled(false);
        dashboard->addCardItem(item);
    }

    log_box->appendLog("#DrawNCards", Self->getGeneralName(), QStringList(), QString(), QString::number(cards.length()));
}

Dashboard::addCardItem方法将代表牌的每个CardItem加入到自己的子列表中,使牌的图像可以显示在仪表盘中,并调整显示位置,添加到card_items中进行管理,设置card_item的信号处理曹函数.这里可以看到card_item的鼠标点击等信号的处理绑定.

void Dashboard::addCardItem(CardItem *card_item){
    card_item->filter(filter);

    if(ClientInstance->getStatus() == Client::Playing)
        card_item->setEnabled(card_item->getFilteredCard()->isAvailable(Self));
    else{
        card_item->setEnabled(true);
        card_item->setEnabled(false);
    }

    card_item->setPos(mapFromScene(card_item->pos()));
    card_item->setParentItem(this);
    card_item->setRotation(0.0);
    card_item->setFlags(ItemIsFocusable);
    card_item->setZValue(0.1);
    card_items << card_item;

    connect(card_item, SIGNAL(clicked()), this, SLOT(onCardItemClicked()));
    connect(card_item, SIGNAL(thrown()), this, SLOT(onCardItemThrown()));
    connect(card_item, SIGNAL(enter_hover()), this, SLOT(onCardItemHover()));
    connect(card_item, SIGNAL(leave_hover()), this, SLOT(onCardItemLeaveHover()));

    sortCards(sort_type);

    handcard_num->setText(QString::number(Self->getHandcardNum()));
    //handcard_num->parentItem()->show();
}

看一下onCardItemClicked曹函数,这个函数没有参数,但借助于QT的信号曹机制,可以使用sender()获得信号的发出对象,即被点击的那张牌.借助设置牌的选择标志,触发card_selected信号,激活处理函数enableTargets(在roomScene构造函数中绑定connect(dashboard, SIGNAL(card_selected(const Card*)), this, SLOT(enableTargets(const Card*)));)这个函数去调整出牌界面的确定按钮的使能.

void Dashboard::onCardItemClicked(){
    CardItem *card_item = qobject_cast<CardItem *>(sender());
    if(!card_item)
        return;

    if(view_as_skill){
        if(card_item->isPending()){
            card_item->unselect();
            pendings.removeOne(card_item);
        }else{
            card_item->select();
            pendings << card_item;
        }

        updatePending();

    }else{
        if(card_item->isPending()){
            unselectAll();
            emit card_selected(NULL);
        }else{
            unselectAll();
            card_item->select();
            //card_item->goBack();
            selected = card_item;

            emit card_selected(selected->getFilteredCard());
        }
    }
}

 出牌界面的确认按钮为ok_button,其点击事件处理函数为:

void RoomScene::doOkButton(){
    if(!ok_button->isEnabled())
        return;

    useSelectedCard();
}

void RoomScene::useSelectedCard(){
    switch(ClientInstance->getStatus()){
    case Client::Playing:{
            const Card *card = dashboard->getSelected();
            if(card)
                useCard(card);
            break;
        }

       ......

}

过去客户端的状态,如果是正在游戏状态,则调用useCard函数:

void RoomScene::useCard(const Card *card){
    if(card->targetFixed() || card->targetsFeasible(selected_targets, Self))
        ClientInstance->onPlayerUseCard(card, selected_targets);

    enableTargets(NULL);
}

onPlayerUseCard函数通知服务端玩家所出的牌和目标玩家:

void Client::onPlayerUseCard(const Card *card, const QList<const Player *> &targets){

    if(card == NULL){
        replyToServer(S_COMMAND_USE_CARD, Json::Value::null);
        // request("useCard .");
    }else{
        Json::Value targetNames(Json::arrayValue);
        foreach(const Player *target, targets)
            targetNames.append(toJsonString(target->objectName()));

        replyToServer(S_COMMAND_USE_CARD, toJsonArray(card->toString(), targetNames));

        //if(target_names.isEmpty())
        //    request(QString("useCard %1->.").arg(card->toString()));
        //else
        //    request(QString("useCard %1->%2").arg(card->toString()).arg(target_names.join("+")));

        if(status == Responsing)
            card_pattern.clear();
    }

    setStatus(NotActive);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值