游戏开始时选择武将后,服务端统一控制向玩家分发初始手牌,并向客户端发生绘制手牌的命令.跟踪的流程如下:服务端向客户端发送命令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);
}

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

  1. vs2008编译QT开源项目--太阳神三国杀源码分析(一) 项目编译及整体分析

    请参看 http://tieba.baidu.com/f?kz=1508964881 按照上面的网址教程,下载三国杀源码,swig工具,并下载最新的QT4.8.2 for vs2008.我本机已经安装 ...

  2. vs2008编译QT开源项目--太阳神三国杀源码分析(四) 动画

    太阳神三国杀中,每当玩家出杀或吃桃子时,就会有一个动画效果,使界面非常生动绚丽.现在我们就分析一下QT中动画的原理,及实现方式,这里我们只分析吃桃子时的动画效果实现.由于三国杀有多个在线玩家同时游戏, ...

  3. vs2008编译QT开源项目--太阳神三国杀源码分析(三) 皮肤

    太阳神三国杀的界面很绚丽,界面上按钮的图标,鼠标移入移出时图标的变化,日志和聊天Widget的边框和半透明等效果,既可以通过代码来控制,也可以使用皮肤文件qss进行控制.下面我们分析一下三国杀的qss ...

  4. vs2008编译QT开源项目--太阳神三国杀源码分析(二) 客户端添加武将

    接着上篇文章继续分析,我们来看看进入到roomScene(房间场景)后,点击add a robot按钮,是如何创建武将的.首先找到add to robot按钮的创建代码: add_robot = ne ...

  5. Mac下编译太阳神三国杀源码

    Mac系统版本是10.13.2,Qt版本是5.11,参考官方博文:太阳神三国杀 Mac 版构建指南 安装Qt5 下载最新的Qt5安装包qt-opensource-mac-x64-5.11.0.dmg, ...

  6. 开源项目-太阳神三国杀-QT4编译教程

    待更中 转载于:https://www.cnblogs.com/sinpener/p/10734692.html

  7. android studio 项目源码_这个标星 2.3k+ 的项目带你 Android 源码分析从入门到放弃...

    上次写了一篇 Android 开发者的福利,介绍几款看源码的工具 ,这篇文章主要介绍了三款看 Android 源码的工具,后台有很多同学留言问,有没有分析源码的. 分析源码的文章也很多,但大多数文章不 ...

  8. (4.2.40)阿里开源路由框架ARouter的源码分析

    一需求背景 1 Android原生方案的不足 2 自定义路由框架的适用场景 3 对自定义路由框架的设想 二ARouter的概述 三ARouter的引入和使用 四源码分析 1 arouter-annot ...

  9. 一个完整的python项目源码-一个Python开源项目-哈勃沙箱源码剖析(下)

    前言 在上一篇中,我们讲解了哈勃沙箱的技术点,详细分析了静态检测和动态检测的流程.本篇接着对动态检测的关键技术点进行分析,包括strace,sysdig,volatility.volatility的介 ...

最新文章

  1. XHTML Strict和Transitional 的区别
  2. python机器学习实战(一)
  3. python教程:如何写类?
  4. AndroidStudio中使用XML和Java代码混合控制UI界面实现QQ相册照片列表页面
  5. 2021年2月Harmonyos时候上线,华为HarmonyOS系统将于4月上线 MateX2首批升级
  6. 玩转Android之加速度传感器的使用,模仿微信摇一摇
  7. 通过jquer连接数据库里面的数据、LINQ简介
  8. KafkaConsumer源码解析
  9. 怎么判断我选了多少个复选框_7~8个月宝宝一天吃多少辅食,怎么安排?妈妈这样做,养出健康娃...
  10. Linux的进程优先级NI和PR
  11. 戴尔服务器t系列和r系列,满足VR需求 戴尔升级T/R系列塔式工作站
  12. 并行程序调试、测试与模型检测
  13. android screenshot 命令,android 截图,视频录制命令 screencap screenrecord screenshot
  14. java打印字符串_Java 打印字符串
  15. 在 Ubuntu Linux 上安装 Maya 2018
  16. 外贸电子商务常见VISA信用卡或MasterCard等测试信用卡卡号一览
  17. 磁盘的组成、MBR、GPT
  18. 2021正睿csp7连day1
  19. 拓展交流空间,分享开发精彩 | 开发者说·DTalk 鉴赏
  20. Java数据结构--Linkedlist

热门文章

  1. python dataframe dropna_在Python中使用熊猫在两个DataFrame之间进行值...
  2. 【技巧】windows11任务栏无法打开任务管理器的解决办法
  3. MT6853(联发科技天玑 720 )核心板支持5G北斗
  4. 我给互联网大佬们换上了女装
  5. js实现图片拖拽,定点缩放,旋转 (二)
  6. Python核心编程-Amy老师第七讲课程作业
  7. 【RPC】分布式一致性与一致性协议
  8. 用天然气做燃料极空气做氧化极的燃料电池
  9. 字节跳动安全AI挑战赛总结
  10. 武大博士后应聘社区社工引热议,内卷还是人各有志?