Exemple #1
0
class Robot(QGraphicsItemGroup):
    def __init__(self, mapSize, parent, repr):
        QGraphicsItemGroup.__init__(self)

        # 公有属性
        self.gamePlace = 1

        # 私有属性
        self.__mapSize = mapSize
        self.__parent = parent
        self.__health = 100
        self.__repr = repr

        self.__gunLock = "free"
        self.__radarLock = "Free"  # 字面意思是雷达锁

        # 两个动画对象、一个physics对象
        self.__runAnimation = animation("run")
        self.__targetAnimation = animation("target")
        self.__physics = physics(self.__runAnimation)  # 一个physics对象

        # 设置一些颜色
        self.maskColor = QColor(0, 255, 255)
        self.gunMaskColor = QColor(0, 255, 255)  # 炮膛颜色
        self.radarMaskColor = QColor(0, 255, 255)  # 雷达颜色

        # 加载车身图片
        self.__base = QGraphicsPixmapItem()
        self.__base.pixmap = QPixmap(os.getcwd() + "/robotImages/baseGrey.png")
        self.__base.setPixmap(self.__base.pixmap)
        self.addToGroup(self.__base)
        self.__baseWidth = self.__base.boundingRect().width()
        self.__baseHeight = self.__base.boundingRect().height()

        # 加载炮膛图片
        self.__gun = QGraphicsPixmapItem()
        self.__gun.pixmap = QPixmap(os.getcwd() + "/robotImages/gunGrey.png")
        self.__gun.setPixmap(self.__gun.pixmap)
        self.addToGroup(self.__gun)
        self.__gunWidth = self.__gun.boundingRect().width()
        self.__gunHeight = self.__gun.boundingRect().height()

        # 炮膛位置
        x = self.__base.boundingRect().center().x()
        y = self.__base.boundingRect().center().y()
        self.__gun.setPos(x - self.__gunWidth / 2.0,
                          y - self.__gunHeight / 2.0)

        # --------------------------雷达初始化-----------------------------

        # 加载雷达图片
        self.__radar = QGraphicsPixmapItem()
        self.__radar.pixmap = QPixmap(os.getcwd() + "/robotImages/radar.png")
        self.__radar.setPixmap(self.__radar.pixmap)
        self.addToGroup(self.__radar)
        self.__radarWidth = self.__radar.boundingRect().width()
        self.__radarHeight = self.__radar.boundingRect().height()
        # radar position
        self.__radar.setPos(x - self.__radarWidth / 2.0,
                            y - self.__radarHeight / 2.0)

        # 加载雷达范围
        firstPoint = QPointF(x - self.__radarWidth / 2, y)
        secondPoint = QPointF(x + self.__radarWidth / 2, y)
        thirdPoint = QPointF(x + 4 * self.__radarWidth, y + 700)
        fourthPoint = QPointF(x - 4 * self.__radarWidth, y + 700)
        qPointListe = []
        qPointListe.append(firstPoint)
        qPointListe.append(secondPoint)
        qPointListe.append(thirdPoint)
        qPointListe.append(fourthPoint)
        self.__radarField = radarField(qPointListe, self, "poly")

        # 大雷达范围
        qPointListe.remove(fourthPoint)
        qPointListe.remove(thirdPoint)
        thirdPoint = QPointF(x + 10 * self.__radarWidth, y + 400)
        fourthPoint = QPointF(x - 10 * self.__radarWidth, y + 400)
        qPointListe.append(thirdPoint)
        qPointListe.append(fourthPoint)
        self.__largeRadarField = radarField(qPointListe, self, "poly")

        # 细雷达范围
        qPointListe.remove(fourthPoint)
        qPointListe.remove(thirdPoint)
        thirdPoint = QPointF(x + 0.4 * self.__radarWidth, y + 900)
        fourthPoint = QPointF(x - 0.4 * self.__radarWidth, y + 900)
        qPointListe.append(thirdPoint)
        qPointListe.append(fourthPoint)
        self.__thinRadarField = radarField(qPointListe, self, "poly")

        # 弧形雷达范围
        self.__roundRadarField = radarField([0, 0, 300, 300], self, "round")
        self.addToGroup(self.__roundRadarField)
        self.__roundRadarField.setPos(
            x - self.__roundRadarField.boundingRect().width() / 2.0,
            y - self.__roundRadarField.boundingRect().height() / 2.0)

        # add to group
        self.addToGroup(self.__radarField)
        self.addToGroup(self.__largeRadarField)
        self.addToGroup(self.__thinRadarField)

        # 一个坦克上有三个雷达范围,但初始化的时候都是隐藏的
        self.__largeRadarField.hide()
        self.__thinRadarField.hide()
        self.__roundRadarField.hide()
        # --------------------------雷达初始化(上-----------------------------

        # 设置坦克颜色:RGB
        self.setColor(0, 200, 100)
        self.setGunColor(0, 200, 100)
        self.setRadarColor(0, 200, 100)
        self.setBulletsColor(0, 200, 100)

        # 设置原点:
        # 雷达范围
        self.__radarField.setTransformOriginPoint(x, y)
        self.__largeRadarField.setTransformOriginPoint(x, y)
        self.__thinRadarField.setTransformOriginPoint(x, y)
        # 车身
        x = self.__baseWidth / 2
        y = self.__baseHeight / 2
        self.__base.setTransformOriginPoint(x, y)
        # 炮膛
        x = self.__gunWidth / 2
        y = self.__gunHeight / 2
        self.__gun.setTransformOriginPoint(x, y)
        # 雷达(雷达与雷达范围不是一个东西
        x = self.__radarWidth / 2
        y = self.__radarHeight / 2
        self.__radar.setTransformOriginPoint(x, y)

        # 添加self.item到items中以防冲突
        self.__items = set([
            self, self.__base, self.__gun, self.__radar, self.__radarField,
            self.__largeRadarField, self.__thinRadarField,
            self.__roundRadarField
        ])

        # 初始化基类(初始化子类中的初始化函数
        self.init()

        # 当前动画
        self.__currentAnimation = []
        # self.a = time.time()

    '''
        重写QGraphicsItem类的advance函数
    '''

    def advance(self, i):
        """
        if i ==1:
            print(time.time() - self.a)
            self.a = time.time()
        """
        # 如果机器人的血量小于等于0
        if self.__health <= 0:
            self.gamePlace = len(self.__parent.aliveBots)
            # print("Robot.advance:"+str(self.gamePlace))
            self.__parent.placeList.append(self.__repr__())
            self.__death()

        # 如果当前的动画列表为空
        if self.__currentAnimation == []:
            try:
                self.__currentAnimation = self.__physics.animation.list.pop()

            except IndexError:
                if self.__physics.animation.name == "target":
                    try:
                        self.__physics.animation = self.__runAnimation
                        self.__currentAnimation = self.__physics.animation.list.pop(
                        )
                    except IndexError:
                        pass
                else:
                    self.stop()
                    try:
                        self.run()
                    except:
                        traceback.print_exc()
                        exit(-1)
                    self.__physics.reverse()
                    try:
                        self.__currentAnimation = self.__physics.animation.list.pop(
                        )
                    except:
                        pass

        if i == 1:
            try:
                command = self.__currentAnimation.pop()  # load animation

                # 读取并执行移动命令
                dx, dy = self.__getTranslation(command["move"])
                self.setPos(dx, dy)

                # 读取并执行转向命令
                angle = self.__getRotation(command["turn"])
                self.__base.setRotation(angle)
                if self.__gunLock.lower() == 'base':
                    self.__gun.setRotation(angle)
                if self.__radarLock.lower() == 'base':
                    self.__setRadarRotation(angle)

                # gun Rotation
                angle = self.__getGunRotation(command["gunTurn"])
                self.__gun.setRotation(angle)
                if self.__radarLock.lower() == 'gun':
                    self.__setRadarRotation(angle)

                # radar Rotation
                angle = self.__getRadarRotation(command["radarTurn"])
                self.__setRadarRotation(angle)

                # asynchronous fire
                #读取并执行开火命令
                if command["fire"] != 0:
                    self.makeBullet(command["fire"])
            except:
                pass

        else:
            # 执行子类的函数——————————————————————!!!!!!!!!
            self.sensors()

            # collisions
            for item in set(self.__base.collidingItems(1)) - self.__items:
                if isinstance(item, QGraphicsRectItem):
                    # wall Collision
                    self.__wallRebound(item)
                elif isinstance(item, Robot):
                    if item.__base.collidesWithItem(self.__base):
                        # robot Collision
                        self.__robotRebound(item)
                elif isinstance(item, Bullet):
                    # bullet colision
                    self.__bulletRebound(item)
                elif isinstance(item, radarField):
                    if item.robot.__physics.animation.name != "target":
                        # targetSpotted
                        self.__targetSeen(item)

    # -------------------------------------------炮膛-------------------------------------------
    # 炮膛转向
    def gunTurn(self, angle):
        s = 1
        if angle < 0:
            s = -1
        steps = int(s * angle / self.__physics.step)
        a = angle % self.__physics.step
        if a != 0:
            self.__physics.gunTurn.append(s * a)
        for i in range(steps):
            self.__physics.gunTurn.append(s * self.__physics.step)

    def lockGun(self, part):
        self.__gunLock = part

    # 设置炮膛颜色
    def setGunColor(self, r, g, b):
        color = QColor(r, g, b)
        mask = self.__gun.pixmap.createMaskFromColor(self.gunMaskColor, 1)
        p = QPainter(self.__gun.pixmap)
        p.setPen(QColor(r, g, b))
        p.drawPixmap(self.__gun.pixmap.rect(), mask, mask.rect())
        p.end()
        self.__gun.setPixmap(self.__gun.pixmap)
        self.gunMaskColor = QColor(r, g, b)

    # -------------------------------------------车身(下-------------------------------------
    # 车身的移动方式
    def move(self, distance):
        s = 1
        if distance < 0:
            s = -1
        steps = int(s * distance / self.__physics.step)
        d = distance % self.__physics.step
        if d != 0:
            self.__physics.move.append(s * d)
        for i in range(steps):
            self.__physics.move.append(s * self.__physics.step)

    # 转向方法,传入的参数为一个角度(类型未知
    def turn(self, angle):
        s = 1
        if angle < 0:
            s = -1
        steps = int(s * angle / self.__physics.step)
        a = angle % self.__physics.step
        if a != 0:
            self.__physics.turn.append(s * a)
        for i in range(steps):
            self.__physics.turn.append(s * self.__physics.step)

    # 设置车身颜色
    def setColor(self, r, g, b):
        color = QColor(r, g, b)
        mask = self.__base.pixmap.createMaskFromColor(self.maskColor, 1)
        p = QPainter(self.__base.pixmap)
        p.setPen(QColor(r, g, b))
        p.drawPixmap(self.__base.pixmap.rect(), mask, mask.rect())
        p.end()
        self.__base.setPixmap(self.__base.pixmap)
        self.maskColor = QColor(r, g, b)

    # ---------------------------------------------雷达(下-----------------------------

    def setRadarField(self, form):
        '''
            设置《雷达范围》类型
            类型:normal、large、thin、round
            根据传入的类型来设置显示的类型(其他类型的就hide
        '''
        if form.lower() == "normal":
            self.__radarField.show()
            self.__largeRadarField.hide()
            self.__thinRadarField.hide()
            self.__roundRadarField.hide()
        if form.lower() == "large":
            self.__radarField.hide()
            self.__largeRadarField.show()
            self.__thinRadarField.hide()
            self.__roundRadarField.hide()
        if form.lower() == "thin":
            self.__radarField.hide()
            self.__largeRadarField.hide()
            self.__thinRadarField.show()
            self.__roundRadarField.hide()
        if form.lower() == "round":
            self.__radarField.hide()
            self.__largeRadarField.hide()
            self.__thinRadarField.hide()
            self.__roundRadarField.show()

    def lockRadar(self, part):
        self.__radarLock = part

    # 雷达转向
    def radarTurn(self, angle):
        s = 1
        if angle < 0:
            s = -1
        steps = int(s * angle / self.__physics.step)
        a = angle % self.__physics.step
        if a != 0:
            self.__physics.radarTurn.append(s * a)
        for i in range(steps):
            self.__physics.radarTurn.append(s * self.__physics.step)

    # 设置雷达颜色(雷达罩的颜色,在坦克车身上的
    def setRadarColor(self, r, g, b):
        color = QColor(r, g, b)
        mask = self.__radar.pixmap.createMaskFromColor(self.radarMaskColor, 1)
        p = QPainter(self.__radar.pixmap)
        p.setPen(QColor(r, g, b))
        p.drawPixmap(self.__radar.pixmap.rect(), mask, mask.rect())
        p.end()
        self.__radar.setPixmap(self.__radar.pixmap)
        self.radarMaskColor = QColor(r, g, b)

    # 设置雷达是否可见,将几个雷达类型都设置为统一的
    def radarVisible(self, bol):
        self.__radarField.setVisible(bol)
        self.__roundRadarField.setVisible(bol)
        self.__thinRadarField.setVisible(bol)
        self.__largeRadarField.setVisible(bol)

    # --------------------------------------------子弹(下------------------------------------
    def fire(self, power):
        # asynchronous fire
        self.stop()
        bullet = Bullet(power, self.bulletColor, self)
        self.__physics.fire.append(bullet)
        self.__items.add(bullet)
        self.__parent.addItem(bullet)
        bullet.hide()
        return id(bullet)

    # 制造子弹,传入的参数是个子弹对象
    def makeBullet(self, bullet):
        bullet.show()
        pos = self.pos()
        angle = self.__gun.rotation()
        # to find the initial position
        x = pos.x() + self.__baseWidth / 2.0
        y = pos.y() + self.__baseHeight / 2.0
        dx = -math.sin(math.radians(angle)) * self.__gunWidth / 2.0
        dy = math.cos(math.radians(angle)) * self.__gunHeight / 2.0
        pos.setX(x + dx)
        pos.setY(y + dy)
        bot = self

        #设置一些子弹的属性
        bullet.init(pos, angle, self.__parent)

        #生成子弹后,会扣除自己的血量,(如果击中敌人会回血
        self.__changeHealth(self, -bullet.power)
        return id(bullet)

    # 设置子弹颜色
    def setBulletsColor(self, r, g, b):
        self.bulletColor = QColor(r, g, b)

    # ---------------------------------------整体的方法(下--------------------------------------

    #停止方法,调用后会使__physics产生一个新的动画
    def stop(self):
        self.__physics.newAnimation()

    # 获取地图尺寸
    def getMapSize(self):
        return self.__mapSize

    # 获取位置
    def getPosition(self):
        p = self.pos()
        r = self.__base.boundingRect()
        return QPointF(p.x() + r.width() / 2, p.y() + r.height() / 2)

    # 获取炮膛朝向
    def getGunHeading(self):
        angle = self.__gun.rotation()
        # if angle > 360:
        #     a = int(angle) / 360
        #     angle = angle - (360*a)
        return angle

    # 获取朝向
    def getHeading(self):
        return self.__base.rotation()

    # 获取雷达朝向
    def getRadarHeading(self):
        return self.__radar.rotation()

    def reset(self):
        self.__physics.reset()
        self.__currentAnimation = []

    # 获取敌人
    def getEnemiesLeft(self):
        l = []
        for bot in self.__parent.aliveBots:
            dic = {"id": id(bot), "name": bot.__repr__()}
            l.append(dic)
        return l

    # 向细节面板加内容的方法
    def rPrint(self, msg):
        self.info.out.add(str(msg))

    def pause(self, duration):
        self.stop()
        for i in range(int(duration)):
            self.__physics.move.append(0)
        self.stop()

    # ---------------------------------下面为私有方法------------------------------------------

    def __getTranslation(self, step):
        angle = self.__base.rotation()
        pos = self.pos()
        x = pos.x()
        y = pos.y()
        dx = -math.sin(math.radians(angle)) * step
        dy = math.cos(math.radians(angle)) * step
        # print(dx, dy)
        return x + dx, y + dy

    def __setRadarRotation(self, angle):
        self.__radar.setRotation(angle)
        self.__radarField.setRotation(angle)
        self.__largeRadarField.setRotation(angle)
        self.__thinRadarField.setRotation(angle)

    def __getRotation(self, alpha):
        return self.__base.rotation() + alpha

    def __getGunRotation(self, alpha):
        return self.__gun.rotation() + alpha

    def __getRadarRotation(self, alpha):
        return self.__radar.rotation() + alpha

    def __wallRebound(self, item):
        self.reset()
        if item.name == 'left':
            x = self.__physics.step * 1.1
            y = 0
        elif item.name == 'right':
            x = -self.__physics.step * 1.1
            y = 0
        elif item.name == 'top':
            x = 0
            y = self.__physics.step * 1.1
        elif item.name == 'bottom':
            x = 0
            y = -self.__physics.step * 1.1
        self.setPos(self.pos().x() + x, self.pos().y() + y)
        self.__changeHealth(self, -1)
        self.stop()
        try:

            # 执行子类的方法-----------!!!!!!!!!!!!!!!
            self.onHitWall()
        except:
            traceback.print_exc()
            exit(-1)
        animation = self.__physics.makeAnimation()
        if animation != []:
            self.__currentAnimation = animation

    def __robotRebound(self, robot):
        try:
            self.reset()
            robot.reset()
            angle = self.__base.rotation()
            pos = self.pos()
            x = pos.x()
            y = pos.y()
            dx = -math.sin(math.radians(angle)) * self.__physics.step * 1.1
            dy = math.cos(math.radians(angle)) * self.__physics.step * 1.1
            self.setPos(x - dx, y - dy)
            pos = robot.pos()
            x = pos.x()
            y = pos.y()
            robot.setPos(x + dx, y + dy)
            self.__changeHealth(robot, -1)
            self.__changeHealth(self, -1)
            self.stop()
            # 执行子类的函数
            self.onRobotHit(id(robot), robot.__repr__())
            animation = self.__physics.makeAnimation()
            if animation != []:
                self.__currentAnimation = animation
            robot.stop()
            robot.onHitByRobot(id(self), self.__repr__())
            animation = robot.__physics.makeAnimation()
            if animation != []:
                robot.__currentAnimation = animation
        except:
            traceback.print_exc()
            exit(-1)

    def __bulletRebound(self, bullet):
        self.__changeHealth(self, -3 * bullet.power)
        try:
            if bullet.robot in self.__parent.aliveBots:
                self.__changeHealth(bullet.robot, 2 * bullet.power)
            self.stop()
            self.onHitByBullet(id(bullet.robot), bullet.robot.__repr__(),
                               bullet.power)
            animation = self.__physics.makeAnimation()
            if animation != []:
                self.__currentAnimation = animation
            bullet.robot.stop()
            bullet.robot.onBulletHit(id(self), id(bullet))
            animation = bullet.robot.__physics.makeAnimation()
            if animation != []:
                bullet.robot.__currentAnimation = animation
            self.__parent.removeItem(bullet)
        except:
            pass

    def __targetSeen(self, target):
        self.stop()
        anim = target.robot.__currentAnimation
        target.robot.__physics.animation = target.robot.__targetAnimation
        target.robot.__physics.reset()
        try:
            target.robot.onTargetSpotted(id(self), self.__repr__(),
                                         self.getPosition())
        except:
            traceback.print_exc()
            exit(-1)
        target.robot.__physics.newAnimation()
        target.robot.__physics.reverse()
        try:
            target.robot.__currentAnimation = target.robot.__physics.animation.list.pop(
            )
        except:
            target.robot.__physics.animation = target.robot.__runAnimation
            target.robot.__currentAnimation = anim

    def __changeHealth(self, bot, value):

        if bot.__health + value >= 100:
            bot.__health = 100
        else:
            bot.__health = bot.__health + value
        try:
            bot.progressBar.setValue(bot.__health)
        except:
            pass

    def removeMyProtectedItem(self, item):
        self.__items.remove(item)

    def __death(self):

        try:
            self.icon.setIcon(QIcon(os.getcwd() + "/robotImages/dead.png"))
            self.icon2.setIcon(QIcon(os.getcwd() + "/robotImages/dead.png"))
            self.progressBar.setValue(0)
        except:
            pass
        self.__parent.deadBots.append(self)
        self.__parent.aliveBots.remove(self)
        try:
            self.onRobotDeath()
        except:
            traceback.print_exc()
            exit(-1)
        self.__parent.removeItem(self)

        if len(self.__parent.aliveBots) <= 1:  # 如果生存的机器人小于等于1,则结束战斗
            self.__parent.battleFinished()

    def __repr__(self):
        repr = self.__repr.split(".")
        return repr[1].replace("'>", "")