コード例 #1
0
class Battle(cocos.layer.ColorLayer):
    is_event_handler = True

    def __init__(self):
        super().__init__(162, 205, 90, 255)
        self.cnum = 4  # TODO delete
        self.status = 'ready'
        self.debug = True
        self.initImage()

    def assistDebug(self):  # TODO delete
        self.me.modCrystal(10, 10)
        self.connect.send(('debug', [self.cnum]))
        time.sleep(1)
        act, local.args = recvMsgs.pop(0)
        self.me.drawCard(self.cnum)

    # 匹配
    def match(self):
        self.connect = Connect()
        self.connect.connect(local.id, local.curDeckID)
        data = self.connect.recv()
        if data == None:
            return logger.error('匹配超时')
        self.cardlist = []  #待选
        self.selected = []  #选中
        self.commitArgs = []  #暂存变量
        self.status = 'beforeBattle'
        self.renderOpening(data)  # 绘制开场信息并等待换牌

    #卡牌选择或替换
    def renderBigCards(self, cards):
        #双方战场绘制区域初始化
        x, y = self.center
        num = len(cards)
        w, h = local.winWidth, local.winHeight
        posx0 = x - (0.3 * w)  # 第一张牌的位置
        distance = 0.6 * w / (num - 1)  # 相邻两张牌的距离
        for card in cards:
            logger.debug(card.name)
            card.initImage()
            # 将其加入场景
            local.battleScene.add(card)
            i = cards.index(card)
            card.do(
                MoveTo((posx0 + distance * i, y + h / 10), 1.5) +
                ScaleBy(2, 0.5))
        self.cardlist = cards
        # 确定按钮
        self.add(self.confirmBtn, z=3)

    #开场
    def renderOpening(self, data):
        # 对方昵称,对方英雄,己方英雄,起始手牌
        opNickName, myHeroID, opHeroID, self.cardlist = data  #获取开场信息、起始手牌
        # print(data)
        # 公共战场信息
        local.battle = PublicBattle()
        me = self.me = Player(openingHeros[myHeroID](), isOpponent=False)
        me.opponent = Player(openingHeros[opHeroID](), isOpponent=True)
        # 我对手的对手是我
        me.opponent.opponent = me
        # 昵称
        enemyNickName = opNickName
        myNickName = local.nickName
        # 绘制待替换卡牌
        self.selected = []  # 换牌时selected比较特殊,是个list
        self.renderBigCards(self.cardlist)

    #起手换牌
    def replace(self):
        newCards = self.connect.send_recv(self.selected)
        logger.debug('换来的牌%s', newCards)
        cards = self.cardlist
        #重新安排cards
        for i in self.selected:
            cards[i] = newCards.pop(0)
            cards[i].initImage()
            # 将其加入场景
            local.battleScene.add(cards[i])
        if len(cards) == 4:
            #硬币入手
            coin = Coin()
            cards.append(coin)
            local.battleScene.add(coin)
        #将开场卡牌加入手牌
        for card in cards:
            card.getDrawed(self.me)
            # card.holder = self.me
        # self.me.hand = cards
        self.me.renderHand()
        self.me.opponent.drawCard(5 if len(cards) == 3 else 3)
        #重置cardlist和selected
        self.cardlist = []
        self.selected = None
        #另起线程监听服务端order
        _thread.start_new_thread(self.listenOrder, ())
        #若先手,则置为我的回合
        if len(cards) == 3:
            self.status = 'myTurnReady'
        else:
            self.status = 'enemyTurn'
            # 设置玩家回合
            self.me.opponent.myTurn = True

    # 回合开始
    def myTurnStart(self):
        logger.info('回合开始')
        #回合开始
        while not recvMsgs:
            time.sleep(0.1)
        # 设置玩家回合
        self.me.myTurn = True
        self.me.opponent.myTurn = False
        # 处理命令和参数
        order, local.args = recvMsgs.pop(0)
        self.me.genEvent(order, self.me)
        self.me.clear()
        if self.debug:
            self.assistDebug()
            self.debug = False
        self.cardlist = self.me.getAvailables()
        # 显示回合结束按钮
        self.add(self.endTurnBtn)

    # 对手行动
    def enemyAction(self):
        if not recvMsgs:
            return
        print('enemyAction', recvMsgs)
        order, local.args = recvMsgs.pop(0)
        # print('local args  ss', local.args)
        player = self.me.opponent
        if isinstance(order, Event):
            self.me.genEvent(order, player)
            if order == Event.回合结束:
                self.status = 'myTurn'
                self.myTurnStart()
                # break
        elif order == 'play':
            # args = local.args[0]
            # handIdx = args[0]
            player.play()
        elif order == 'attack':
            args = local.args.pop(0)
            card = fromLocation(args[0], player)
            target = fromLocation(args[1], player)
            card.attacking(target)
        elif order == 'power':
            pass
        elif order == 'debug':
            self.me.opponent.modCrystal(10, 10)
            self.me.opponent.drawCard(self.cnum)
        self.me.clear()

    # 监听通知
    def listenOrder(self):
        while True:
            order = self.connect.recv(1024)
            recvMsgs.append(order)
            log(('listen', recvMsgs))
            _thread.start_new_thread(self.mousemove, ())

    def commitOrder(self, act):
        card = self.selected
        log(card)
        self.connect.send((act, self.commitArgs))
        while not recvMsgs:
            time.sleep(0.2)
        order, local.args = recvMsgs.pop(0)
        if act == 'play':
            # 随从:handIdx, minionIdx, [targetLoc]
            # 其他:handIdx, [targetLoc]
            handIdx = self.commitArgs.pop(0)  #TODO 待测
            self.me.hand[handIdx].play(*self.commitArgs)
        elif act == 'attack':
            log(self.commitArgs)
            fromLocation(self.commitArgs[0], self.me).attacking(
                fromLocation(self.commitArgs[1], self.me))
        elif act == 'turnEnd':
            self.me.genEvent(Event.回合结束)
            # 设置玩家回合
            self.me.myTurn = False
            self.me.opponent.myTurn = True
            self.status = 'enemyTurn'
            self.fade()
            self.remove(self.endTurnBtn)
        self.me.clear()

    def mousemove(self):
        while True:
            if local.animingMutex == 0:
                curx, cury = simuInput.getPos()
                if self.status == 'enemyTurn' and recvMsgs:
                    simuInput.moveTo(local.winWidth - 6, local.winHeight - 6)
                elif self.status == 'myTurnReady':
                    simuInput.moveTo(local.winWidth - 6, local.winHeight - 3)
                #功成身退,回到原位
                # time.sleep(0.05)
                # print(self.status)
                # simuInput.moveTo(curx, cury)
                return
            else:
                time.sleep(0.1)

    def on_mouse_motion(self, x, y, dx, dy):
        if self.status == 'enemyTurn' and recvMsgs:
            self.enemyAction()
        elif self.status == 'myTurnReady' and x >= local.winWidth - 6 and y >= local.winHeight - 6:
            self.status = 'myTurn'
            self.myTurnStart()

    def on_mouse_press(self, posx, posy, buttons, modifiers):
        if self.status == 'myTurn' and self.me.myTurn:
            card = self.clickCard(self.cardlist, posx, posy)
            if card:
                logger.warning('箭头')
                self.add(self.arrow, z=4)
                self.status = 'arrow'
                self.selected = card
                self.fade()
                card.do(ScaleBy(1.5, 0))
            if self.hitIt(posx, posy, self.endTurnBtn, self):
                # 回合结束
                logger.info('回合结束按钮')
                self.commitOrder('turnEnd')
        elif self.status == 'battlecry':
            target = self.clickCard(self.cardlist, posx, posy)
            if target:
                # getLocation(target)
                self.commitArgs.append(toLocation(target))
                self.commitOrder('play')
        elif self.status == 'enemyTurn':
            self.enemyAction()
        elif self.status == 'beforeBattle':
            ##换牌
            card = self.clickCard(self.cardlist, posx, posy)
            if card:
                idx = self.cardlist.index(card)
                #此时比较特殊,selected存放的是序号
                if idx in self.selected:
                    card.remove(card.cross)
                    self.selected.remove(idx)
                else:
                    card.cross = Sprite(local.res['cross'],
                                        position=card.items['frame'].position,
                                        scale=local.itemScale * card.scale * 4)
                    card.add(card.cross, z=3)
                    self.selected.append(idx)
                return
            if self.hitIt(posx, posy, self.confirmBtn, self):
                # self.status = 'myTurnReady'
                for idx in self.selected:
                    local.battleScene.remove(self.cardlist[idx])
                self.remove(self.confirmBtn)
                self.replace()

    #判断指定对象是否被点击
    def hitIt(self, posx, posy, sprite, node):
        nodex, nodey = node.position
        spritex, spritey = sprite.position
        x, y = spritex + nodex, spritey + nodey
        w, h = sprite.width * node.scale, sprite.height * node.scale
        if x - w / 2 < posx < x + w / 2 and y - h / 2 < posy < y + h / 2:
            return True

    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
        if self.status == 'arrow':
            #箭头跟随鼠标
            self.arrow.position = x, y

    def on_mouse_release(self, posx, posy, buttons, modifiers):
        if self.status != 'arrow':
            return
        #箭头消失
        self.remove(self.arrow)
        self.status = 'none'
        #当前操纵卡牌
        card = self.selected
        me = self.me
        # 若为手牌,将其位置作为提交的第一个参数
        if card in self.me.hand:
            self.commitArgs = [self.me.hand.index(card)]
        # 随从牌
        if card in self.me.hand and card.type == 'minion':
            x, y, w, h = me.minionRegion
            if x < posx < x + w and y < posy < y + h:
                fieldIdx = 0
                for m in me.minionField:
                    if m.position[0] < posx:
                        fieldIdx += 1
                    else:
                        break
                self.commitArgs.append(fieldIdx)
                # 若有战吼目标
                # 或有连击、有连击计数且有连击目标
                # 直接返回,保留self.selected
                if card.targetType and (
                    ('combo' not in card.exts) or
                    ('combo' in card.exts and card.holder.comboCount > 0)):
                    logger.info('战吼或连击')
                    self.cardlist = card.getSelectables()
                    if self.cardlist:
                        self.status == 'battlecry'
                        return
                    #若没有符合条件的战吼目标,取消战吼直接登场
                # print(card.name, '直接登场')
                self.commitOrder('play')
        #无需指定目标的手牌
        elif posy < me.minionRegion[1]: # 需上移一定距离才可打出,防误触
            pass
        elif card in self.me.hand and not card.targetType:
            self.commitOrder('play')
        else:
            print('法术',me.minionRegion[1],posy)
            #获得所有可针对的目标
            targets = card.getSelectables()
            #获取当前位置且可针对的目标
            target = self.clickCard(targets, posx, posy)
            #没有满足条件的目标
            if not target:
                return
            #若卡牌为场上角色,发起攻击
            if card in card.holder.minionField + [self.me.hero]:
                self.commitArgs = [
                    toLocation(card, me),
                    toLocation(target, me)
                ]
                self.commitOrder('attack')
            else:
                self.commitArgs.append(self.getLocation(target))
                self.commitOrder('play')
        self.settle()

    #整理场面
    def settle(self):
        self.status = 'myTurn'
        self.arrow.position = (-100, -100)
        self.fade()
        self.cardlist = self.me.getAvailables()
        self.selected.scale = local.cardScale
        self.selected = None
        self.commitArgs = []
        self.me.renderHand()
        if not self.cardlist:
            #没有可做的事了
            #TODO 特殊提示
            pass

    # 键盘按压
    def on_key_press(self, key, modifiers):
        if self.status == 'ready' and key == local.keyCode['space']:
            self.status = ''
            logger.info('匹配中')
            self.match()

    #消除可选/可操作光圈
    def fade(self):
        log(self.cardlist)
        for card in self.cardlist:
            try:
                card.remove(card.items['circle'])
            except:
                logger.debug('%s没有光圈', card.name)

    #若有卡牌在点击范围,返回这张卡
    def clickCard(self, cards, posx, posy):
        for card in cards:
            # x,y=card.position
            # print(x,y)
            # w,h = card.items['frame'].width*card.scale, card.items['frame'].height*card.scale
            # if x-w/2<posx<x+w/2 and y-h/2<posy<y+h/2:
            if self.hitIt(posx, posy, card.items['frame'], card):
                return card
        return None

    #绘制战场按钮
    def initImage(self):
        self.center = (director.get_window_size()[0] / 2,
                       director.get_window_size()[1] / 2)
        posx, posy = self.center
        # 棋盘
        self.chessboard = Sprite(local.res['chessboard'],
                                 position=self.center,
                                 scale=local.winHeight * 0.8 / 1000)
        self.add(self.chessboard)
        # 确认按钮
        self.confirmBtn = Sprite(local.res['confirm'],
                                 position=(posx, posy - 0.2 * local.winHeight),
                                 scale=local.winHeight * 0.6 / 1000)
        # 红箭头
        self.arrow = Sprite(local.res['arrow'], position=(-100, -100))
        # 回合结束按钮
        self.endTurnBtn = Sprite(local.res['end_turn'],
                                 position=local.endTurnPos)
        #初始化模拟点击
        simuInput.init(local.director)
        _thread.start_new_thread(simuInput.key_press, ('space', ))