Beispiel #1
0
class Power(NodePath, HUDElement):
    """Modified from drwr: https://discourse.panda3d.org/t/health-bars-using-directgui/2098/3"""
    def __init__(self, min_strike=0.05, max_strike=7):
        self.min_strike = min_strike
        self.max_strike = max_strike

        HUDElement.__init__(self)
        self.text_scale = 0.11
        self.text_color = (1, 1, 1, 1)

        NodePath.__init__(self, 'powerbar')
        self.reparentTo(self.dummy_right)

        cmfg = CardMaker('fg')
        cmfg.setFrame(0, 1, -0.04, 0.04)
        self.fg = self.attachNewNode(cmfg.generate())

        cmbg = CardMaker('bg')
        cmbg.setFrame(-1, 0, -0.04, 0.04)
        self.bg = self.attachNewNode(cmbg.generate())
        self.bg.setPos(1, 0, 0)

        self.fg.setColor(1, 0, 0, 1)
        self.bg.setColor(0.5, 0.5, 0.5, 1)

        self.setScale(0.3)

        start_value = 2
        self.text = OnscreenText(
            text=f"{start_value:.2f} m/s",
            pos=(0, 0),
            scale=self.text_scale,
            fg=self.text_color,
            align=TextNode.ACenter,
            mayChange=True,
            parent=self,
        )
        self.text.setPos(0.5, -0.15)
        self.setPos(0, 0, -0.9)

        self.set(start_value)

    def init(self):
        self.show()

    def destroy(self):
        self.hide()
        del self.text
        del self

    def set(self, V0):
        self.text.setText(f"{V0:.2f} m/s")

        value = (V0 - self.min_strike) / (self.max_strike - self.min_strike)
        if value < 0: value = 0
        if value > 1: value = 1
        self.fg.setScale(value, 1, 1)
        self.bg.setScale(1.0 - value, 1, 1)
class Personagem():
    def __init__(self, render):
        self.fram = DirectFrame(frameSize=(100,100,100,100),
                                 frameColor=(255,0,0,0),
                                 pos=(0.0,0,0))
        #self.fram.setPos(-1,0)
        #render.attachNewNode (self.frame)
    
    def hp(self,base):
        self.hp = OnscreenText(text = "100", pos=(0,0,0), parent = base.aspect2d)
        #self.NewButton = DirectButton(frameColor = (0, 0, 0, 0), parent = base.aspect2d, text = ("Testing"), scale = 0.08, command = sys.exit) 
        self.hp.setPos(-1.25, 0) 
        #self.hp.setFrame(self.fram)
    
    def experiencia(self):
        pass
class ConsoleLog:
    def __init__(self, text, valid, archivable=True, auto_create=True):
        """
        @param text: What did they type in the console?
        @type text: str
        @param valid: Did the command work?
        @type valid: bool
        @param archivable: Should the log be retrievable via arrow keys?
        @type archivable: bool
        @param auto_create: Should the text of the log be auto created?
        @type auto_create: bool
        """
        self.text = text
        self.valid = valid
        self.log = None
        self.archivable = archivable
        if auto_create:
            self.create()

        if not valid and self.log is not None:
            self.log["fg"] = (1, 0, 0, 1)

    def create(self):
        self.log = OnscreenText(text=self.text,
                                fg=(1, 1, 1, 1),
                                pos=(-1.25, -.8),
                                align=TextNode.ALeft)

        if not self.archivable:
            self.log["pos"] = (self.log["pos"][0] + 0.05, self.log["pos"][1])
            self.log["fg"] = (.8, .8, .8, 1)

        if not self.valid:
            self.log["fg"] = (1, 0, 0, 1)

            if not self.archivable:
                self.log["fg"] = (.8, 0, 0, 1)

    def move_up(self):
        """
        Move the OnscreenText up
        """
        self.log.setPos(self.log.getPos()[0], self.log.getPos()[1] + 0.07)

    def destroy(self):
        self.log.destroy()
def load(args):
    """Sets up the GUI for the main menu.
    Arguments:
        This takes no arguments.
    """

    global backFrame
    global menuFrame
    global pauseText
    global backButton

    font_digital = loader.loadFont('digital.egg')

    backFrame = DirectFrame()
    backFrame['frameColor'] = (0, 0, 0, .5)
    backFrame['frameSize'] = (2, -2, 2, -2)
    backFrame.setPos(0, 0, 0)

    menuFrame = DirectFrame()
    menuFrame.reparentTo(backFrame)
    menuFrame['frameColor'] = (1, 1, 1, .5)
    menuFrame['frameSize'] = (.5, -.5, .5, -.5)
    menuFrame.setPos(0, 0, 0)

    pauseText = OnscreenText()
    pauseText['text'] = ('PAUSED')
    pauseText['scale'] = (.1)
    pauseText['font'] = (font_digital)
    pauseText['fg'] = (1, 1, 1, 1)
    pauseText.setPos(0, .9)

    backButton = DirectButton()
    backButton.reparentTo(menuFrame)
    backButton['text'] = ('Back')
    backButton['text_scale'] = (.1)
    backButton['text_pos'] = (0, -0.03)
    backButton['frameVisibleScale'] = (2, 0.5, 0)
    backButton['frameColor'] = (1, 1, 1, 0)
    backButton['command'] = (messenger.send)
    backButton['extraArgs'] = ("switch_gui", [gui.menu.pause_options, gui.menu.pause])
    backButton.setPos(0, 0, 0)
Beispiel #5
0
def test_onscreentext_text_pos():
    text = OnscreenText(pos=(1, 2))
    assert text['pos'] == (1, 2)
    assert text.pos == (1, 2)
    assert text.getPos() == (1, 2)
    assert text.text_pos == (1, 2)
    assert text.getTextPos() == (1, 2)
    assert text.get_pos() == (0, 0, 0)

    text.setTextPos(3, 4)
    assert text['pos'] == (3, 4)
    assert text.pos == (3, 4)
    assert text.getPos() == (3, 4)
    assert text.text_pos == (3, 4)
    assert text.getTextPos() == (3, 4)
    assert text.get_pos() == (0, 0, 0)

    text.text_pos = (7, 8)
    assert text['pos'] == (7, 8)
    assert text.pos == (7, 8)
    assert text.getPos() == (7, 8)
    assert text.text_pos == (7, 8)
    assert text.getTextPos() == (7, 8)
    assert text.get_pos() == (0, 0, 0)

    text.setPos(9, 10)
    assert text['pos'] == (9, 10)
    assert text.pos == (9, 10)
    assert text.getPos() == (9, 10)
    assert text.text_pos == (9, 10)
    assert text.getTextPos() == (9, 10)
    assert text.get_pos() == (0, 0, 0)

    text['pos'] = (11, 12)
    assert text['pos'] == (11, 12)
    assert text.pos == (11, 12)
    assert text.getPos() == (11, 12)
    assert text.text_pos == (11, 12)
    assert text.getTextPos() == (11, 12)
    assert text.get_pos() == (0, 0, 0)
Beispiel #6
0
class ScrollText():
    def __init__(self,
                 text='',
                 align=TextNode.ALeft,
                 scale=(1, 1),
                 font=None,
                 font_size=12,
                 parent=None,
                 frameColor=(0.33, 0.33, 0.33, .66),
                 frameSize=(0, 0.5, -1.0, 0)):
        if parent is None:
            parent = aspect2d
        self.parent = parent
        self.frame = DirectScrolledFrame(
            parent=parent,
            frameColor=frameColor,
            state=DGG.DISABLED,
            frameSize=frameSize,
            relief=DGG.FLAT,
            scrollBarWidth=scale[0] * font_size,
            horizontalScroll_relief=DGG.FLAT,
            verticalScroll_relief=DGG.FLAT,
        )
        self.text = OnscreenText(parent=self.frame.getCanvas(),
                                 text=text,
                                 align=align,
                                 scale=tuple(scale * font_size),
                                 font=font)
        bounds = self.text.getTightBounds()
        self.frame['canvasSize'] = [
            0, bounds[1][0] - bounds[0][0], -bounds[1][2] + bounds[0][2], 0
        ]
        self.text.setPos(-bounds[0][0], -bounds[1][2])
        self.frame.setPos(0, 0, 0)

    def destroy(self):
        self.frame.destroy()

    def reparent_to(self, parent):
        self.frame.reparent_to(parent)
Beispiel #7
0
class StageScreen(DirectObject.DirectObject):
    def __init__(self, callback = None):
        self.stageRoot = NodePath("stageSelectRoot")
        
        self.ps = PreviewStrip("../assets/stages" ,-0.7)
        self.ps.getStripNP().reparentTo(self.stageRoot)
        
        self.callback = callback
        # name of the stage will be displayed here
        self.text = OnscreenText("")
        self.text.reparentTo(self.stageRoot)
        self.text.setPos(0,self.ps.height - 0.4)
        
        self.preview_size = [-0.5,  0.5, -0.5, 0.5]
        
        self.generator = CardMaker("PreviewMaker") 
        self.generator.setFrame(*self.preview_size)
        
        self.preview = self.stageRoot.attachNewNode(self.generator.generate())
        self.preview.setPos(0,0, 0.4)
        # keys are read so that the first in the pair is from player 1
        # and second from the player 2, so that they both can decide
        self.keys = readKeys()
        self.left = [self.keys[0][1], self.keys[1][2]]
        self.right = [self.keys[0][3], self.keys[1][3]]
        self.select = [self.keys[0][4], self.keys[1][4]]
        
        self.ready = OnscreenText("ready")
        self.ready.reparentTo(self.stageRoot)
        self.ready.setPos(0,self.ps.height)
        # will be shown when players selected the stage
        self.ready.hide()
        # we notify ourselves to enable the key input and update text
        # and preview
        
        self.updateText()
        self.updateImg() 
        
        self.disableInput()
    
    def enableInput(self):
        self.accept( self.left[0], self.rotateLeft ) 
        self.accept( self.left[1], self.rotateLeft ) 
        self.accept( self.right[0], self.rotateRight ) 
        self.accept( self.right[1], self.rotateRight ) 
        self.accept( self.select[0], self.callback)
        self.accept( self.select[1], self.callback)
    
    def disableInput(self):
        for key in self.left + self.right + self.select:
            self.ignore(key) 
    
    def getNp(self):
        return self.stageRoot 
     
    def updateText(self):
        t = str(self.ps.current().getTexture().getFilename())
        self.text["text"] = t.split(sep)[-2] 
     
    def updateImg(self):
        self.preview.setTexture(self.ps.current().getTexture())

    def rotateRight(self):
        self.ps.rotateRight()
        self.updateText()
        self.updateImg()    
        
    def rotateLeft(self):
        self.ps.rotateLeft()
        self.updateText()
        self.updateImg()
    
    def hide(self):
        self.stageRoot.hide()
    
    def show(self):
        self.stageRoot.show()
        
    def getStage(self):
        # return path to stage acceptable by Match class
        t = str(self.ps.current().getTexture().getFilename()).rstrip("icon.jpg")
        return t + "stage"
Beispiel #8
0
class Game(ShowBase, Player, Walls):
    def __init__(self):
        ShowBase.__init__(self)
        Player.__init__(self)
        Walls.__init__(self)
        Road.__init__(self)

        self.all_car = []
        self.carN = 1
        self.car_y = [-6, -4, -2, 0, 2, 4, 6, 8, 10]
        self.car_x = [-25, 25]
        self.speed = [.1, .2, .3, .4]
        self.score = 0
        self.highscore = 0
        self.output = "Score: " + str(self.score)
        self.difficulty = .3
        self.font = loader.loadFont('Fonts/SigmarOne-Regular.ttf')
        self.collision = False

        self.env = loader.loadModel("Models/env.egg.pz")
        self.env.reparentTo(self.render)
        self.env.setScale(30)

        self.traverser = CollisionTraverser('traverser')
        base.cTrav = self.traverser
        self.colEvent = CollisionHandlerEvent()
        self.traverser.addCollider(self.player_collision, self.colEvent)
        self.colEvent.addInPattern("into-%in")
        self.colEvent.addOutPattern("out-%in")

        for name in ["Twall", "Bwall", "Rwall", "Lwall"]:
            self.accept(f"into-{name}", self.Check)
            self.accept(f"out-{name}", self.Out)

        base.setBackgroundColor(.1, .1, .1)
        base.disableMouse()
        camera.setPosHpr(0, -35, 20, 0, -30, 0)

        taskMgr.add(self.Move, "move_player")
        taskMgr.add(self.car_check, "car_check")
        self.carSeq = Sequence(Func(self.MakeCar), Wait(self.difficulty))
        self.carSeq.loop()

        self.text = OnscreenText(text=self.output,
                                 pos=(1, .9),
                                 scale=.1,
                                 mayChange=1,
                                 font=self.font,
                                 fg=(1, .5, 0, 1))
        self.idle.play()
        self.pause(False)

    def Check(self, coll):
        if coll.getIntoNodePath().getName() == "Twall":
            self.wOn = False
        if coll.getIntoNodePath().getName() == "Rwall":
            self.dOn = False
        if coll.getIntoNodePath().getName() == "Bwall":
            self.sOn = False
        if coll.getIntoNodePath().getName() == "Lwall":
            self.aOn = False

    def Out(self, coll):
        if coll.getIntoNodePath().getName() == "Twall":
            self.wOn = True
        if coll.getIntoNodePath().getName() == "Rwall":
            self.dOn = True
        if coll.getIntoNodePath().getName() == "Bwall":
            self.sOn = True
        if coll.getIntoNodePath().getName() == "Lwall":
            self.aOn = True

    def MakeCar(self):
        shuffle(self.car_y)
        shuffle(self.car_x)
        shuffle(self.speed)
        self.all_car.append(
            Car(self.speed[0], self.car_x[0], self.car_y[0], str(self.carN)))
        self.carN += 1

    def car_check(self, task):
        for car in self.all_car:
            if car.x < -25 or car.x > 25:
                self.all_car.remove(car)
                car.car.removeNode()
                taskMgr.remove('move_car' + car.car_num)
                self.score += 1
                self.output = "Score: " + str(self.score)
                self.text.setText(self.output)
            if not (self.collision):
                self.accept(f"into-{car.name}", self.collide_car)

        return Task.cont

    def collide_car(self, coll):
        for car in self.all_car:
            if car.carNode != coll.getIntoNodePath():
                car.car.removeNode()
            taskMgr.remove('move_car' + car.car_num)
        self.collision = True
        self.pause()

    def pause(self, coll=True):
        self.carSeq.pause()
        self.walk.stop()
        taskMgr.remove("move_player")
        if self.score > self.highscore:
            self.highscore = self.score
        self.text.setPos(10, 10)
        if coll:
            self.dead_text = OnscreenText(
                text=
                f"You Have Been Hit \n Score: {self.score} \n Highscore:  {self.highscore} \n \n \n Press R to play again \n Press F to exit",
                pos=(0, .4),
                scale=.1,
                mayChange=1,
                fg=(.1, .7, .1, 1),
                font=self.font)
        else:
            self.dead_text = OnscreenText(
                text=f"Dodge the Cars! \n \n Press R to start",
                pos=(0, .4),
                scale=.1,
                mayChange=1,
                fg=(0, .6, 1, 1),
                font=self.font)
        self.accept("r", self.un_pause)
        self.accept("f", self.exit)

    def un_pause(self):
        for car in self.all_car:
            car.car.removeNode()
        for car in self.all_car:
            self.all_car.remove(car)

        taskMgr.remove("pause")
        taskMgr.add(self.Move, "move_player")
        self.carSeq.resume()
        self.ignore("r")
        self.ignore("f")

        self.score = 0
        self.dead_text.remove_node()
        self.output = "Score: " + str(self.score)
        self.text.setText(self.output)
        self.text.setPos(1.1, .9)
        self.collision = False

    def exit(self):
        finalizeExit()
    def addLine(self, text, color):
        # Whilst in a battle, we don't want to display update text.
        if base.localAvatarReachable():
            place = base.cr.playGame.getPlace()

            if base.localAvatar.getBattleZone() or (
                    place and place.fsm.getCurrentState().getName() != 'walk'):
                self.queuedLines[text] = color
                return

        if len(self.lines) == self.MAX_LINES:
            oldestLine = self.lines[len(self.lines) - 1]
            ival = self.ivalDict.get(oldestLine, None)
            ival.finish()

        newLine = OnscreenText(parent=self,
                               text=text,
                               fg=color,
                               shadow=(color[0] * self.SHADOW_MODIFIER,
                                       color[1] * self.SHADOW_MODIFIER,
                                       color[2] * self.SHADOW_MODIFIER, 1.0),
                               mayChange=1,
                               font=CIGlobals.getMinnieFont())

        newLine.setPos(*self.LINE_MINIMUM_POS)

        initScale = (1.0, 1.0, 1.0)
        growScale = (1.15, 1.15, 1.15)
        """
        LerpScaleInterval(newLine, 0.5, 
            scale = initScale,
            blendType = 'easeIn',
            bakeInStart = 0),
        """

        lineIval = Sequence(
            Func(self.alertSfx.play),
            LerpScaleInterval(newLine,
                              0.5,
                              scale=initScale,
                              startScale=(0.01, 0.01, 0.01),
                              blendType='easeOut',
                              bakeInStart=0), Wait(0.5),
            Wait(self.SHOW_DURATION),
            Parallel(
                LerpPosInterval(newLine,
                                self.FADE_DURATION,
                                pos=(0.0, 0.0, (self.LINE_Y_OFFSET *
                                                (self.MAX_LINES + 1.8))),
                                blendType='easeIn',
                                bakeInStart=0,
                                other=self),
                LerpColorScaleInterval(newLine,
                                       self.FADE_DURATION - 0.5,
                                       (1.0, 1.0, 1.0, 0.01),
                                       blendType='easeIn')),
            Func(self.deleteLine, newLine))

        self.lines.insert(0, newLine)
        self.ivalDict.update({newLine: lineIval})

        for i in range(1, len(self.lines)):
            line = self.lines[i]

            if not line.isEmpty():
                # Let's reposition this element.
                line.setPos(
                    line.getX(),
                    self.LINE_MINIMUM_POS[1] + (self.LINE_Y_OFFSET * i))

        lineIval.start()
Beispiel #10
0
class GameTextBox(DirectObject, NodePath):
    '''游戏文本显示器类  Main displayer of current game text.
        继承自Panda3D的DirectFram
    Attributes:
        currentText: A list that includes current game text (see sogal_text's recordedText)
        currentSpeaker: A string that represents the speaker
        textFont: The font of the text
        properties: Properties of the text box. 
    '''
    def __init__(self):
        '''
        Constructor
        '''
        self.currentText = []
        self.currentSpeaker = ""
        self.newText = None
        self.textfont = None
        self.properties = copy.deepcopy(base.getStyle('textbox'))
        self._normal_speakerLabel = None
        self._normal_textLabel = None
        self._large_label = None
        self._frame = None
        self._textArrow = None
        self.__namescale = None

        NodePath.__init__(self, 'GameTextBox')
        self.reparentTo(aspect2d)
        self.reload()

    def presave(self):
        runtime_data.RuntimeData.current_text = [
            self.currentText, self.currentSpeaker
        ]

    def reload(self):
        if runtime_data.RuntimeData.gameTextBox_properties:  #this creates an reference
            self.properties = runtime_data.RuntimeData.gameTextBox_properties
        else:
            runtime_data.RuntimeData.gameTextBox_properties = self.properties

        self.applyStyle()

        if runtime_data.RuntimeData.current_text:
            if runtime_data.RuntimeData.current_text[0]:
                self.currentText = copy.copy(
                    runtime_data.RuntimeData.current_text[0])
                if self.currentTextLabel:
                    self.currentTextLabel.loadRecordedText(
                        runtime_data.RuntimeData.current_text[0])
            if runtime_data.RuntimeData.current_text[1]:
                self.currentSpeaker = runtime_data.RuntimeData.current_text[1]
                if self._normal_speakerLabel:
                    self._normal_speakerLabel.setText(
                        runtime_data.RuntimeData.current_text[1])

    def reloadTheme(self):
        self.properties = copy.deepcopy(base.getStyle('textbox'))
        runtime_data.RuntimeData.gameTextBox_properties = self.properties
        self.applyStyle()

    def showArrow(self):
        if self._textArrow:
            if self.currentTextLabel:
                '''
                self._textArrow.setPos(self._frame.getWidth()/2-self.properties['arrow_rightspace'],
                             0,
                             self.currentTextLabel.textNode.getLowerRight3d()[2]-0.03)
                '''
                apos = self._frame.getRelativePoint(
                    self.currentTextLabel, self.currentTextLabel.getEndPos())
                apos = (self._frame.getWidth() / 2 -
                        self.properties['arrow_rightspace'], 0, apos[2])
                self._textArrow.setPos(apos)
            else:
                self._textArrow.setPos(0, 0, 0)
            self._textArrow.show()

    def hideArrow(self):
        if self._textArrow:
            self._textArrow.hide()

    def quickFinish(self):
        '''Finish the current text typer quickly
        '''
        if self.currentTextLabel:
            self.currentTextLabel.quickFinish()

    def destroyElements(self):
        self.currentText = []
        self.currentSpeaker = None
        self.newText = ''

        if self._textArrow:
            self._textArrow.removeNode()
            self._textArrow = None

        if self._normal_textLabel:
            self._normal_textLabel.destroy()
            self._normal_textLabel = None

        if self._normal_speakerLabel:
            self._normal_speakerLabel.destroy()
            self._normal_speakerLabel = None

        if self._frame:
            self._frame.destroy()
            self._frame = None

        if self._large_label:
            self._large_label.destroy()
            self._large_label = None

    def destroy(self, *args, **kwargs):
        if self.currentTextLabel:
            self.currentTextLabel.destroy
        if self._frame:
            self._frame.destroy()
            self._frame = None

    def clearText(self):
        '''make current text empty'''

        self.currentText = []
        self.currentSpeaker = None
        self.newText = ''

        if self.currentTextLabel:
            self.currentTextLabel.clear()
        if self._currentStyle == GameTextBoxStyle.Normal and self._normal_speakerLabel:
            self._normal_speakerLabel.setText('')

    def pushText(self,
                 text,
                 speaker=None,
                 continuous=False,
                 text_speed=None,
                 fadein=None,
                 rate=1.0,
                 read=False):
        '''添加文字
        进行判断并改变文字
        parameters:
            speaker: A string contains the speaker's name. (None means no speaker)
            read: see if the text is already read
        '''
        if self.currentTextLabel and self.currentTextLabel.isWaiting():
            self.currentTextLabel.quickFinish()

        #The text is necessary
        if not text:
            return

        text = text.rstrip('\n')

        text_speed = (text_speed or base.getStyle('textbox')['text_speed']
                      or runtime_data.game_settings['text_speed']) * rate
        if fadein is None:
            fadein = base.getStyle('textbox')['text_fadein_duration']
        fadein_style = base.getStyle('textbox')['text_fadein_style']

        if self._currentStyle == GameTextBoxStyle.Normal:
            if not continuous:
                self.currentTextLabel.clear()
        elif self._currentStyle == GameTextBoxStyle.Large:
            if not continuous and self.currentTextLabel.hasContent():
                self.currentTextLabel.appendText(
                    '\n')  #Inserting an empty line

        if continuous:  #When continuous, ignore the speaker
            speaker = None
            #self.currentSpeaker = ''
        else:
            self.currentSpeaker = speaker

        if self._currentStyle == GameTextBoxStyle.Normal:
            if not continuous:
                if speaker:
                    self._normal_speakerLabel.setText(
                        self.currentSpeaker)  #TODO: use SogalText
                else:
                    self._normal_speakerLabel.setText(' ')
        elif self._currentStyle == GameTextBoxStyle.Large:
            if speaker:
                self.currentTextLabel.appendText(self.currentSpeaker,
                                                 custom=True,
                                                 newLine=True,
                                                 textScale=self.__namescale)

        self.newText = text

        #This is *very* useful
        safeprint(self.newText)

        if not read:
            self.currentTextLabel.appendText(self.newText,
                                             speed=text_speed,
                                             newLine=(not continuous),
                                             fadein=fadein,
                                             fadeinType=fadein_style)
        else:
            self.currentTextLabel.appendText(self.newText,
                                             speed=text_speed,
                                             newLine=(not continuous),
                                             fadein=fadein,
                                             fadeinType=fadein_style,
                                             custom=True,
                                             fg=self.properties['read_fg'])

        self.currentText = self.currentTextLabel.getCopiedText()

        #TODO: FADING TEXT AND TYPER AGAIN

    _currentStyle = None

    @property
    def currentStyle(self):
        '''Style of this box
        '''
        return self._currentStyle

    @property
    def currentTextLabel(self):
        '''current text label
        '''
        if self._currentStyle == GameTextBoxStyle.Normal:
            return self._normal_textLabel
        elif self._currentStyle == GameTextBoxStyle.Large:
            return self._large_label

    def applyStyle(self):
        '''套用风格 Apply style setting.
        override this to apply your own style
        '''
        #        窝才想起来这是引用不是浅拷贝……所以构造函数中运行这个就能同步runtime_data了lol
        #         if runtime_data.RuntimeData.gameTextBox_properties:
        #             self.properties = runtime_data.RuntimeData.gameTextBox_properties
        #         else: runtime_data.RuntimeData.gameTextBox_properties = self.properties

        self.destroyElements()

        if self.properties.has_key('style'):
            self.setTextBoxStyle(self.properties['style'])
        else:
            self.setTextBoxStyle('normal')

        st = self._currentStyle

        if st == GameTextBoxStyle.Normal:
            height = self.properties['normal_height']
            width = self.properties['normal_width']

            self._frame = DirectFrame(
                parent=self,
                frameSize=(-width / 2.0, width / 2.0, -height / 2.0,
                           height / 2.0),
                frameColor=self.properties['background_color'],
            )

            if self.currentSpeaker:
                speaker = self.currentSpeaker
            else:
                speaker = ''

            self._normal_speakerLabel = OnscreenText(
                parent=self._frame,
                text=speaker,
                font=base.textFont,
                fg=self.properties['foreground_color'],
                mayChange=True  # @UndefinedVariable
                ,
                align=TextNode.ALeft  #@UndefinedVariable
                ,
                scale=self.properties['normal_name_scale'])

            self._normal_textLabel = SogalText(
                parent=self._frame,
                font=base.textFont,
                fg=self.properties['foreground_color'],
                scale=self.properties['normal_text_scale'],
                shadow=(0.1, 0.1, 0.1, 0.5),
                pos=(-width / 2.0 + self.properties['normal_text_pos'][0], 0,
                     height / 2.0 + self.properties['normal_text_pos'][1]),
                wordwrap=self.properties['normal_text_wrap'])

            self.setPos(self.properties['normal_pos'][0], 0,
                        self.properties['normal_pos'][1])

            self._normal_speakerLabel.setPos(
                -width / 2.0 + self.properties['normal_name_pos'][0],
                height / 2.0 + self.properties['normal_name_pos'][1])

            self._normal_speakerLabel.setShadow((0.1, 0.1, 0.1, 0.5))

            self._normal_textLabel.textMaker.setTabWidth(1.0)

        elif st == GameTextBoxStyle.Large:

            self.__namescale = self.properties[
                'large_name_scale'] / self.properties['large_text_scale']

            height = self.properties['large_height']
            width = self.properties['large_width']

            self._frame = DirectFrame(
                parent=self,
                frameSize=(-width / 2.0, width / 2.0, -height / 2.0,
                           height / 2.0),
                frameColor=self.properties['background_color'],
            )

            self._large_label = SogalText(
                parent=self._frame,
                font=base.textFont,
                fg=self.properties['foreground_color'],
                scale=self.properties['large_text_scale'],
                shadow=(0.1, 0.1, 0.1, 0.5),
                pos=(-width / 2.0 + self.properties['large_text_pos'][0], 0,
                     height / 2.0 + self.properties['large_text_pos'][1]),
                wordwrap=self.properties['large_text_wrap'])

            self.setPos(self.properties['large_pos'][0], 0,
                        self.properties['large_pos'][1])

            self._large_label.textMaker.setTabWidth(1.0)

        #generate an arrow after text
        arrow = loader.loadModel(
            'models/text_arrow/text_arrow')  # @UndefinedVariable
        arrow.reparentTo(self._frame)
        arrow.setColor(self.properties['arrow_color'])
        arrow.setScale(self.properties['arrow_scale'])
        width = 2.0
        if self._currentStyle == GameTextBoxStyle.Normal:
            width = self.properties['normal_width']
        elif self._currentStyle == GameTextBoxStyle.Large:
            width = self.properties['large_width']

        self._textArrow = arrow
        self._textArrow.hide()

    def setTextBoxStyle(self, style):
        if style.strip() == 'normal':
            self._currentStyle = GameTextBoxStyle.Normal
        elif style.strip() == 'large':
            self._currentStyle = GameTextBoxStyle.Large
        else:
            safeprint('Unknown style: ' + str(style))
        self.properties['style'] = style

    def paragraphSparator(self):
        #if self._currentStyle == GameTextBoxStyle.Large:
        self.clearText()

    def setTextBoxProperty(self, propname, value):
        runtime_data.RuntimeData.gameTextBox_properties[propname] = value

    def applyTextBoxProperties(self):
        self.applyStyle()

    def getIsWaitingForText(self):
        is_waiting = False

        if self.currentTextLabel:
            is_waiting = self.currentTextLabel.isWaiting()

        return is_waiting

    def getIsWaiting(self):
        '''Inherited from GameTextBoxBase
        Get whether the text typer is unfinished
        '''
        return self.getIsWaitingForText()
class MyApp(ShowBase):
    """Test class for the all the uses cases for the EasingMgr class."""

    def __init__(self):
        ShowBase.__init__(self)

        base.disableMouse()
        base.setBackgroundColor(.2, .2, .2)

        camera.setPos(0, 0, 45)
        camera.setHpr(0, -90, 0)

        self.curr_ease = [(easeClass[8], easeType[1]),
                          (easeClass[8], easeType[1]),
                          (easeClass[8], easeType[1])]
        self.curr_param = easeParam[2]

        self._labs = []

        self.param_lab = OnscreenText(text=self.curr_param,
                                      pos=(-1.3, .9),
                                      scale=0.07,
                                      fg=(0.8, 0.8, 0.8, 1),
                                      align=TextNode.ALeft,
                                      mayChange=1)

        self.controls = OnscreenText(text='Controls: \n' +
          '   [p] Change paramter. \n' +
          '   [q, a, z] Change ease mode (x, y, z).\n' +
          '   [w, s, x] Change ease type (x,y, z).\n' +
          '   [spacebar] Start the transition.\n' +
          '   [esc] Quit.',
                                     pos=(-1.3, -.7),
                                     scale=0.055,
                                     fg=(0.8, 0.8, 0.8, 1),
                                     align=TextNode.ALeft)

        for i in range(3):
            row = []
            row.append(OnscreenText(text=axis[i],
                                    pos=(-.9, .9 - (i*.1)),
                                    scale=0.07,
                                    fg=(0.8, 0.8, 0.8, 1),
                                    align=TextNode.ALeft,
                                    mayChange=1))
            row.append(OnscreenText(text=self.curr_ease[i][0],
                                    pos=(-.8, .9 - (i*.1)),
                                    scale=0.07,
                                    fg=(0.8, 0.8, 0.8, 1),
                                    align=TextNode.ALeft,
                                    mayChange=1))

            row.append(OnscreenText(text=self.curr_ease[i][1],
                                    pos=(-.6, .9 - (i*.1)),
                                    scale=0.07,
                                    fg=(0.8, 0.8, 0.8, 1),
                                    align=TextNode.ALeft,
                                    mayChange=1))
            self._labs.append(row)

        self._node = None

        self._ease_values = {'position3D': [(-8.0, -3.0, 10.0),
                                            (15.0, 3.0, -20.0)],
                             'position2D': [(-.7, -.3), (.7, .3)],
                             'scale1D': [[.08], [.20]],
                             'scale3D': [(1.0, 1.0, 1.0), (4.0, 4.0, 4.0)]}

        self.end_time = 1.0

        self.accept('escape', sys.exit, [0])
        self.input_setup(True)

        self.__easingMgr = EasingMgr()
        self.__curr_tr = None

        self.__change_param(0)

    def input_setup(self, activate):
        if activate:
            self.accept('q-up', self.__change_class, extraArgs=[0, 1])
            self.accept('a-up', self.__change_class, extraArgs=[1, 1])
            self.accept('z-up', self.__change_class, extraArgs=[2, 1])
            self.accept('w-up', self.__change_type, extraArgs=[0, 1])
            self.accept('s-up', self.__change_type, extraArgs=[1, 1])
            self.accept('x-up', self.__change_type, extraArgs=[2, 1])

            self.accept('p-up', self.__change_param, extraArgs=[1])
            self.accept('space-up', self.start_ease)
            self.accept('escape', sys.exit, [0])
        else:
            self.ignoreAll()

    def start_ease(self):
        self.input_setup(False)
        self.__easingMgr.start_transition(self.__curr_tr)

    def check_finished(self):
        if not self.__curr_tr.is_updating:
            self.input_setup(True)

    def __change_class(self, row, incr):
        self.curr_ease[row] = (easeClass[
            (easeClass.index(self.curr_ease[row][0]) + incr) % len(easeClass)],
            self.curr_ease[row][1])
        self._labs[row][1].setText(self.curr_ease[row][0])
        self.change_transition()

    def __change_type(self, row, incr):
        self.curr_ease[row] = (self.curr_ease[row][0], easeType[
            (easeType.index(self.curr_ease[row][1]) + incr) % len(easeType)])
        self._labs[row][2].setText(self.curr_ease[row][1])
        self.change_transition()

    def __change_param(self, incr):
        self.curr_param = easeParam[
            (easeParam.index(self.curr_param) + incr) % len(easeParam)]
        self.param_lab.setText(self.curr_param)
        self.release_nodes()
        if self.curr_param in ['position2D', 'scale1D']:
            self.load_text()
        if self.curr_param in ['position3D', 'scale3D']:
            self.load_sphere()
        if '1D' in self.curr_param:
            for i, row in enumerate(self._labs):
                if i < 1:
                    for lab in row:
                        lab.show()
                else:
                    for lab in row:
                        lab.hide()

        if '2D' in self.curr_param:
            for i, row in enumerate(self._labs):
                if i < 2:
                    for lab in row:
                        lab.show()
                else:
                    for lab in row:
                        lab.hide()
        if '3D' in self.curr_param:
            for i, row in enumerate(self._labs):
                for lab in row:
                    lab.show()
        self.change_transition()

    def change_transition(self):
        if self.__curr_tr:
            self.__easingMgr.remove_transition(self.__curr_tr)

        values = self._ease_values[self.curr_param]
        self.__curr_tr = self.__easingMgr.add_transition(self._node,
                                                         self.curr_param,
                                                         self.curr_ease,
                                                         self.end_time,
                                                         values,
                                                         self.check_finished)

    def load_text(self):
        self._node = OnscreenText(text='Fantastic text',
                                  pos=(self._ease_values['position2D'][0]),
                                  scale=self._ease_values['scale1D'][0][0])

    def load_sphere(self):
        self._node = loader.loadModel("assets/planet_sphere")
        self._node.reparentTo(render)
        self._node.setScale(self._ease_values['scale3D'][0][0],
                            self._ease_values['scale3D'][0][1],
                            self._ease_values['scale3D'][0][2])
        self._node.setPos(self._ease_values['position3D'][0][0],
                          self._ease_values['position3D'][0][1],
                          self._ease_values['position3D'][0][2])
        self._node_tex = loader.loadTexture("assets/earth.jpg")
        self._node.setTexture(self._node_tex, 1)

    def release_nodes(self):
        if self._node:
            self._node.removeNode()
            self._node = None
class VirtualWorld(ShowBase):
    def __init__(self, scene_file, pedestrian_file, dir, mode):
        ShowBase.__init__(self)

        self.globalClock = ClockObject.getGlobalClock()
        self.globalClock.setMode(ClockObject.MSlave)

        self.directory = dir
        self.model = Model(dir)
        self.loadScene(scene_file)
        self.loadPedestrians(pedestrian_file)

        self.cam_label = OST("Top Down",
                             pos=(0, 0.95),
                             fg=(1, 1, 1, 1),
                             scale=0.05,
                             mayChange=True)
        self.time_label = OST("Time: 0.0",
                              pos=(-1.3, 0.95),
                              fg=(1, 1, 1, 1),
                              scale=0.06,
                              mayChange=True,
                              align=TextNode.ALeft)

        self.accept("arrow_right", self.changeCamera, [1])
        self.accept("arrow_left", self.changeCamera, [-1])
        self.accept("escape", self.exit)
        self.accept("aspectRatioChanged", self.setAspectRatio)
        self.accept("window-event", self.windowChanged)

        #base.disableMouse()
        lens = OrthographicLens()
        lens.setFilmSize(1550, 1000)
        self.display_region = base.win.makeDisplayRegion()
        self.default_camera = render.attachNewNode(Camera("top down"))
        self.default_camera.node().setLens(lens)
        self.default_camera.setPosHpr(Vec3(-75, 0, 2200), Vec3(0, -90, 0))

        self.setCamera(0)

        self.controller = Controller(self, mode)
        self.taskMgr.add(self.updateCameraModules, "Update Camera Modules", 80)

        self.globalClock.setFrameTime(0.0)
        self.width = WIDTH
        self.height = HEIGHT

        props = WindowProperties()
        props.setTitle('Virtual Vision Simulator')
        base.win.requestProperties(props)

    def getModel(self):
        """
        Returns the model that stores all of the cameras, pedestrians and 
        static objects in the scene.
        """
        return self.model

    def getController(self):
        """
        Returns a controller that is used to control the world time.
        """
        return self.controller

    def getTime(self):
        """
        Returns the current time in the world.
        """
        return self.globalClock.getFrameTime()

    def loadScene(self, scene_file):
        """
        Loads the static objects that make up the scene. Also loads the lights
        that illuminate the scene and for performance implications, sets what 
        lights affect what objects.
        """
        if not os.path.exists(scene_file):
            logging.error("The path '%s' does not exist" % scene_file)
            sys.exit()
        light_builder = LightBuilder(self)
        object_builder = ObjectBuilder(self, self.directory)
        parser = SceneFileParser(self.model, object_builder, light_builder)
        parser.parse(scene_file)

        self.setUpLights()

    def setUpLights(self):
        # Set what lights illuminate what objects
        light_list = self.model.getLightList()
        static_objects = self.model.getObjectList()
        for object in static_objects:
            if object.hasLighting():
                model_root = object.getModel().getChildren()[0]
                children = model_root.getChildren()
                for child in children:
                    light_map = {}
                    for index, light in enumerate(light_list):
                        distance = Length(child.getPos(render), light.getPos())
                        half_fov = light.node().getLens().getFov()[0] / 2.0
                        height = light.getPos()[2]
                        radius = height * tan(radians(half_fov))
                        if distance > radius**2 + 2500 + 10:
                            continue
                        if distance not in light_map:
                            light_map[distance] = [index]
                        else:
                            light_map[distance].append(index)

                    sorted_lights = sorted(light_map.keys())
                    light_count = 0
                    for key in sorted_lights:
                        for i in light_map[key]:
                            child.setLight(light_list[i])
                            light_count += 1
                            if light_count > LIGHTS_PER_OBJECT:
                                break
                        if light_count > LIGHTS_PER_OBJECT:
                            break
                    child.flattenStrong()

        # Apply a directional light to the static models
        light_list = self.model.getLightList(DIRECTIONALLIGHT)
        if light_list:
            for object in static_objects:
                if object.hasLighting():
                    model_root = object.getModel().getChildren()[0]
                    model_root.setLight(light_list[0])

        render.setShaderAuto()
        render.setAntialias(AntialiasAttrib.MLine)

    def loadPedestrians(self, pedestrian_file):
        """Loads the pedestrians into the scene."""
        if not os.path.exists(pedestrian_file):
            logging.error("The path '%s' does not exist" % pedestrian_file)
            sys.exit()
        pedestrian_builder = PedestrianBuilder(self, "../media/characters/")
        parser = PedestrianFileParser(self.model, pedestrian_builder)
        parser.parse("../media/characters/pedestrians.xml")
        parser.parse(pedestrian_file)

    def addCamera(self, config):
        """
        This method is used to add a new panda camera to the world. The panda
        camera is returned so that it can be linked with a camera module.
        """
        type = config.type
        cam_builder = PandaCameraBuilder(self)
        if type == WIDE_FOV_CAMERA:
            pass
        else:
            camera = cam_builder.buildPandaPTZCamera(config)
            self.model.addCamera(camera)
        return camera

    def setAspectRatio(self):
        """
        This method is called when the aspect ratio of the window changes.
        It updates the aspect ratios of all the cameras.
        """
        width = base.win.getXSize()
        height = base.win.getYSize()
        ratio = self.camLens.getAspectRatio()
        camera_list = self.model.getCameraList()
        for camera in camera_list:
            camera.setAspectRatio(ratio)
            camera.setImageSize(width, height)

        self.default_camera.node().getLens().setAspectRatio(ratio)
        r = width / float(height)
        self.time_label.setPos(-r, 0.95)

    def changeCamera(self, num):
        """
        This method is used to toggle the camera that is viewed in the main 
        window. Typically num is either 1 or -1 denoting whether to toggle up
        or down the camera list.
        """
        number = self.cur_camera + 1 + num
        num_cameras = len(self.model.getCameraList())
        if number > num_cameras:
            number = 0
        elif number < 0:
            number = num_cameras
        self.setCamera(number)

    def setCamera(self, num):
        """
        This method sets which cameras view is shown in the panda3d window.
        """
        if MANUAL_CAMERA:
            self.cur_camera = num - 1
            return

        self.display_region.setClearColor(VBase4(0, 0, 0, 1))
        self.display_region.setClearColorActive(True)
        self.display_region.setClearDepthActive(True)
        if num == 0:
            self.cur_camera = -1
            self.display_region.setCamera(self.default_camera)
            self.cam_label.setText("Top Down")
        else:
            camera_list = self.model.getCameraList()
            index = num - 1
            if index < len(camera_list):
                self.cur_camera = index
                camera = camera_list[index]
                camera_np = camera.getCameraNode()
                self.display_region.setCamera(camera_np)
                name = camera.getName()
                status_label = camera.getStatusLabel()
                label = "%s: %s" % (name, status_label)
                self.cam_label.setText(label)

    def step(self, increment):
        """
        This method updates the world by one time step.
        """
        if increment:
            new_time = self.globalClock.getFrameTime() + increment
        else:
            new_time = self.globalClock.getRealTime()

        self.globalClock.setFrameTime(new_time)
        self.time_label.setText("Time: %.2f" % new_time)

        self.updateActors()
        self.updateCameras()

    def updateActors(self):
        """
        This method updates the pedestrians in the scene by calling their update
        functions.
        """
        pedestrians = self.model.getPedestrianList()
        time = self.getTime()
        for pedestrian in pedestrians:
            if pedestrian.isActive(time):
                pedestrian.update(time)

    def updateCameras(self):
        """
        This method updates the panda cameras which are used to provide the
        higher level camera modules with rendered images of the scene. There
        is one panda camera for each camera module.
        """
        time = self.getTime()
        camera_list = self.model.getCameraList()
        for camera in camera_list:
            camera.update(time)

        if self.cur_camera != -1:
            cur_camera = camera_list[self.cur_camera]
            if cur_camera.statusChanged():
                name = cur_camera.getName()
                status_label = cur_camera.getStatusLabel()
                label = "%s: %s" % (name, status_label)
                self.cam_label.setText(label)

    def updateCameraModules(self, task):
        """
        This method updates the camera modules by calling their update function.
        This allows the camera modules to process messages and complete any
        tasks that were assigned to them.
        """
        time = self.getTime()
        for camera in self.model.getCameraModules():
            camera.update(time)
        return Task.cont

    def windowChanged(self, window):
        """
        This function is called when the window is modified. It updates the
        image size used by the cameras when getting the rendered image from the 
        texture.
        """
        wp = window.getProperties()
        width = wp.getXSize()
        height = wp.getYSize()
        if width != self.width or height != self.height:
            self.width = width
            self.height = height
            camera_list = self.model.getCameraList()
            for camera in camera_list:
                camera.setImageSize(width, height)
        self.windowEvent(window)

    def exit(self):
        sys.exit()
Beispiel #13
0
class GameApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.viewDistanceChunks = 4
        self.viewDistance = (self.viewDistanceChunks + 0.5) * CHUNK_SIDE

        self.visibleChunksXY = set()
        self.visibleChunks = {}
        self.chunksForLoader = {}

        # Disable the camera trackball controls.
        self.disableMouse()

        self.camAngleA = 0
        self.camAngleB = 0

        self.currChunkXY = (None, None)
        self.currChunk = None

        self.accept('arrow_left', self.evtArrowLeft)
        self.accept('arrow_left-repeat', self.evtArrowLeft)
        self.accept('arrow_right', self.evtArrowRight)
        self.accept('arrow_right-repeat', self.evtArrowRight)
        self.accept('arrow_up', self.evtArrowUp)
        self.accept('arrow_up-repeat', self.evtArrowUp)
        self.accept('arrow_down', self.evtArrowDown)
        self.accept('arrow_down-repeat', self.evtArrowDown)
        self.accept('w', self.evtForward)
        self.accept('w-repeat', self.evtForward)
        self.accept('s', self.evtBack)
        self.accept('s-repeat', self.evtBack)
        self.accept('i', self.render.analyze)

        self.dirtTexture = self.loader.loadTexture("textures/blocks/dirt.png")
        self.dirtTexture.setMagfilter(Texture.FTNearest)
        self.dirtTexture.setMinfilter(Texture.FTLinearMipmapLinear)

        self.waterTexture = self.loader.loadTexture(
            "textures/blocks/water.jpg")
        self.waterTexture.setMagfilter(Texture.FTNearest)
        self.waterTexture.setMinfilter(Texture.FTLinearMipmapLinear)

        self.xyzInfo = OnscreenText(text="text",
                                    align=TextNode.ALeft,
                                    parent=pixel2d,
                                    fg=(1, 1, 1, 1),
                                    bg=(0, 0, 0, 0.7))
        self.xyzInfo.setScale(18, 20)
        self.xyzInfo.setPos(5, -20)

        #self.messenger.toggleVerbose()

        self.setFrameRateMeter(True)
        #self.chunkLoaderThread = threading.Thread(target=chunkLoader)
        #self.chunkLoaderThread.start()

        taskMgr.doMethodLater(0.01, self.refreshChunksTask,
                              'refreshChunksTask')
        taskMgr.setupTaskChain('chunkLoaderTaskChain', numThreads=1)

        bgColor = (0.3, 0.5, 1)
        self.setBackgroundColor(*bgColor)
        self.initFog(bgColor)
        self.camLens.setFar(self.viewDistance)

        self.setCamPos(CHUNK_SIDE / 2, CHUNK_SIDE / 2, 32)

        dlight = DirectionalLight('dlight')
        dlight.setColor(VBase4(0.8, 0.8, 0.5, 1))
        dlnp = render.attachNewNode(dlight)
        dlnp.setHpr(-30, -60, 0)
        render.setLight(dlnp)

        alight = AmbientLight('alight')
        alight.setColor(VBase4(0.4, 0.4, 0.4, 1))
        alnp = render.attachNewNode(alight)
        render.setLight(alnp)

    def initFog(self, color):
        self.fog = Fog("fog")
        self.fog.setColor(*color)
        self.fog.setLinearRange(self.viewDistance * 0.8, self.viewDistance)
        self.render.setFog(self.fog)

    @staticmethod
    def coordConvert(angA, angB, l):
        angA = radians(90 + angA)
        angB = radians(90 - angB)
        x = sin(angB) * cos(angA) * l
        y = sin(angB) * sin(angA) * l
        z = cos(angB) * l
        return x, y, z

    #----------Events--------------
    def evtArrowLeft(self):
        self.camAngleA += 1

        if self.camAngleA > 180:
            self.camAngleA = -179

        self.camera.setH(self.camAngleA)

    def evtArrowRight(self):
        self.camAngleA -= 1

        if self.camAngleA < -179:
            self.camAngleA = 180

        self.camera.setH(self.camAngleA)

    def evtArrowUp(self):
        self.camAngleB += 1

        if self.camAngleB > 90:
            self.camAngleB = 90

        self.camera.setP(self.camAngleB)

    def evtArrowDown(self):
        self.camAngleB -= 1

        if self.camAngleB < -90:
            self.camAngleB = -90

        self.camera.setP(self.camAngleB)

    def evtForward(self):
        dx, dy, dz = self.coordConvert(self.camAngleA, self.camAngleB, 0.2)
        x, y, z = self.camera.getPos()
        self.setCamPos(x + dx, y + dy, z + dz)

    def evtBack(self):
        dx, dy, dz = self.coordConvert(self.camAngleA, self.camAngleB, -0.2)
        x, y, z = self.camera.getPos()
        self.setCamPos(x + dx, y + dy, z + dz)

    #------------------------------
    def setCamPos(self, x, y, z):
        self.camera.setPos(x, y, z)

        chunkXY = (int(floor(x / CHUNK_SIDE)), int(floor(y / CHUNK_SIDE)))
        if chunkXY != self.currChunkXY:
            self.setCurrChunk(chunkXY)

        self.xyzInfo.setText("x=%2.2f\ny=%2.2f\nz=%2.2f" % (x, y, z))

    def setCurrChunk(self, chunkXY):
        print chunkXY
        self.currChunkXY = chunkXY
        self.updateVisibleChunkSet()

    @staticmethod
    def loadChunk(chunkXY):
        return Chunk(chunkXY)

    def createVisibleChunkList(self):

        currChunkX, currChunkY = self.currChunkXY

        viewDistSquare = (self.viewDistanceChunks + 1)**2
        #chunkList = filter( lambda xy : xy[0]**2 + xy[1]**2 <=  viewDistSquare,
        #                    product(xrange(-self.viewDistanceChunks, self.viewDistanceChunks + 1),
        #                            xrange(-self.viewDistanceChunks, self.viewDistanceChunks + 1)))
        chunkList = product(
            xrange(-self.viewDistanceChunks, self.viewDistanceChunks + 1),
            xrange(-self.viewDistanceChunks, self.viewDistanceChunks + 1))

        def maxXY(xy1, xy2):
            x1, y1 = xy1
            x2, y2 = xy2
            max1 = max(abs(x1), abs(y1))
            max2 = max(abs(x2), abs(y2))
            return cmp(max1, max2)

        chunkList = [(x + currChunkX, y + currChunkY)
                     for x, y in sorted(chunkList, maxXY)]

        return chunkList

    def updateVisibleChunkSet(self):
        self.visibleChunksXY = self.createVisibleChunkList()
        self.chunkRefreshNeeded = True

    def refreshChunksTask(self, task):
        if not self.chunkRefreshNeeded:
            return task.again

        if taskMgr.hasTaskNamed('chunkLoaderTask'):
            return task.again

        self.chunkRefreshNeeded = False

        print "thinking..."

        chunksToUnload = {}
        oldVisibleChunks = self.visibleChunks
        self.visibleChunks = {}

        for xy, chunk in oldVisibleChunks.iteritems():
            if isinstance(chunk, Chunk):
                if xy in self.visibleChunksXY:
                    self.visibleChunks[xy] = chunk
                else:
                    chunksToUnload[xy] = chunk
                    chunk.hide()
                    chunk.setFree(True)

        chunksToLoadXY = set()

        for xy in self.visibleChunksXY:
            if not self.visibleChunks.has_key(xy):
                chunk = self.chunksForLoader.get(xy, None)
                if isinstance(chunk, Chunk):
                    chunk.show(self)
                    self.visibleChunks[xy] = chunk
                    del self.chunksForLoader[xy]
                else:
                    if len(chunksToLoadXY) <= 2:
                        chunksToLoadXY.add(xy)

        for xy, chunk in self.chunksForLoader.iteritems():
            chunk.setFree(True)

        for xy, chunk in chunksToUnload.iteritems():
            self.chunksForLoader[xy] = chunk

        for xy in chunksToLoadXY:

            self.chunksForLoader[xy] = True

        taskMgr.add(self.chunkLoaderTask,
                    'chunkLoaderTask',
                    taskChain='chunkLoaderTaskChain')

        print "end of thinking"

        return task.again

    def chunkLoaderTask(self, task):
        print "loader Task"

        for xy, chunk in self.chunksForLoader.items():
            if chunk == True:
                newChunk = Chunk(xy)
                self.chunksForLoader[xy] = newChunk
                self.chunkRefreshNeeded = True
            elif isinstance(chunk, Chunk) and chunk.getFree():
                chunk.unload()
                del self.chunksForLoader[xy]
            else:
                print "chunkLoaderTask:unexpected chunk"

        print "loader Task end"
        return Task.done
Beispiel #14
0
class KubikiApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.viewDistanceChunks = 4
        self.viewDistance = (self.viewDistanceChunks + 0.5) * CHUNK_SIDE

        self.visibleChunksXY = set()
        self.visibleChunks = {}
        self.chunksForLoader = {}

        # Disable the camera trackball controls.
        self.disableMouse()

        self.camAngleA = 0
        self.camAngleB = 0

        self.currChunkXY = (None, None)
        self.currChunk = None

        self.accept('arrow_left', self.evtArrowLeft)
        self.accept('arrow_left-repeat', self.evtArrowLeft)
        self.accept('arrow_right', self.evtArrowRight)
        self.accept('arrow_right-repeat', self.evtArrowRight)
        self.accept('arrow_up', self.evtArrowUp)
        self.accept('arrow_up-repeat', self.evtArrowUp)
        self.accept('arrow_down', self.evtArrowDown)
        self.accept('arrow_down-repeat', self.evtArrowDown)
        self.accept('w', self.evtForward)
        self.accept('w-repeat', self.evtForward)
        self.accept('s', self.evtBack)
        self.accept('s-repeat', self.evtBack)
        self.accept('i', self.render.analyze)

        self.texture = self.loader.loadTexture("dirt.png")
        self.texture.setMagfilter(Texture.FTNearest)
        self.texture.setMinfilter(Texture.FTLinearMipmapLinear)

        self.xyzInfo = OnscreenText(text="text",
                                    align=TextNode.ALeft,
                                    parent=pixel2d,
                                    fg=(1, 1, 1, 1),
                                    bg=(0, 0, 0, 0.7))
        self.xyzInfo.setScale(18, 20)
        self.xyzInfo.setPos(5, -20)

        #self.messenger.toggleVerbose()

        self.setFrameRateMeter(True)
        #self.chunkLoaderThread = threading.Thread(target=chunkLoader)
        #self.chunkLoaderThread.start()

        taskMgr.doMethodLater(0.01, self.refreshChunksTask,
                              'refreshChunksTask')
        taskMgr.setupTaskChain('chunkLoaderTaskChain', numThreads=1)

        bgColor = (0.3, 0.5, 1)
        self.setBackgroundColor(*bgColor)
        self.initFog(bgColor)
        self.camLens.setFar(self.viewDistance)

        self.setCamPos(CHUNK_SIDE / 2, CHUNK_SIDE / 2, 32)

        dlight = DirectionalLight('dlight')
        dlight.setColor(VBase4(0.8, 0.8, 0.5, 1))
        dlnp = render.attachNewNode(dlight)
        dlnp.setHpr(-30, -60, 0)
        render.setLight(dlnp)

        alight = AmbientLight('alight')
        alight.setColor(VBase4(0.4, 0.4, 0.4, 1))
        alnp = render.attachNewNode(alight)
        render.setLight(alnp)

    def initFog(self, color):
        self.fog = Fog("fog")
        self.fog.setColor(*color)
        self.fog.setLinearRange(self.viewDistance * 0.8, self.viewDistance)
        self.render.setFog(self.fog)

    @staticmethod
    def coordConvert(angA, angB, l):
        #Преобразование из системы коородинат Panda3d в координаты для формулы
        angA = radians(90 + angA)
        angB = radians(90 - angB)
        x = sin(angB) * cos(angA) * l
        y = sin(angB) * sin(angA) * l
        z = cos(angB) * l
        return x, y, z

    #----------Events--------------
    def evtArrowLeft(self):
        self.camAngleA += 1

        if self.camAngleA > 180:
            self.camAngleA = -179

        self.camera.setH(self.camAngleA)

    def evtArrowRight(self):
        self.camAngleA -= 1

        if self.camAngleA < -179:
            self.camAngleA = 180

        self.camera.setH(self.camAngleA)

    def evtArrowUp(self):
        self.camAngleB += 1

        if self.camAngleB > 90:
            self.camAngleB = 90

        self.camera.setP(self.camAngleB)

    def evtArrowDown(self):
        self.camAngleB -= 1

        if self.camAngleB < -90:
            self.camAngleB = -90

        self.camera.setP(self.camAngleB)

    def evtForward(self):
        dx, dy, dz = self.coordConvert(self.camAngleA, self.camAngleB, 0.2)
        x, y, z = self.camera.getPos()
        self.setCamPos(x + dx, y + dy, z + dz)

    def evtBack(self):
        dx, dy, dz = self.coordConvert(self.camAngleA, self.camAngleB, -0.2)
        x, y, z = self.camera.getPos()
        self.setCamPos(x + dx, y + dy, z + dz)

    #------------------------------
    def setCamPos(self, x, y, z):
        self.camera.setPos(x, y, z)

        chunkXY = (int(floor(x / CHUNK_SIDE)), int(floor(y / CHUNK_SIDE)))
        if chunkXY != self.currChunkXY:
            self.setCurrChunk(chunkXY)

        self.xyzInfo.setText("x=%2.2f\ny=%2.2f\nz=%2.2f" % (x, y, z))

    def setCurrChunk(self, chunkXY):
        print chunkXY
        self.currChunkXY = chunkXY
        self.updateVisibleChunkSet()

    @staticmethod
    def loadChunk(chunkXY):
        return Chunk(chunkXY)

    def createVisibleChunkList(self):

        currChunkX, currChunkY = self.currChunkXY

        #Создаём список смещений чанков от текущего, и фильтруем его через функцию чтобы скруглить
        #слишком удалённые углы
        viewDistSquare = (self.viewDistanceChunks + 1)**2
        #chunkList = filter( lambda xy : xy[0]**2 + xy[1]**2 <=  viewDistSquare,
        #                    product(xrange(-self.viewDistanceChunks, self.viewDistanceChunks + 1),
        #                            xrange(-self.viewDistanceChunks, self.viewDistanceChunks + 1)))
        chunkList = product(
            xrange(-self.viewDistanceChunks, self.viewDistanceChunks + 1),
            xrange(-self.viewDistanceChunks, self.viewDistanceChunks + 1))

        def maxXY(xy1, xy2):
            x1, y1 = xy1
            x2, y2 = xy2
            max1 = max(abs(x1), abs(y1))
            max2 = max(abs(x2), abs(y2))
            return cmp(max1, max2)

        chunkList = [(x + currChunkX, y + currChunkY)
                     for x, y in sorted(chunkList, maxXY)]

        return chunkList

    def updateVisibleChunkSet(self):
        #Новый массив с видимыми чанками
        self.visibleChunksXY = self.createVisibleChunkList()
        self.chunkRefreshNeeded = True

    def refreshChunksTask(self, task):
        if not self.chunkRefreshNeeded:
            return task.again

        if taskMgr.hasTaskNamed('chunkLoaderTask'):
            return task.again

        self.chunkRefreshNeeded = False

        print "thinking..."

        chunksToUnload = {}
        oldVisibleChunks = self.visibleChunks
        self.visibleChunks = {}

        #Старые видимые чанки переносим в новые или готовим к выгрузке
        for xy, chunk in oldVisibleChunks.iteritems():
            if isinstance(chunk, Chunk):
                if xy in self.visibleChunksXY:
                    self.visibleChunks[xy] = chunk
                else:
                    chunksToUnload[xy] = chunk
                    chunk.hide()
                    chunk.setFree(True)

        chunksToLoadXY = set()

        #Недостающие чанки получаем из загруженных или готовим задание на загрузку
        for xy in self.visibleChunksXY:
            if not self.visibleChunks.has_key(xy):
                chunk = self.chunksForLoader.get(xy, None)
                if isinstance(chunk, Chunk):
                    chunk.show(self)
                    self.visibleChunks[xy] = chunk
                    del self.chunksForLoader[xy]
                else:
                    if len(chunksToLoadXY) <= 2:
                        chunksToLoadXY.add(xy)

        #Загруженные, но ненужные чанки - на выгрузку

        for xy, chunk in self.chunksForLoader.iteritems():
            chunk.setFree(True)

        #Задание на выгрузку
        for xy, chunk in chunksToUnload.iteritems():
            self.chunksForLoader[xy] = chunk

        #Задание на загрузку
        for xy in chunksToLoadXY:

            self.chunksForLoader[xy] = True

        #Запускаем задачу загрузки-выгрузки
        taskMgr.add(self.chunkLoaderTask,
                    'chunkLoaderTask',
                    taskChain='chunkLoaderTaskChain')

        print "end of thinking"

        return task.again

    def chunkLoaderTask(self, task):
        """
        Запускается при необходимости загрузить-выгрузить чанки.
        Выполняется в отдельном потоке
        """
        print "loader Task"

        for xy, chunk in self.chunksForLoader.items():
            if chunk == True:
                #Грузим новый чанк
                newChunk = Chunk(xy)
                self.chunksForLoader[xy] = newChunk
                self.chunkRefreshNeeded = True
            elif isinstance(chunk, Chunk) and chunk.getFree():
                #Выгружаем ненужный чанк
                chunk.unload()
                del self.chunksForLoader[xy]
            else:
                print "chunkLoaderTask:unexpected chunk"

        print "loader Task end"
        return Task.done
Beispiel #15
0
class SkillShotScreen(GameScreen):

    awards = [
        "QUICK FREEZE", "ADVANCE BONUS X", "5000 POINTS", "SPOT MTL",
        "QUICK FREEZE", "500,000 POINTS", "LIGHT CLAW"
    ]

    current_side = 1
    current_award = 0
    cube = None
    _awardText = None
    cubeMovement = None
    cubeRotation = None
    awardMovement = None
    SKILLSHOT_THRESHOLD = 2.34726002216

    def __init__(self, screen_manager):
        super(SkillShotScreen, self).__init__(screen_manager,
                                              "skillshot_screen")

        # Load our trunk model
        self.cube = base.loader.loadModel("assets/models/powerup.egg")
        # Set its position to:
        # X: -0.4 (just to the left of h-center)
        # Y: 40 (way far back away from the viewer)
        # Z: 0 (vertically center)
        self.cube.setPos(11, 40, 0)
        # Set the scaling size of the trunk
        self.cube.setScale(0.05, 0.05, 0.05)

        if base.displayFlipped:
            self.cube.setAttrib(
                CullFaceAttrib.make(CullFaceAttrib.MCullCounterClockwise))

        # Insert the trunk into this screen's rendering tree
        self.cube.reparentTo(self.node)
        """
        # Set up a splotlight to project onto the trunk
        self.dlight = Spotlight('my dlight')
        # Associate the spotlight to the rendering system
        self.dlnp = render.attachNewNode(self.dlight)
        # Set this trunk's light explicitly so it only takes light from this light
        self.cube.setLight(self.dlnp)
        self.dlnp.lookAt(self.cube)
        
        plight = PointLight('plight')
        plight.setColor(VBase4(1, 1, 1, 1))
        self.plnp = render.attachNewNode(plight)
        self.plnp.setPos(11, 35, 12)
        """

        self.dlight = DirectionalLight('dlight')
        self.dlight.setColor(VBase4(1, 1, 1, 1))
        self.dlnp = render.attachNewNode(self.dlight)
        self.dlnp.setHpr(0, -60, 0)
        self.dlnp.lookAt(self.cube)

        self.obj = DirectObject()

        self.movement_speed = 0.7
        """
        self.explosion = Sprite(
                                parent=self.node, 
                                file_name="assets/sprites/explosion/explosion_", 
                                file_type="png", 
                                num_frames=29, 
                                int_padding=2,
                                scale=(5,5,5))
        """

        self.explosion = Sprite(
            parent=self.node,
            file_name="assets/sprites/blue_explosion/blue_explosion_",
            file_type="png",
            num_frames=13,
            int_padding=2,
            scale=(5, 5, 5))
        #0.6 - high
        #-0.4 - low
        self._awardText = OnscreenText(
            "RANDOM AWARD",
            1,
            font=base.fontLoader.load('digital.ttf'),
            fg=((0.0 / 255.0), (255.0 / 255.0), (255.0 / 255.0), 1),
            pos=(1, -0.4),
            align=TextNode.ACenter,
            scale=.1,
            mayChange=True,
            parent=self.node2d)

        self.cubeRotation = self.cube.hprInterval(1.2, Vec3(360, 0, 0))
        # Set up a sequence to perform the animation in, pause and out... "sequentially"
        self.cubeMovement = Sequence(
            # Lerp stands for "linearly interpolate", so we move from one position to the other with
            # an 'easeOut' blend so it comes to a nice slow stop at the end instead of an abrupt finish
            LerpPosInterval(self.cube,
                            self.movement_speed,
                            pos=(13, 40, 11),
                            startPos=(13, 40, 0),
                            blendType='easeOut'),
            # Animate back to our home position (off screen) with an ease in so it starts moving gradually
            LerpPosInterval(self.cube,
                            self.movement_speed,
                            pos=(13, 40, 0),
                            blendType='easeIn'))
        self.awardMovement = Sequence(
            LerpFunc(self._updateAwardTextPosition,
                     fromData=-0.4,
                     toData=0.6,
                     duration=self.movement_speed,
                     blendType='easeOut',
                     extraArgs=[],
                     name=None),
            LerpFunc(self._updateAwardTextPosition,
                     fromData=0.6,
                     toData=-0.4,
                     duration=self.movement_speed,
                     blendType='easeIn',
                     extraArgs=[],
                     name=None))

    def _updateAwardTextPosition(self, t):
        self._awardText.setPos(1, t)

    def show(self):
        """
        Overridden method that is invoked when the screen is shown.
        
        We use this to orient our camera and spotlights to the appropriate place. We do this because
        not every screen has its own camera. I suppose we could do that in the future the same way that
        each screen has its own 2d and 3d nodes.
        """

        # Set the camera a bit up in the air (vertically, not moving forward. Just straight up)
        base.camera.setZ(9.6)
        # Set the pitch negatively a bit so we can look down upon the trunk
        base.camera.setP(-5)

        # Call our base class show method now so it can render anything it wants
        super(SkillShotScreen, self).show()

        # Fire off the sequence
        self.cubeMovement.loop()
        self.cubeRotation.loop()
        self.awardMovement.loop()
        base.taskMgr.doMethodLater(0.1, self._advanceAward, 'award_advance')

        self.cube.setLight(self.dlnp)
        random.shuffle(self.awards)
        self.obj.ignoreAll()
        self.obj.acceptOnce("skillshot_hit", self.stop_skillshot_motion)
        self.cube.show()
        self._awardText.show()

    def stop_skillshot_motion(self):

        self.explosion = Sprite(
            parent=self.node,
            file_name="assets/sprites/blue_explosion/blue_explosion_",
            file_type="png",
            num_frames=13,
            int_padding=2,
            scale=(5, 5, 5))

        self.cubeRotation.pause()
        self.cubeMovement.pause()
        self.awardMovement.pause()
        base.taskMgr.remove('award_advance')
        self.cube.hide()
        self._awardText.hide()
        self.explosion.setPos(self.cube.getX() - 0.50, 40, self.cube.getZ())
        self.explosion.fps = 24
        self.explosion.play(loops=1)
        # -0.3550 is the threshold
        if self.cube.getZ() <= self.SKILLSHOT_THRESHOLD:

            base.screenManager.showModalMessage(
                message=self.awards[self.current_award],
                time=5.0,
                font="eurostile.ttf",
                scale=0.08,
                bg=(0, 0, 0, 1),
                fg=(0, 1, 1, 1),
                frame_color=(0, 1, 1, 1),
                blink_speed=0.015,
                blink_color=(0, 0, 0, 1),
                #l r t b
                frame_margin=(0.1, 0.25, 0, 0),
                animation='slide',
                start_location=(1.7, 0, 0.8),
                end_location=(1, 0, 0.8))

    def is_skillshot_hit(self):
        if self.cube.getZ() <= self.SKILLSHOT_THRESHOLD:
            return self.awards[self.current_award]
        else:
            return False

    def _advanceAward(self, task):
        self.current_award = (self.current_award + 1) % len(self.awards)
        self._awardText.setText(self.awards[self.current_award])
        return task.again

    def hide(self):
        """
        Called when the screen manager wants to remove this screen from the display.
        
        We have no choice but to obey when this method is called. So hide our background.
        
        Our models will be hidden automatically as the 3d nodes are removed from the render tree
        """
        super(SkillShotScreen, self).hide()

        if self.cube != None: self.cube.clearLight(self.dlnp)
        if self.cubeMovement: self.cubeMovement.finish()
        if self.cubeRotation: self.cubeRotation.finish()
        if self.awardMovement: self.awardMovement.finish()
        base.taskMgr.remove('award_advance')
        if self._awardText != None: self._awardText.hide()
Beispiel #16
0
class GameTextBox(DirectObject, NodePath):
    '''游戏文本显示器类  Main displayer of current game text.
        继承自Panda3D的DirectFram
    Attributes:
        currentText: A list that includes current game text (see sogal_text's recordedText)
        currentSpeaker: A string that represents the speaker
        textFont: The font of the text
        properties: Properties of the text box. 
    '''
    

    
    def __init__(self):
        '''
        Constructor
        '''
        self.currentText = []
        self.currentSpeaker = ""
        self.newText = None
        self.textfont = None
        self.properties = copy.deepcopy(base.getStyle('textbox'))
        self._normal_speakerLabel = None
        self._normal_textLabel = None
        self._large_label = None
        self._frame = None
        self._textArrow = None
        self.__namescale = None
        
        NodePath.__init__(self, 'GameTextBox')
        self.reparentTo(aspect2d)
        self.reload()
    
    def presave(self):
        runtime_data.RuntimeData.current_text = [self.currentText, self.currentSpeaker]
                    
    def reload(self):
        if runtime_data.RuntimeData.gameTextBox_properties: #this creates an reference
            self.properties = runtime_data.RuntimeData.gameTextBox_properties
        else: runtime_data.RuntimeData.gameTextBox_properties = self.properties
        
        self.applyStyle()
        
        if runtime_data.RuntimeData.current_text:
            if runtime_data.RuntimeData.current_text[0]:
                self.currentText = copy.copy(runtime_data.RuntimeData.current_text[0]) 
                if self.currentTextLabel:
                    self.currentTextLabel.loadRecordedText(runtime_data.RuntimeData.current_text[0])
            if runtime_data.RuntimeData.current_text[1]:
                self.currentSpeaker = runtime_data.RuntimeData.current_text[1]
                if self._normal_speakerLabel:
                    self._normal_speakerLabel.setText(runtime_data.RuntimeData.current_text[1])
                    
    def reloadTheme(self):
        self.properties = copy.deepcopy(base.getStyle('textbox'))
        runtime_data.RuntimeData.gameTextBox_properties = self.properties
        self.applyStyle()
    
    def showArrow(self):
        if self._textArrow: 
            if self.currentTextLabel:
                '''
                self._textArrow.setPos(self._frame.getWidth()/2-self.properties['arrow_rightspace'],
                             0,
                             self.currentTextLabel.textNode.getLowerRight3d()[2]-0.03)
                '''
                apos = self._frame.getRelativePoint(self.currentTextLabel, self.currentTextLabel.getEndPos())
                apos = (self._frame.getWidth()/2-self.properties['arrow_rightspace'],
                        0,
                        apos[2])
                self._textArrow.setPos(apos)
            else: self._textArrow.setPos(0,0,0)
            self._textArrow.show()
            
    def hideArrow(self):
        if self._textArrow:
            self._textArrow.hide()
    
            
    def quickFinish(self):
        '''Finish the current text typer quickly
        '''
        if self.currentTextLabel:
            self.currentTextLabel.quickFinish()

    def destroyElements(self):
        self.currentText = []
        self.currentSpeaker = None
        self.newText = ''

        
        if self._textArrow:
            self._textArrow.removeNode()
            self._textArrow = None
        
        if self._normal_textLabel:
            self._normal_textLabel.destroy()
            self._normal_textLabel = None
            
        if self._normal_speakerLabel:
            self._normal_speakerLabel.destroy()
            self._normal_speakerLabel = None
            
        if self._frame:
            self._frame.destroy()
            self._frame = None
            
        if self._large_label:
            self._large_label.destroy()
            self._large_label = None
            

        
    def destroy(self, *args, **kwargs):
        if self.currentTextLabel:
            self.currentTextLabel.destroy
        if self._frame:
            self._frame.destroy()
            self._frame = None
 
    def clearText(self):
        '''make current text empty'''

        self.currentText = []
        self.currentSpeaker = None
        self.newText = ''
        
        if self.currentTextLabel:
            self.currentTextLabel.clear()
        if self._currentStyle == GameTextBoxStyle.Normal and self._normal_speakerLabel:
            self._normal_speakerLabel.setText('')
            
        
    
    def pushText(self, text, speaker = None, continuous = False, text_speed = None, fadein = None, rate = 1.0,read = False):
        '''添加文字
        进行判断并改变文字
        parameters:
            speaker: A string contains the speaker's name. (None means no speaker)
            read: see if the text is already read
        '''
        if self.currentTextLabel and self.currentTextLabel.isWaiting():
            self.currentTextLabel.quickFinish()
        
        #The text is necessary
        if not text:
            return
        
        text = text.rstrip('\n')
        
        text_speed = (text_speed or base.getStyle('textbox')['text_speed'] or runtime_data.game_settings['text_speed']) * rate
        if fadein is None:
            fadein = base.getStyle('textbox')['text_fadein_duration']
        fadein_style = base.getStyle('textbox')['text_fadein_style']
        
        if self._currentStyle == GameTextBoxStyle.Normal:
            if not continuous:
                self.currentTextLabel.clear()
        elif self._currentStyle == GameTextBoxStyle.Large:
            if not continuous and self.currentTextLabel.hasContent():
                self.currentTextLabel.appendText('\n') #Inserting an empty line
       

        if continuous:    #When continuous, ignore the speaker
            speaker = None  
            #self.currentSpeaker = ''
        else:
            self.currentSpeaker = speaker
        
        if self._currentStyle == GameTextBoxStyle.Normal:
            if not continuous:
                if speaker:
                    self._normal_speakerLabel.setText(self.currentSpeaker) #TODO: use SogalText
                else:
                    self._normal_speakerLabel.setText(' ')
        elif self._currentStyle == GameTextBoxStyle.Large:
            if speaker:
                self.currentTextLabel.appendText(self.currentSpeaker,custom = True, newLine = True, 
                                                 textScale = self.__namescale)
                

        self.newText = text
        
        #This is *very* useful
        safeprint(self.newText)
        
        if not read:
            self.currentTextLabel.appendText(self.newText, speed = text_speed , newLine = (not continuous) , fadein = fadein, 
                                                 fadeinType = fadein_style)
        else:
            self.currentTextLabel.appendText(self.newText, speed = text_speed , newLine = (not continuous) , fadein = fadein, 
                                                 fadeinType = fadein_style, custom = True, fg = self.properties['read_fg'])            
        
        self.currentText = self.currentTextLabel.getCopiedText()
        
        #TODO: FADING TEXT AND TYPER AGAIN

    
    _currentStyle = None
    @property
    def currentStyle(self):
        '''Style of this box
        '''
        return self._currentStyle
    
    @property
    def currentTextLabel(self):
        '''current text label
        '''
        if self._currentStyle == GameTextBoxStyle.Normal:
            return self._normal_textLabel
        elif self._currentStyle == GameTextBoxStyle.Large:
            return self._large_label
    
    def applyStyle(self):
        '''套用风格 Apply style setting.
        override this to apply your own style
        '''
#        窝才想起来这是引用不是浅拷贝……所以构造函数中运行这个就能同步runtime_data了lol
#         if runtime_data.RuntimeData.gameTextBox_properties:  
#             self.properties = runtime_data.RuntimeData.gameTextBox_properties
#         else: runtime_data.RuntimeData.gameTextBox_properties = self.properties
        
        self.destroyElements()
        
        if self.properties.has_key('style'):
            self.setTextBoxStyle(self.properties['style'])
        else: self.setTextBoxStyle('normal')
            
        st = self._currentStyle
        
        if st == GameTextBoxStyle.Normal:
            height = self.properties['normal_height']
            width = self.properties['normal_width']
            
            
            self._frame = DirectFrame(
                    parent      = self,
                    frameSize   = (-width/2.0,width/2.0,-height/2.0,height/2.0),
                    frameColor  = self.properties['background_color'],
                    )
            
            if self.currentSpeaker:
                speaker = self.currentSpeaker
            else: speaker = ''
            
            self._normal_speakerLabel = OnscreenText(parent = self._frame
                                      , text = speaker
                                      , font = base.textFont
                                      , fg = self.properties['foreground_color']
                                      , mayChange = True  # @UndefinedVariable
                                      , align = TextNode.ALeft#@UndefinedVariable
                                      , scale = self.properties['normal_name_scale']
                                      )  
            
            self._normal_textLabel = SogalText(parent = self._frame,
                                               font = base.textFont,
                                               fg = self.properties['foreground_color'],
                                               scale = self.properties['normal_text_scale'],
                                               shadow = (0.1,0.1,0.1,0.5),
                                               pos = (-width/2.0 + self.properties['normal_text_pos'][0],
                                                      0,
                                                      height/2.0 + self.properties['normal_text_pos'][1]),
                                               wordwrap = self.properties['normal_text_wrap']
                                               )  
            

            self.setPos(self.properties['normal_pos'][0],0,self.properties['normal_pos'][1])
            
            
            self._normal_speakerLabel.setPos(-width/2.0 + self.properties['normal_name_pos'][0], 
                                          height/2.0 + self.properties['normal_name_pos'][1])
    
            self._normal_speakerLabel.setShadow((0.1,0.1,0.1,0.5))
            
            self._normal_textLabel.textMaker.setTabWidth(1.0)
            
            
        elif st == GameTextBoxStyle.Large:
            
           
            self.__namescale = self.properties['large_name_scale']/self.properties['large_text_scale']
            
            height = self.properties['large_height']
            width = self.properties['large_width']
              
            self._frame = DirectFrame(
                    parent      = self,
                    frameSize   = (-width/2.0,width/2.0,-height/2.0,height/2.0),
                    frameColor  = self.properties['background_color'],
                    )
            
            self._large_label = SogalText(parent = self._frame,
                                          font = base.textFont,
                                          fg = self.properties['foreground_color'],
                                          scale = self.properties['large_text_scale'],
                                          shadow = (0.1,0.1,0.1,0.5),
                                          pos = (-width/2.0 + self.properties['large_text_pos'][0],
                                                 0,
                                                 height/2.0 + self.properties['large_text_pos'][1]),
                                          wordwrap = self.properties['large_text_wrap']
                                         )  
            

            self.setPos(self.properties['large_pos'][0],0,self.properties['large_pos'][1])
            
            
    
            
            self._large_label.textMaker.setTabWidth(1.0)
           
        #generate an arrow after text 
        arrow = loader.loadModel('models/text_arrow/text_arrow')  # @UndefinedVariable
        arrow.reparentTo(self._frame)
        arrow.setColor(self.properties['arrow_color'])
        arrow.setScale(self.properties['arrow_scale'])
        width = 2.0
        if self._currentStyle == GameTextBoxStyle.Normal:
            width = self.properties['normal_width']
        elif self._currentStyle == GameTextBoxStyle.Large:
            width = self.properties['large_width']

        self._textArrow = arrow
        self._textArrow.hide()

    def setTextBoxStyle(self, style):
        if style.strip() == 'normal':
            self._currentStyle = GameTextBoxStyle.Normal
        elif style.strip() == 'large':
            self._currentStyle = GameTextBoxStyle.Large
        else: safeprint('Unknown style: ' + str(style))
        self.properties['style'] = style
        
        


    def paragraphSparator(self):
        #if self._currentStyle == GameTextBoxStyle.Large:
        self.clearText()

    def setTextBoxProperty(self, propname, value):
        runtime_data.RuntimeData.gameTextBox_properties[propname] = value

    def applyTextBoxProperties(self):
        self.applyStyle()
       
            
    def getIsWaitingForText(self):
        is_waiting = False
        
        if self.currentTextLabel:
            is_waiting = self.currentTextLabel.isWaiting()
        
        return is_waiting
    
    
    def getIsWaiting(self):
        '''Inherited from GameTextBoxBase
        Get whether the text typer is unfinished
        '''
        return self.getIsWaitingForText()


        


        
Beispiel #17
0
def load(args):
    """Sets up the GUI for the in game pause menu.
    Arguments:
        args[0] -- The function for the 'resume' button.
        args[1] -- The function for the 'settings' button.
        args[2] -- The function for the 'exit' button.
    """
    # GUI should do what they are told, they should get data sent to them, not request it.

    global pauseText
    global backFrame
    global menuFrame
    global resumeButton

    font_digital = loader.loadFont("digital.egg")

    backFrame = DirectFrame()
    backFrame["frameSize"] = (2, -2, 2, -2)
    backFrame.setPos(0, 0, 0)

    backFrame["frameColor"] = (0, 0, 0, 0.5)
    menuFrame = DirectFrame()
    menuFrame.reparentTo(backFrame)
    menuFrame["frameColor"] = (1, 1, 1, 0.5)
    menuFrame["frameSize"] = (0.5, -0.5, 0.5, -0.5)
    menuFrame.setPos(0, 0, 0)

    buttonClickSound = loader.loadSfx("sound/buttonClick.wav")
    buttonRollSound = loader.loadSfx("sound/buttonRoll.wav")

    resumeButton = DirectButton()
    resumeButton.reparentTo(menuFrame)
    resumeButton["text"] = "Resume"
    resumeButton["text_scale"] = 0.1
    resumeButton["text_pos"] = (0, -0.03)
    resumeButton["frameVisibleScale"] = (2, 0.5, 0)
    resumeButton["frameColor"] = (1, 1, 1, 0)
    resumeButton["command"] = resume
    resumeButton["rolloverSound"] = buttonRollSound
    resumeButton["clickSound"] = buttonClickSound
    resumeButton.setPos(0, 0, 0.4)

    settingsButton = DirectButton()
    settingsButton.reparentTo(menuFrame)
    settingsButton["text"] = "Settings"
    settingsButton["text_scale"] = 0.1
    settingsButton["text_pos"] = (0, -0.03)
    settingsButton["frameVisibleScale"] = (2, 0.5, 0)
    settingsButton["frameColor"] = (1, 1, 1, 0)
    settingsButton["rolloverSound"] = buttonRollSound
    settingsButton["clickSound"] = buttonClickSound
    settingsButton["command"] = messenger.send  # Command to run
    settingsButton["extraArgs"] = ("switch_gui", [gui.menu.pause, gui.menu.pause_options])  # Args to send
    settingsButton.setPos(0, 0, 0.2)

    exitButton = DirectButton()
    exitButton.reparentTo(menuFrame)
    exitButton["text"] = "Exit"
    exitButton["text_scale"] = 0.1
    exitButton["text_pos"] = (0, -0.03)
    exitButton["frameVisibleScale"] = (2, 0.5, 0)
    exitButton["frameColor"] = (1, 1, 1, 0)
    exitButton["rolloverSound"] = buttonRollSound
    exitButton["clickSound"] = buttonClickSound
    exitButton["command"] = exit
    exitButton.setPos(0, 0, 0)

    pauseText = OnscreenText()
    pauseText["text"] = "PAUSED"
    pauseText["scale"] = 0.1
    pauseText["font"] = font_digital
    pauseText["fg"] = (1, 1, 1, 1)
    pauseText.setPos(0, 0.9)
Beispiel #18
0
class Window():
    texture = None

    def __init__(self,
                 title,
                 scale,
                 parent=None,
                 child=None,
                 transparent=False,
                 owner=None):
        self.scale = scale
        self.owner = owner
        self.last_pos = None
        self.title_text = title
        self.title_color = (1, 1, 1, 1)
        self.title_pad = tuple(self.scale * 2)
        if parent is None:
            parent = aspect2d
        self.parent = parent
        if transparent:
            frameColor = (0, 0, 0, 0)
        else:
            frameColor = (0, 0, 0, 1)
        self.pad = 0
        #         if Window.texture is None:
        #             Window.texture = loader.loadTexture('textures/futureui1.png')
        #         image_scale = (scale[0] * Window.texture.get_x_size(), 1, scale[1] * Window.texture.get_y_size())
        self.frame = DirectFrame(
            parent=parent, state=DGG.NORMAL, frameColor=frameColor
        )  #, image=self.texture, image_scale=image_scale)
        self.title_frame = DirectFrame(parent=self.frame,
                                       state=DGG.NORMAL,
                                       frameColor=(.5, .5, .5, 1))
        self.title = OnscreenText(text=self.title_text,
                                  style=Plain,
                                  fg=self.title_color,
                                  scale=tuple(self.scale * 14),
                                  parent=self.title_frame,
                                  pos=(0, 0),
                                  align=TextNode.ALeft,
                                  font=None,
                                  mayChange=True)
        bounds = self.title.getTightBounds()
        self.title_frame['frameSize'] = [
            0, bounds[1][0] - bounds[0][0] + self.title_pad[0] * 2, 0,
            bounds[1][2] - bounds[0][2] + self.title_pad[1] * 2
        ]
        self.title.setPos(-bounds[0][0] + self.title_pad[0],
                          -bounds[0][2] + self.title_pad[1])
        self.close_frame = DirectFrame(parent=self.frame,
                                       state=DGG.NORMAL,
                                       frameColor=(.5, .5, .5, 1))
        self.close = OnscreenText(text='X',
                                  style=Plain,
                                  fg=self.title_color,
                                  scale=tuple(self.scale * 14),
                                  parent=self.close_frame,
                                  pos=(0, 0),
                                  align=TextNode.ACenter,
                                  font=None,
                                  mayChange=True)
        bounds = self.close.getTightBounds()
        self.close_frame['frameSize'] = [
            0, bounds[1][0] - bounds[0][0] + self.title_pad[0] * 2,
            self.title_frame['frameSize'][2], self.title_frame['frameSize'][3]
        ]
        self.close.setPos(-bounds[0][0] + self.title_pad[0],
                          -bounds[0][2] + self.title_pad[1])
        self.frame.setPos(0, 0, 0)
        self.title_frame.bind(DGG.B1PRESS, self.start_drag)
        self.title_frame.bind(DGG.B1RELEASE, self.stop_drag)
        self.close_frame.bind(DGG.B1PRESS, self.close_window)
        self.set_child(child)

    def set_child(self, child):
        if child is not None:
            self.child = child
            child.reparent_to(self.frame)
            self.update()

    def update(self):
        if self.child is not None:
            frame_size = self.child.frame['frameSize']
            if frame_size is not None:
                frame_size[0] -= self.pad
                frame_size[1] += self.pad
                frame_size[2] += self.pad
                frame_size[3] -= self.pad
            self.frame['frameSize'] = frame_size
        if self.frame['frameSize'] is not None:
            width = self.frame['frameSize'][1] - self.frame['frameSize'][0]
            title_size = self.title_frame['frameSize']
            title_size[0] = 0
            title_size[1] = width
            self.title_frame['frameSize'] = title_size
            self.close_frame.setPos(width - self.close_frame['frameSize'][1],
                                    0, 0)

    def start_drag(self, event):
        if base.mouseWatcherNode.has_mouse():
            mpos = base.mouseWatcherNode.get_mouse()
            self.drag_start = self.frame.parent.get_relative_point(
                render2d, Point3(mpos.get_x(), 0,
                                 mpos.get_y())) - self.frame.getPos()
            taskMgr.add(self.drag, "drag", -1)

    def drag(self, task):
        if base.mouseWatcherNode.has_mouse():
            mpos = base.mouseWatcherNode.get_mouse()
            current_pos = self.frame.parent.get_relative_point(
                render2d, Point3(mpos.get_x(), 0, mpos.get_y()))
            self.frame.set_pos(current_pos - self.drag_start)
        return task.again

    def close_window(self, event=None):
        if self.owner is not None:
            self.owner.window_closed(self)
        self.destroy()

    def stop_drag(self, event):
        taskMgr.remove("drag")
        self.last_pos = self.frame.getPos()

    def destroy(self):
        if self.frame is not None:
            self.frame.destroy()
        self.frame = None

    def getPos(self):
        return self.frame.getPos()

    def setPos(self, pos):
        self.frame.setPos(pos)
Beispiel #19
0
class VisualizerApp(ShowBase):

    FOV = 90
    VIEW_DISTANCE_CHUNKS = 5

    def __init__(self, level, chunks):
        ShowBase.__init__(self)

        self.level = level

        self.disableMouse()

        wp = WindowProperties()
        #wp.setFullscreen(True)
        wp.setCursorHidden(True)
        wp.setMouseMode(WindowProperties.M_relative)
        #wp.setSize(800, 500)
        self.win.requestProperties(wp)

        self.camLens.setFov(VisualizerApp.FOV)

        self.keyMap = {
            'forward': 0,
            'backward': 0,
            'left': 0,
            'right': 0,
            'shift': 0
        }

        self.setBackgroundColor(0.53, 0.80, 0.92, 1)

        self.accept('escape', sys.exit)
        self.accept("a", self.set_key, ["left", True])
        self.accept("d", self.set_key, ["right", True])
        self.accept("w", self.set_key, ["forward", True])
        self.accept("s", self.set_key, ["backward", True])
        self.accept('lshift', self.set_key, ['shift', True])
        self.accept("a-up", self.set_key, ["left", False])
        self.accept("d-up", self.set_key, ["right", False])
        self.accept("w-up", self.set_key, ["forward", False])
        self.accept("s-up", self.set_key, ["backward", False])
        self.accept('lshift-up', self.set_key, ['shift', False])

        self.cameraMovementTask = taskMgr.add(self.camera_movement, "CameraMovement")
        self.cameraRotationTask = taskMgr.add(self.camera_rotation, 'CameraRotation')

        self.position_text = OnscreenText(text="Position: \nChunk: ", align=TextNode.ALeft, parent=self.pixel2d, fg=(1, 1, 1, 1), bg=(0, 0, 0, 0.7))
        self.position_text.setScale(18)
        self.position_text.setPos(5, -20)

        self.taskMgr.setupTaskChain('chunk_loader_chain', numThreads=6)

        self.create_lights()

        self.taskMgr.doMethodLater(0, self.load_chunks, 'Load Chunks', extraArgs=[chunks], appendTask=True)

        self.camera.setPos(-64 * 5, 54 * 5, 100)

    def create_lights(self):

        plight = PointLight('plight')
        plight.setColor((0.2, 0.2, 0.2, 1))
        plight_node = self.render.attachNewNode(plight)
        plight_node.setPos(-64 * 25, 54 * 25, 126)
        self.render.setLight(plight_node)

        alight = AmbientLight('alight')
        alight.setColor((0.2, 0.2, 0.2, 1))
        self.render.setLight(self.render.attachNewNode(alight))

    def set_key(self, key, value):
        self.keyMap[key] = value

    def recenter_mouse(self):
        self.win.movePointer(0,
                             int(self.win.getProperties().getXSize() / 2),
                             int(self.win.getProperties().getYSize() / 2))

    SENSITIVITY_MULTIPLIER = 20

    def camera_rotation(self, task):

        mw = self.mouseWatcherNode

        has_mouse = mw.hasMouse()

        if has_mouse:
            dx, dy = mw.getMouseX(), mw.getMouseY()
        else:
            dx, dy = 0, 0

        camera_h = self.camera.getH() + -dx * VisualizerApp.SENSITIVITY_MULTIPLIER
        camera_p = self.camera.getP() + dy * VisualizerApp.SENSITIVITY_MULTIPLIER

        self.camera.setH(camera_h)
        self.camera.setP(camera_p)

        self.recenter_mouse()
        return task.cont

    MOVE_SPEED = 3
    MOVE_SPEED_MULTIPLIER = 10

    def camera_movement(self, task):

        dt = globalClock.getDt()

        direction = self.render.getRelativeVector(self.camera, (0, 1, 0))
        direction.normalize()

        position = self.camera.getPos()

        move_speed = VisualizerApp.MOVE_SPEED

        if self.keyMap['shift']:
            move_speed *= VisualizerApp.MOVE_SPEED_MULTIPLIER

        if self.keyMap['forward']:
            position += direction * dt * move_speed
        if self.keyMap['backward']:
            position += direction * dt * -move_speed

        self.camera.setPos(position)

        chunk_x = position.x // self.level.chunk_width
        chunk_z = position.y // self.level.chunk_depth

        self.position_text.text = 'Position: (x: %04d, y: %04d, z: %04d)\nChunk (x: %02d, z: %02d)' % (position.x, position.z, position.y, chunk_x, chunk_z)

        return task.cont

    def load_chunks(self, chunks, task):

        for chunk in chunks:
            self.taskMgr.doMethodLater(0, self.load_chunk, 'Load Chunk', extraArgs=[chunk], appendTask=True,
                                       taskChain='chunk_loader_chain')

        return task.done

    def load_chunk(self, chunk, task):

        voxel_real_size = Vec3(self.level.chunk_unit_width / self.level.chunk_width, self.level.chunk_unit_height / self.level.chunk_voxel_height,
                               self.level.chunk_unit_depth / self.level.chunk_depth)

        chunk_size = Vec3(self.level.chunk_width, self.level.chunk_voxel_height, self.level.chunk_depth)

        chunk = VChunk(chunk_size, voxel_real_size, chunk)
        chunk.show(self)

        return task.done
Beispiel #20
0
class Window():
    texture = None
    def __init__(self, title_text, scale, parent=None, child=None, transparent=False, owner=None):
        self.title_text = title_text
        self.scale = scale
        self.title_size = settings.ui_font_size
        self.owner = owner
        self.child = None
        self.last_pos = None
        self.title_color = (1, 1, 1, 1)
        self.title_pad = tuple(self.scale * 2)
        if parent is None:
            parent = aspect2d
        self.parent = parent
        if transparent:
            frameColor = (0, 0, 0, 0)
        else:
            frameColor = (0.5, 0.5, 0.5, 1)
        self.pad = 0
        self.event_handler = DirectObject()
        self.button_thrower = base.buttonThrowers[0].node()
        self.event_handler.accept("wheel_up-up", self.mouse_wheel_event, extraArgs = [-1])
        self.event_handler.accept("wheel_down-up", self.mouse_wheel_event, extraArgs = [1])
        self.scrollers = []

#         if Window.texture is None:
#             Window.texture = loader.loadTexture('textures/futureui1.png')
#         image_scale = (scale[0] * Window.texture.get_x_size(), 1, scale[1] * Window.texture.get_y_size())
        self.frame = DirectFrame(parent=parent, state=DGG.NORMAL, frameColor=frameColor)#, image=self.texture, image_scale=image_scale)
        self.title_frame = DirectFrame(parent=self.frame, state=DGG.NORMAL, frameColor=(.5, .5, .5, 1))
        self.title = OnscreenText(text=self.title_text,
                                  style=Plain,
                                  fg=self.title_color,
                                  scale=tuple(self.scale * self.title_size),
                                  parent=self.title_frame,
                                  pos=(0, 0),
                                  align=TextNode.ALeft,
                                  font=None,
                                  mayChange=True)
        bounds = self.title.getTightBounds()
        self.title_frame['frameSize'] = [0, bounds[1][0] - bounds[0][0] + self.title_pad[0] * 2,
                                         0, bounds[1][2] - bounds[0][2] + self.title_pad[1] * 2]
        self.title.setPos( -bounds[0][0] + self.title_pad[0],  -bounds[0][2] + self.title_pad[1])
        self.close_frame = DirectFrame(parent=self.frame, state=DGG.NORMAL, frameColor=(.5, .5, .5, 1))
        self.close = OnscreenText(text='X',
                                  style=Plain,
                                  fg=self.title_color,
                                  scale=tuple(self.scale * self.title_size),
                                  parent=self.close_frame,
                                  pos=(0, 0),
                                  align=TextNode.ACenter,
                                  font=None,
                                  mayChange=True)
        bounds = self.close.getTightBounds()
        self.close_frame['frameSize'] = [0, bounds[1][0] - bounds[0][0] + self.title_pad[0] * 2,
                                         self.title_frame['frameSize'][2], self.title_frame['frameSize'][3]]
        self.close.setPos( -bounds[0][0] + self.title_pad[0],  -bounds[0][2] + self.title_pad[1])
        self.frame.setPos(0, 0, 0)
        self.title_frame.bind(DGG.B1PRESS, self.start_drag)
        self.title_frame.bind(DGG.B1RELEASE, self.stop_drag)
        self.close_frame.bind(DGG.B1PRESS, self.close_window)
        self.set_child(child)

    def set_child(self, child):
        if child is not None:
            self.child = child
            child.reparent_to(self.frame)
            self.update()

    def update(self):
        if self.child is not None:
            frame_size = list(self.child.frame['frameSize'])
            if frame_size is not None:
                frame_size[0] -= self.pad
                frame_size[1] += self.pad
                frame_size[2] += self.pad
                frame_size[3] -= self.pad
            self.frame['frameSize'] = frame_size
        if self.frame['frameSize'] is not None:
            width = self.frame['frameSize'][1] - self.frame['frameSize'][0]
            title_size = self.title_frame['frameSize']
            title_size[0] = 0
            title_size[1] = width
            self.title_frame['frameSize'] = title_size
            self.close_frame.setPos(width - self.close_frame['frameSize'][1], 0, 0)

    def register_scroller(self, scroller):
        self.scrollers.append(scroller)

    def mouse_wheel_event(self, dir):
        # If the user is scrolling a scroll-bar, don't try to scroll the scrolled-frame too.
        region = base.mouseWatcherNode.getOverRegion()
        if region is not None:
            widget = base.render2d.find("**/*{0}".format(region.name))
            if widget.is_empty() or isinstance(widget.node(), PGSliderBar) or isinstance(widget.getParent().node(), PGSliderBar):
                return

        # Get the mouse-position
        if not base.mouseWatcherNode.hasMouse():
            return
        mouse_pos = base.mouseWatcherNode.getMouse()

        found_scroller = None
        # Determine whether any of the scrolled-frames are under the mouse-pointer
        for scroller in self.scrollers:
            bounds = scroller['frameSize']
            pos = scroller.get_relative_point(base.render2d, Point3(mouse_pos.get_x() ,0, mouse_pos.get_y()))
            if pos.x > bounds[0] and pos.x < bounds[1] and \
                pos.z > bounds[2] and pos.z < bounds[3]:
                found_scroller = scroller
                break

        if found_scroller is not None:
            if not found_scroller.verticalScroll.isHidden():
                self.do_mouse_scroll(found_scroller.verticalScroll, dir, None)
            else:
                self.do_mouse_scroll(found_scroller.horizontalScroll, dir, None)

    def do_mouse_scroll(self, obj, dir, data):
        if isinstance(obj, DirectSlider) or isinstance(obj, DirectScrollBar):
            obj.setValue(obj.getValue() + dir * obj["pageSize"] * 0.1)

    def start_drag(self, event):
        if base.mouseWatcherNode.has_mouse():
            mpos = base.mouseWatcherNode.get_mouse()
            self.drag_start = self.frame.parent.get_relative_point(render2d, Point3(mpos.get_x() ,0, mpos.get_y())) - self.frame.getPos()
            taskMgr.add(self.drag, "drag", -1)

    def drag(self, task):
        if base.mouseWatcherNode.has_mouse():
            mpos = base.mouseWatcherNode.get_mouse()
            current_pos = self.frame.parent.get_relative_point(render2d, Point3(mpos.get_x() ,0, mpos.get_y()))
            self.frame.set_pos(current_pos - self.drag_start)
        return task.again

    def close_window(self, event=None):
        if self.owner is not None:
            self.owner.window_closed(self)
        self.destroy()

    def stop_drag(self, event):
        taskMgr.remove("drag")
        self.last_pos = self.frame.getPos()

    def destroy(self):
        if self.frame is not None:
            self.frame.destroy()
        self.frame = None
        self.scrollers = []
        self.event_handler.ignore_all()

    def getPos(self):
        return self.frame.getPos()

    def setPos(self, pos):
        self.frame.setPos(pos)
class LabTask03(DirectObject):
  
  #define the state of the game and level
  gameState = 'INIT'
  gameLevel = 1
  cameraState = 'STARTUP'
  count = 0
  attempts = 3
  posX = -200
  posY = 20
  posZ = 30
  score = 0
  contacts = 0
  pause = False
  fire = True
  desiredCamPos = Vec3(-200,30,20)

  def __init__(self):
    self.imageObject = OnscreenImage(image = 'models/splashscreen.png', pos=(0,0,0), scale=(1.4,1,1))
    preloader = Preloader()
    self.musicLoop = loader.loadSfx("music/loop/EndlessBliss.mp3")
    self.snowmansHit = loader.loadSfx("music/effects/snowball_hit.wav")
    self.candleThrow = loader.loadSfx("music/effects/snowball_throw.wav")
    self.presentHit = loader.loadSfx("music/effects/present_hit.wav")
    self.loseSound = loader.loadSfx("music/effects/Failure-WahWah.mp3")
    self.winSound = loader.loadSfx("music/effects/Ta Da-SoundBible.com-1884170640.mp3")
    self.nextLevelSound = loader.loadSfx("music/effects/button-17.wav")
    self.loseScreen = OnscreenImage(image = 'models/losescreen.png', pos=(0,0,0), scale=(1.4,1,1))
    self.loseScreen.hide()
    self.winScreen = OnscreenImage(image = 'models/winscreen.png', pos=(0,0,0), scale=(1.4,1,1))
    self.winScreen.hide()
    self.helpScreen = OnscreenImage(image = 'models/helpscreen.jpg', pos=(0,0,0.1), scale=(1,1,0.8))
    self.helpScreen.hide()
    self.backBtn = DirectButton(text=("Back"), scale = 0.1,  pos = (0,0,-0.8), command = self.doBack)
    self.retryBtn = DirectButton(text="Retry", scale = 0.1, pos = (0,0,0), command = self.doRetry)
    self.retryBtn.hide()
    self.menuBtn = DirectButton(text="Main Menu", scale = 0.1, pos = (0,0,0), command = self.doBack)
    self.menuBtn.hide()
    self.backBtn.hide()
    base.setBackgroundColor(0.1, 0.1, 0.8, 1)
    #base.setFrameRateMeter(True)
    
    # Position the camera
    base.cam.setPos(0, 30, 20)
    base.cam.lookAt(0, 30, 0)

    # Light
    alight = AmbientLight('ambientLight')
    alight.setColor(Vec4(0.5, 0.5, 0.5, 1))
    alightNP = render.attachNewNode(alight)

    dlight = DirectionalLight('directionalLight')
    dlight.setDirection(Vec3(1, 1, -1))
    dlight.setColor(Vec4(0.7, 0.7, 0.7, 1))
    dlightNP = render.attachNewNode(dlight)

    render.clearLight()
    render.setLight(alightNP)
    render.setLight(dlightNP)

    # Input
    self.accept('escape', self.doExit)
    self.accept('r', self.doReset)
    self.accept('f1', self.toggleWireframe)
    self.accept('f2', self.toggleTexture)
    self.accept('f3', self.toggleDebug)
    self.accept('f5', self.doScreenshot)
    self.accept('f', self.doShoot, [True])
    self.accept('p', self.doPause)

    inputState.watchWithModifiers('forward', 'w')
    inputState.watchWithModifiers('left', 'a')
    inputState.watchWithModifiers('reverse', 's')
    inputState.watchWithModifiers('right', 'd')
    inputState.watchWithModifiers('turnLeft', 'q')
    inputState.watchWithModifiers('turnRight', 'e')
    
    inputState.watchWithModifiers('moveLineUp', 'i')
    inputState.watchWithModifiers('moveLineDown','k')
    inputState.watchWithModifiers('moveLineRight','l')
    inputState.watchWithModifiers('moveLineLeft','j')
    
    self.font = loader.loadFont('models/SHOWG.TTF')
    self.font.setPixelsPerUnit(60)
    self.attemptText = OnscreenText(text='', pos = (0.9,0.8), scale = 0.07, font = self.font)
    self.levelText = OnscreenText(text='', pos=(-0.9,0.9), scale = 0.07, font = self.font )
    self.scoreText = OnscreenText(text='', pos = (0.9,0.9), scale = 0.07, font = self.font)
    self.text = OnscreenText(text = '', 
                              pos = (0, 0), scale = 0.07, font = self.font)
    self.pauseText = OnscreenText(text='P: Pause', pos= (0.9,0.7), scale = 0.05, font = self.font)
    self.pauseText.hide()
    # Task
    taskMgr.add(self.update, 'updateWorld')

    # Physics
    self.setup()

  # _____HANDLER_____
  
  def doRetry(self):
    self.loseScreen.hide()
    self.levelText.clearText()
    self.scoreText.clearText()
    self.attemptText.clearText()
    self.playGame()
    self.retryBtn.hide()
    self.cleanup()
    self.setup()
    

  def doExit(self):
    self.cleanup()
    sys.exit(1)

  def doReset(self):
    self.attempts = 3
    self.cameraState = 'STARTUP'
    base.cam.setPos(0,30,20)
    self.arrow.removeNode()
    self.scoreText.clearText()
    self.levelText.clearText()
    self.attemptText.clearText()
    self.cleanup()
    self.setup()
    
  def toggleWireframe(self):
    base.toggleWireframe()

  def toggleTexture(self):
    base.toggleTexture()

  def toggleDebug(self):
    if self.debugNP.isHidden():
      self.debugNP.show()
    else:
      self.debugNP.hide()

  def doScreenshot(self):
    base.screenshot('Bullet')
    
    
  def doShoot(self, ccd):
    if(self.fire and self.attempts > 0 and self.gameState == 'PLAY'):
      self.cameraState = 'LOOK'
      self.fire = False
      self.candleThrow.play()
      self.attempts -= 1
      #get from/to points from mouse click
      ## pMouse = base.mouseWatcherNode.getMouse()
      ## pFrom = Point3()
      ## pTo = Point3()
      ## base.camLens.extrude(pMouse, pFrom, pTo)
      
      ## pFrom = render.getRelativePoint(base.cam, pFrom)
      ## pTo = render.getRelativePoint(base.cam, pTo)
      
      # calculate initial velocity
      v = self.pTo - self.pFrom
      ratio = v.length() / 40
      v.normalize()
      v *= 70.0 * ratio
      torqueOffset = random.random() * 10
      
      #create bullet
      shape = BulletSphereShape(0.5)
      shape01 = BulletSphereShape(0.5)
      shape02 = BulletSphereShape(0.5)
      shape03 = BulletSphereShape(0.5)
      body = BulletRigidBodyNode('Candle')
      bodyNP = self.worldNP.attachNewNode(body)
      bodyNP.node().addShape(shape, TransformState.makePos(Point3(0,0,0)))
      bodyNP.node().addShape(shape01, TransformState.makePos(Point3(0,0.5,-0.5)))
      bodyNP.node().addShape(shape02,TransformState.makePos(Point3(0,1,-1)))
      bodyNP.node().addShape(shape03,TransformState.makePos(Point3(0,1.5,-1.5)))
      bodyNP.node().setMass(100)
      bodyNP.node().setFriction(1.0)
      bodyNP.node().setLinearVelocity(v)
      bodyNP.node().applyTorque(v*torqueOffset)
      bodyNP.setPos(self.pFrom)
      bodyNP.setCollideMask(BitMask32.allOn())
      
      visNP = loader.loadModel('models/projectile.X')
      visNP.setScale(0.7)
      visNP.clearModelNodes()
      visNP.reparentTo(bodyNP)
      
      #self.bird = bodyNP.node()
      
      if ccd:
          bodyNP.node().setCcdMotionThreshold(1e-7)
          bodyNP.node().setCcdSweptSphereRadius(0.5)
          
      self.world.attachRigidBody(bodyNP.node())
      
      #remove the bullet again after 1 sec
      self.bullets = bodyNP
      taskMgr.doMethodLater(5, self.removeBullet, 'removeBullet', extraArgs=[bodyNP], 
                            appendTask = True)
      
    
  def removeBullet(self, bulletNP, task):
    self.cameraState = 'STAY'
    self.fire = True
    self.world.removeRigidBody(bulletNP.node())
    bulletNP.removeNode()
    if(self.attempts <= 0 and len(self.snowmans)>0):
      self.gameState = 'LOSE'
      self.doContinue()
      
    return task.done

  # ____TASK___

  def processInput(self, dt):
    force = Vec3(0, 0, 0)
    torque = Vec3(0, 0, 0)
    #print self.pTo.getY()
    if inputState.isSet('forward'):
      if(self.pTo.getZ() < 40):
        self.pTo.addZ(0.5)
    if inputState.isSet('reverse'):
      if(self.pTo.getZ() > 0 ):
        self.pTo.addZ(-0.5)
    if inputState.isSet('left'):
      if(self.pTo.getY() < 100):
        self.pTo.addY(0.5)
        self.arrow.setScale(self.arrow.getSx(),self.arrow.getSy()-0.006,self.arrow.getSz())
    if inputState.isSet('right'):
      if(self.pTo.getY() > 60):
        self.pTo.addY(-0.5)
        self.arrow.setScale(self.arrow.getSx(),self.arrow.getSy()+0.006,self.arrow.getSz())
        
    self.arrow.lookAt(self.pTo)
    
  def processContacts(self, dt):
      for box in self.boxes:
        for snowman in self.snowmans:
          result = self.world.contactTestPair(box, snowman.node())
      
          if (result.getNumContacts() > 0):
            self.snowmansHit.play()
            self.score += 100
            self.text.setPos(0,0.7)
            self.text.setText("HIT")
            self.snowmans.remove(snowman)
            self.world.removeRigidBody(snowman.node())
            snowman.removeNode()
            if(len(self.snowmans)  <= 0):
              self.gameState = "NEXT"
              self.text.setText('Nice! Press space to continue')

              
      for box in self.boxes:
        for present in self.presents:
          result01 = self.world.contactTestPair(box,present.node())
          if(result01.getNumContacts() > 0):
            self.presents.remove(present)
            self.world.removeRigidBody(present.node())
            present.removeNode()
            self.presentHit.play()
            self.score += 500
            
  def doContinue(self):
    if(self.gameState == 'INIT'):
      self.gameState = 'MENU'
      self.text.clearText()
      self.musicLoop.setLoop(True)
      self.musicLoop.setVolume(0.5)
      self.musicLoop.play()
      self.startBtn = DirectButton(text=("Play"), scale = 0.1, pos = (0,0,0),command=self.playGame)
      self.helpBtn = DirectButton(text=("Help"), scale = 0.1, pos = (0,0,-0.2),command=self.help)
      self.exitBtn = DirectButton(text=("Exit"), scale = 0.1,  pos = (0,0,-0.4), command = self.doExit)
      return
    
    if self.gameState == 'NEXT':
      self.nextLevelSound.play()
      self.fire = True
      self.gameLevel += 1
      self.score += (self.attempts * 100)
      self.doReset()
      self.gameState = 'PLAY'
      return
    
    if self.gameState == 'LOSE':
      self.loseSound.play()
      self.arrow.removeNode()
      self.loseScreen.show()
      self.levelText.hide()
      self.attemptText.hide()
      self.scoreText.hide()
      self.text.hide()
      self.pauseText.hide()
      self.retryBtn.show()
      return
    
    if self.gameState == 'WIN':
      self.levelText.hide()
      self.attemptText.hide()
      self.scoreText.clearText()
      self.scoreText.setPos(0,0.6)
      self.scoreText.setText("%s"%self.score)
      self.winScreen.show()
      self.winSound.play()
      self.menuBtn.show()
      self.pauseText.hide()
      return
      
    
  def playGame(self):
    print "Play Game"
    self.attempts = 3
    self.score = 0
    self.gameLevel = 1
    self.gameState = 'PLAY'
    self.musicLoop.setVolume(0.3)
    self.imageObject.hide()
    self.startBtn.hide()
    self.exitBtn.hide()
    self.helpBtn.hide()
    self.cleanup()
    self.setup()
    
  def doBack(self):
    self.gameState = 'MENU'
    self.scoreText.setPos(0.9,0.9)
    self.scoreText.hide()
    self.imageObject.show()
    self.startBtn.show()
    self.exitBtn.show()
    self.helpBtn.show()
    self.helpScreen.hide()
    self.backBtn.hide()
    self.menuBtn.hide()
    self.winScreen.hide()
    
  def help(self):
    self.gameState = 'HELP'
    self.startBtn.hide()
    self.exitBtn.hide()
    self.helpBtn.hide()
    self.backBtn.show()
    self.helpScreen.show()
    return
    
  def doPause(self):
    self.pause  = not self.pause
    if(self.pause):
      self.text.setText("Pause")
    else:
      self.text.clearText()
      

  def update(self, task):

    dt = globalClock.getDt()
    if(not self.pause):
      if self.gameState == 'INIT':
        self.text.setPos(0,0)
        self.text.setText('Press space to continue')
        self.accept('space',self.doContinue)
          
      if self.gameState == 'PLAY':
        #print self.posZ
        #if(self.posX < -120):
        #  self.posX += 0.03
        #  self.posZ -= 0.02
        #elif(self.posZ < 70):
        #  self.posZ += 0.02;
        #elif(self.posZ > 70 and self.posX > -120):
        #  self.posZ -= 0.02
        #  self.posX -= 0.03
        #base.cam.setPos(self.posX, self.posZ, self.posY)
        self.levelText.setText('Level: %s'%self.gameLevel)
        self.attemptText.setText('Tries Left: %s'%self.attempts)
        self.scoreText.setText('Score: %s'%self.score)
        self.pauseText.show()
        self.processContacts(dt)
        self.world.doPhysics(dt, 20, 1.0/180.0)
        #self.drawLines()
        self.processInput(dt)
        
        if self.cameraState == 'STARTUP':
          oldPos = base.cam.getPos()
          pos = (oldPos*0.9) + (self.desiredCamPos*0.1)
          base.cam.setPos(pos)
          base.cam.lookAt(0,30,0)
        elif self.cameraState == 'STAY':
          #oldPos = base.cam.getPos()
          #currPos = (oldPos*0.9) + (self.desiredCamPos*0.1)
          #base.cam.setPos(currPos)
          base.cam.lookAt(0,30,0)
        elif self.cameraState == 'LOOK':
          base.cam.lookAt(self.bullets)
          #base.cam.setPos(-200,self.bullets.getZ(),20)
        
      if self.gameState == 'NEXT':
        self.world.doPhysics(dt, 20, 1.0/180.0)
        

      ## self.raycast()
    
    return task.cont
      
  def raycast(self):
    # Raycast for closest hit
    tsFrom = TransformState.makePos(Point3(0,0,0))
    tsTo = TransformState.makePos(Point3(10,0,0))
    shape = BulletSphereShape(0.5)
    penetration = 1.0
    result = self.world.sweepTestClosest(shape, tsFrom, tsTo, penetration)
    if result.hasHit():
        torque = Vec3(10,0,0)
        force = Vec3(0,0,100)
        
        ## for hit in result.getHits():
            ## hit.getNode().applyTorque(torque)
            ## hit.getNode().applyCentralForce(force)
        result.getNode().applyTorque(torque)
        result.getNode().applyCentralForce(force)
        ## print result.getClosestHitFraction()
        ## print result.getHitFraction(), \
            ## result.getNode(), \
            ## result.getHitPos(), \
            ## result.getHitNormal()

  def cleanup(self):
    self.world = None
    self.worldNP.removeNode()
    self.arrow.removeNode()
    self.lines.reset()
    self.text.clearText()

  def setup(self):
    self.attemptText.show()
    self.levelText.show()
    self.scoreText.show()
    self.text.show()
    
    self.worldNP = render.attachNewNode('World')

    # World
    self.debugNP = self.worldNP.attachNewNode(BulletDebugNode('Debug'))
    self.debugNP.show()

    self.world = BulletWorld()
    self.world.setGravity(Vec3(0, 0, -9.81))
    self.world.setDebugNode(self.debugNP.node())
    
    #arrow
    self.scaleY = 10
    self.arrow = loader.loadModel('models/arrow.X')
    self.arrow.setScale(0.5,0.5,0.5)
    self.arrow.setAlphaScale(0.5)
    #self.arrow.setTransparency(TransparencyAttrib.MAlpha) 
    self.arrow.reparentTo(render)
    
    #SkyBox
    skybox = loader.loadModel('models/skybox.X')
    skybox.reparentTo(render)

    # Ground
    shape = BulletPlaneShape(Vec3(0, 0, 1), 0)

    np = self.worldNP.attachNewNode(BulletRigidBodyNode('Ground'))
    np.node().addShape(shape)
    np.setPos(0, 0, -1)
    np.setCollideMask(BitMask32.allOn())

    self.world.attachRigidBody(np.node())
    
    visualNP = loader.loadModel('models/ground.X')
    visualNP.clearModelNodes()
    visualNP.reparentTo(np)
    
    #some boxes
    self.boxes = []
    self.snowmans = []
    self.platforms = []
    self.presents = []
    #TODO: Make a table
    #Table Top
    #self.createBox(Vec3(),Vec3())
    if(self.gameLevel == 1):
      self.createBox(Vec3(5,7,1),Vec3(0,5,10),1.0)
      #2 legs
      self.createBox(Vec3(4,1,4),Vec3(0,11,5),1.0)
      self.createBox(Vec3(4,1,4),Vec3(0,-1,5),1.0)
      
      # Pigs
      self.createSnowman(2.0,Vec3(0, 5, 2.0),10.0)
      self.createSnowman(1.5, Vec3(0,-10,4.0),10.0)
      
    if(self.gameLevel == 2):
      #table01
      self.createBox(Vec3(5,14,1),Vec3(0,-2,12),2.0)
      self.createBox(Vec3(5,7,1),Vec3(0,5,10),2.0)
      self.createBox(Vec3(4,1,4),Vec3(0,11,5),1.0)
      self.createBox(Vec3(4,1,4),Vec3(0,-1,5),1.0)
      #table02
      self.createBox(Vec3(5,7,1),Vec3(0,-9,10),2.0)
      self.createBox(Vec3(4,1,4),Vec3(0,-3,5),1.0)
      self.createBox(Vec3(4,1,4),Vec3(0,-15,5),1.0)
      #table03
      self.createBox(Vec3(1,1,1), Vec3(0,-1,14), 2.0)
      self.createBox(Vec3(1,1,1), Vec3(0,-3,14), 2.0)
      self.createBox(Vec3(1,1,1), Vec3(0,3,14), 2.0)
      self.createBox(Vec3(1,1,1), Vec3(0,-5,14), 2.0)
      self.createBox(Vec3(1,1,1), Vec3(0,5,14), 2.0)
      #pigs
      self.createSnowman(2.0,Vec3(0, 5, 2.0),10.0)
      self.createSnowman(2.0, Vec3(0,-9,2.0), 10.0)
      self.createSnowman(2.0,Vec3(0,-23,2.0),10.0)
      
    if(self.gameLevel == 3):
      #table01
      self.createBox(Vec3(4,2,2),Vec3(0,12,12),1.0)
      self.createBox(Vec3(4,1,4),Vec3(0,11,5),1.0)
      self.createBox(Vec3(4,1,4),Vec3(0,13,5),1.0)
      #table02
      self.createBox(Vec3(4,2,2),Vec3(0,-15,12),1.0)
      self.createBox(Vec3(4,1,4),Vec3(0,-14,5),1.0)
      self.createBox(Vec3(4,1,4),Vec3(0,-16,5),1.0)
      #table03
      self.createBox(Vec3(4,10,1),Vec3(0,-1,12),1.0)
      self.createBox(Vec3(4,10,1),Vec3(0,-1,14),1.0)
      self.createBox(Vec3(4,2,4),Vec3(0,-2,5),0.1)
      #table04
      self.createPlatform(Vec3(4,8,1),Vec3(0,7,16),1.0)
      self.createPlatform(Vec3(4,8,1),Vec3(0,-9,16),1.0)
      self.createBox(Vec3(4,1,3),Vec3(0,13,20),1.0)
      self.createBox(Vec3(4,1,3),Vec3(0,-16,20),1.0)
      #table05
      self.createBox(Vec3(4,15,1),Vec3(0,-1,24),1.0)
      self.createStoneBox(Vec3(1,1,1),Vec3(0,2,20),5.0)
      self.createStoneBox(Vec3(1,1,1),Vec3(0,-2,20),5.0)
      self.createStoneBox(Vec3(1,1,1),Vec3(0,4,20),5.0)
      self.createStoneBox(Vec3(1,1,1),Vec3(0,8,20),5.0)
      self.createStoneBox(Vec3(1,1,1),Vec3(0,6,20),5.0)
      
      #pigs
      self.createSnowman(2.0,Vec3(0, 5, 2.0),10.0)
      self.createSnowman(2.0,Vec3(0,-8.5,2.0),10.0)
      self.createSnowman(1.5, Vec3(0,-9,19.5), 7.0)
      
      #presents
      self.createPresent(Vec3(2,2,2),Vec3(0,-20,5))
         
    if(self.gameLevel == 4):
      #wall
      self.createStoneBox(Vec3(4,1.5,10), Vec3(0,20,10),20)
      #table01
      self.createBox(Vec3(4,1,5), Vec3(0,7,7),1)
      self.createBox(Vec3(4,1,5), Vec3(0,0,7),1)
      self.createBox(Vec3(4,1,4), Vec3(0,3,7),1)
      self.createPlatform(Vec3(5,8,1), Vec3(0,4,13),1)
      self.createBox(Vec3(4,1,3), Vec3(0,11,18),1)
      self.createBox(Vec3(4,1,3), Vec3(0,-3,18),1)
      self.createBox(Vec3(4,8,1), Vec3(0,4,25),1)
      self.createStoneBox(Vec3(1,1,1), Vec3(0,4,27),2)
      self.createStoneBox(Vec3(1,1,1), Vec3(0,7,27),2)
      self.createStoneBox(Vec3(1,1,1), Vec3(0,2,27),2)
      self.createStoneBox(Vec3(1,1,1), Vec3(0,2,29),2)
      #stairs
      self.createPlatform(Vec3(4,50,4), Vec3(0,-55,5),100)
      #table02
      self.createBox(Vec3(4,1,5), Vec3(0,-13,15),1)
      self.createBox(Vec3(4,1,5), Vec3(0,-20,15),1)
      self.createBox(Vec3(4,1,4), Vec3(0,-17,15),1)
      self.createPlatform(Vec3(4,8,1), Vec3(0,-16,22),1)
      self.createBox(Vec3(4,1,3), Vec3(0,-9,28),1)
      self.createBox(Vec3(4,1,3), Vec3(0,-23,28),1)
      self.createBox(Vec3(4,8,1), Vec3(0,-16,33),1)
      self.createStoneBox(Vec3(1,1,1), Vec3(0,-16,35),2)
      self.createStoneBox(Vec3(1,1,1), Vec3(0,-13,35),2)
      self.createStoneBox(Vec3(1,1,1), Vec3(0,-18,35),2)
      self.createStoneBox(Vec3(1,1,1), Vec3(0,-18,37),2)
      self.createStoneBox(Vec3(1,1,1), Vec3(0,-14,37),2)
      
      #snowman
      self.createSnowman(2.0,Vec3(0,30,5),1.0)
      self.createSnowman(1.5,Vec3(0,4,18),1.0)
      self.createSnowman(1.5,Vec3(0,-13,26),1.0)
      self.createSnowman(1.5,Vec3(0,-19,26),1.0)
      self.createSnowman(2.0,Vec3(0,12,5),1.0)
      self.createPresent(Vec3(2,2,2),Vec3(0,-25,13))
      self.createPresent(Vec3(3,3,3),Vec3(0,-30,13))
      self.createPresent(Vec3(4,4,4),Vec3(0,-36,13))
      #self.createSnowman(1.5,Vec3(0,4,20),1.0)

      
    if(self.gameLevel == 5):
      #table01
      self.createStoneBox(Vec3(4,7,3), Vec3(0,30,5),10.0)
      self.createStoneBox(Vec3(4,7,3), Vec3(0,-30,5),10.0)
      self.createBox(Vec3(4,1,3), Vec3(0,0,5), 1.0)
      self.createSnowman(1.5,Vec3(0,-6,5),1.0)
      self.createSnowman(1.5,Vec3(0,6,5),1.0)
      self.createBox(Vec3(4,1,3), Vec3(0,-12,5), 1.0)
      self.createBox(Vec3(4,1,3), Vec3(0,12,5), 1.0)
      self.createSnowman(1.5,Vec3(0,-18,5),1.0)
      self.createSnowman(1.5,Vec3(0,18,5),1.0)
      self.createStoneBox(Vec3(4,6,1),Vec3(0,-18,10), 0.1)
      self.createStoneBox(Vec3(4,6,1),Vec3(0,-6,10), 0.1)
      self.createStoneBox(Vec3(4,6,1),Vec3(0,6,10), 0.1)
      self.createStoneBox(Vec3(4,6,1),Vec3(0,18,10), 0.1)
      self.createStoneBox(Vec3(4,1,3),Vec3(0,23,14), 1.0)
      self.createStoneBox(Vec3(4,1,3),Vec3(0,-23,14), 1.0)
      self.createBox(Vec3(4,1,3),Vec3(0,18,14),1.0)
      self.createBox(Vec3(4,1,3),Vec3(0,-18,14),1.0)
      self.createStoneBox(Vec3(4,1,7),Vec3(0,13,20), 2.0)
      self.createStoneBox(Vec3(4,1,7),Vec3(0,-13,20), 2.0)
      self.createBox(Vec3(4,1,3),Vec3(0,8,14),1.0)
      self.createBox(Vec3(4,1,3),Vec3(0,-8,14),1.0)
      self.createStoneBox(Vec3(4,1,3),Vec3(0,3,14), 1.0)
      self.createStoneBox(Vec3(4,1,3),Vec3(0,-3,14), 1.0)
      self.createPlatform(Vec3(4,3.5,1),Vec3(0,-20 ,20), 1.0)
      self.createPlatform(Vec3(4,3.5,1),Vec3(0,20 ,20), 1.0)
      self.createPlatform(Vec3(4,3.5,1),Vec3(0,-5 ,20), 1.0)
      self.createPlatform(Vec3(4,3.5,1),Vec3(0,5 ,20), 1.0)
      self.createStoneBox(Vec3(4,1,3.5),Vec3(0,-18,25), 2.0)
      self.createStoneBox(Vec3(4,1,3.5),Vec3(0,18,25), 2.0)
      self.createStoneBox(Vec3(4,1,3.5),Vec3(0,-7.5,25), 2.0)
      self.createStoneBox(Vec3(4,1,3.5),Vec3(0,7.5,25), 2.0)
      self.createStoneBox(Vec3(4,6,1),Vec3(0,-12,30), 2.0)
      self.createStoneBox(Vec3(4,6,1),Vec3(0,12,30), 2.0)
      self.createBox(Vec3(4,1,5),Vec3(0,-5,30), 2.0)
      self.createBox(Vec3(4,1,5),Vec3(0,5,30), 2.0)
      self.createBox(Vec3(4,5,1),Vec3(0,0,40), 2.0)
      self.createPlatform(Vec3(4,2,0.5),Vec3(0,0,42), 2.0)
      self.createStoneBox(Vec3(4,0.5,2),Vec3(0,-3.5,45), 2.0)
      self.createStoneBox(Vec3(4,0.5,2),Vec3(0,3.5,45), 2.0)
      self.createStoneBox(Vec3(4,4,0.5),Vec3(0,0,48), 2.0)
      
      self.createPresent(Vec3(1.5,1.5,1.5),Vec3(0,22,30))
      self.createPresent(Vec3(1.5,1.5,1.5),Vec3(0,-22,30))
      self.createPresent(Vec3(2,2,1),Vec3(0,0,44))
      self.createPresent(Vec3(3,3,4),Vec3(0,0,33))
      
      
    if(self.gameLevel > 5):
      self.gameState = 'WIN'
      self.doContinue()
      return
        
    # drawing lines between the points 
    ## self.lines = LineNodePath(parent = render, thickness = 3.0, colorVec = Vec4(1, 0, 0, 1))
    ## self.pFrom = Point3(-4, 0, 0.5)
    ## self.pTo = Point3(4, 0, 0.5)
    
    # Aiming line 
    self.lines = LineNodePath(parent = render, thickness = 3.0, 
                              colorVec = Vec4(1, 0, 0, 1))
    self.pFrom = Point3(0, 100, 0.5)
    self.pTo = Point3(0, 60, 10)
    
    self.arrow.setPos(self.pFrom)
      
    
  def drawLines(self):  
    # Draws lines for the ray.
    self.lines.reset()  
    self.lines.drawLines([(self.pFrom,self.pTo)])
    self.lines.create()
    
  def createBox(self,size,pos,mass):
    shape = BulletBoxShape(size)
    body = BulletRigidBodyNode('Obstacle')
    bodyNP = self.worldNP.attachNewNode(body)
    bodyNP.node().addShape(shape)
    bodyNP.node().setMass(mass)
    bodyNP.node().setFriction(1.0)
    bodyNP.node().setDeactivationEnabled(False)
    bodyNP.setPos(pos)
    bodyNP.setCollideMask(BitMask32.allOn())

    self.world.attachRigidBody(bodyNP.node())
            
    visNP = loader.loadModel('models/crate.X')
    visNP.setScale(size*2)
    visNP.clearModelNodes()
    visNP.reparentTo(bodyNP)
    self.boxes.append(body)
    
  def createStoneBox(self,size,pos,mass):
    shape = BulletBoxShape(size)
    body = BulletRigidBodyNode('Obstacle')
    bodyNP = self.worldNP.attachNewNode(body)
    bodyNP.node().addShape(shape)
    bodyNP.node().setMass(mass)
    bodyNP.node().setFriction(1.0)
    bodyNP.node().setDeactivationEnabled(False)
    bodyNP.setPos(pos)
    bodyNP.setCollideMask(BitMask32.allOn())

    self.world.attachRigidBody(bodyNP.node())
            
    visNP = loader.loadModel('models/stone.X')
    visNP.setScale(size*2)
    visNP.clearModelNodes()
    visNP.reparentTo(bodyNP)
    self.boxes.append(body)
    
  def createSnowman(self, size, pos, mass):
    shape = BulletBoxShape(Vec3(size,size,size))
    shape01 = BulletSphereShape(size/2)
    body = BulletRigidBodyNode('Snowman')
    np = self.worldNP.attachNewNode(body)
    np.node().setMass(mass)
    np.node().addShape(shape, TransformState.makePos(Point3(0,0,-1)))
    np.node().addShape(shape01, TransformState.makePos(Point3(0,0,1)))
    np.node().setFriction(10.0)
    np.node().setDeactivationEnabled(False)
    np.setPos(pos)
    np.setCollideMask(BitMask32.allOn())
      
    self.world.attachRigidBody(np.node())
  
    visualNP = loader.loadModel('models/snowman.X')
    visualNP.setScale(size)
    visualNP.clearModelNodes()
    visualNP.reparentTo(np)
    self.snowmans.append(np)
    
  def createPlatform(self,size,pos,mass):
    shape = BulletBoxShape(size)
    body = BulletRigidBodyNode('Platform')
    bodyNP = self.worldNP.attachNewNode(body)
    bodyNP.node().addShape(shape)
    bodyNP.node().setMass(mass)
    bodyNP.node().setFriction(1.0)
    bodyNP.node().setDeactivationEnabled(False)
    bodyNP.setPos(pos)
    bodyNP.setCollideMask(BitMask32.allOn())

    self.world.attachRigidBody(bodyNP.node())
            
    visNP = loader.loadModel('models/crate.X')
    visNP.setScale(size*2)
    visNP.clearModelNodes()
    visNP.reparentTo(bodyNP)
    self.platforms.append(body)
    
  def createPresent(self,size,pos):
    shape = BulletBoxShape(size*0.7)
    body = BulletRigidBodyNode('Present')
    bodyNP = self.worldNP.attachNewNode(body)
    bodyNP.node().addShape(shape)
    bodyNP.node().setMass(1.0)
    bodyNP.node().setFriction(1.0)
    bodyNP.node().setDeactivationEnabled(False)
    bodyNP.setPos(pos)
    bodyNP.setCollideMask(BitMask32.allOn())
    
    self.world.attachRigidBody(bodyNP.node())
    
    visNP = loader.loadModel('models/present.X')
    visNP.setScale(size*2)
    visNP.clearModelNodes()
    visNP.reparentTo(bodyNP)
    self.presents.append(bodyNP)
Beispiel #22
0
class AsteroidsDemo(ShowBase):
    def __init__(self, p3d_proto=None, obs_pixel=0, act_disc=0):
        # Initialize the ShowBase class from which we inherit, which will
        # create a window and set up everything we need for rendering into it.
        ShowBase.__init__(self)

        self.p3d_proto = p3d_proto
        self.obs_pixel = obs_pixel
        self.act_disc = act_disc

        globalClock.setFrameRate(30)
        # MNormal:0 MNoneRealTime:1 MForced:2 MLimited:5
        #~ globalClock.setMode(0)
        globalClock.setMode(1)

        self.exitFunc = on_exit

        if SHOW_ARROW:
            self.ship_arrow = P3DCreateAxes(length=GUN_RANGE / SCREEN_X)
            self.ship_arrow1 = P3DCreateAxes(length=GUN_RANGE / SCREEN_X)
        #~ self.ship_arrow1 = P3DCreateAxes(length=AVOID_DIST/SCREEN_X)

        #~ self.ast_arrow = P3DCreateAxes(length=GUN_RANGE/SCREEN_X)
        #~ self.ast_arrow1 = P3DCreateAxes(length=AVOID_DIST/SCREEN_X)

        self.bullets_text = OnscreenText(text="bullets 100:100",
                                         parent=base.a2dBottomRight,
                                         scale=.1,
                                         align=TextNode.ALeft,
                                         pos=(-1.99, 1.8),
                                         fg=(0, 1, 0, 1),
                                         shadow=(0, 0, 0, 0.5))

        self.life_text = OnscreenText(text="life 10:10",
                                      parent=base.a2dBottomRight,
                                      scale=.1,
                                      align=TextNode.ALeft,
                                      pos=(-1.99, 1.7),
                                      fg=(1, 0, 0, 1),
                                      shadow=(0, 0, 0, 0.5))

        self.debug_text = OnscreenText(text="DBG --",
                                       parent=base.a2dBottomRight,
                                       scale=.1,
                                       align=TextNode.ALeft,
                                       pos=(-1.99, 1.9),
                                       fg=(1, 1, 0, 1),
                                       shadow=(0, 0, 0, 0.5))

        self.text_agent1 = OnscreenText(text="A1",
                                        parent=base.a2dBottomRight,
                                        scale=.1,
                                        align=TextNode.ALeft,
                                        pos=(-1, 1),
                                        fg=(0, 1, 0, 1),
                                        shadow=(0, 0, 0, 0.5))

        # Disable default mouse-based camera control.  This is a method on the
        # ShowBase class from which we inherit.
        self.disableMouse()

        # Load the background starfield.
        self.setBackgroundColor((0, 0, 0, 1))
        self.bg = loadObject("stars.jpg",
                             scale=146,
                             depth=200,
                             transparency=False)

        # Load the ship and set its initial velocity.
        #~ self.ship = loadObject("ship.png", scale=2)
        #~ self.setVelocity(self.ship, LVector3.zero())
        self.ship1 = Ship(self)
        self.ship2 = Ship(self)

        # A dictionary of what keys are currently being pressed
        # The key events update this list, and our task will query it as input
        self.keys = {"turnLeft": 0, "turnRight": 0, "accel": 0, "fire": 0}

        #~ self.accept("escape", sys.exit)  # Escape quits
        self.accept("escape", on_exit)  # Escape quits
        # Other keys events set the appropriate value in our key dictionary
        self.accept("a", self.setKey, ["turnLeft", 1])
        self.accept("a-up", self.setKey, ["turnLeft", 0])
        self.accept("d", self.setKey, ["turnRight", 1])
        self.accept("d-up", self.setKey, ["turnRight", 0])
        self.accept("w", self.setKey, ["accel", 1])
        self.accept("w-up", self.setKey, ["accel", 0])

        self.accept("arrow_left", self.setKey, ["turnLeft", 1])
        self.accept("arrow_left-up", self.setKey, ["turnLeft", 0])
        self.accept("arrow_right", self.setKey, ["turnRight", 1])
        self.accept("arrow_right-up", self.setKey, ["turnRight", 0])
        self.accept("arrow_up", self.setKey, ["accel", 1])
        self.accept("arrow_up-up", self.setKey, ["accel", 0])

        self.accept("space", self.setKey, ["fire", 1])
        self.accept("space-up", self.setKey, ["fire", 0])

        self.gameTask = taskMgr.add(self.gameLoop, "gameLoop")

        # Stores the time at which the next bullet may be fired.
        self.nextBullet = 0.0

        # This list will stored fired bullets.
        self.bullets = []

        self.reset_hud()

        # Complete initialization by spawning the asteroids.
        self.spawnAsteroids()

    def reset_hud(self):
        self.rounds = 0
        self.count_win = 50
        self.draws = [0] * self.count_win
        self.wins1 = [0] * self.count_win
        self.wins2 = [0] * self.count_win
        self.wins1s = 0
        self.wins2s = 0

    # As described earlier, this simply sets a key in the self.keys dictionary
    # to the given value.
    def setKey(self, key, val):
        self.keys[key] = val

    def setVelocity(self, obj, val):
        obj.setPythonTag("velocity", val)

    def getVelocity(self, obj):
        return obj.getPythonTag("velocity")

    def setExpires(self, obj, val):
        obj.setPythonTag("expires", val)

    def getExpires(self, obj):
        return obj.getPythonTag("expires")

    def setAttacker(self, obj, val):
        obj.setPythonTag("attacker", val)

    def getAttacker(self, obj):
        return obj.getPythonTag("attacker")

    def spawnAsteroids(self):
        # Control variable for if the ship is alive
        self.alive = True
        self.asteroids = []  # List that will contain our asteroids

        for i in range(AST_NUM):
            # This loads an asteroid. The texture chosen is random
            # from "asteroid1.png" to "asteroid3.png".
            asteroid = loadObject("asteroid%d.png" % (randint(1, 3)),
                                  scale=AST_INIT_SCALE)
            self.asteroids.append(asteroid)

            # This is kind of a hack, but it keeps the asteroids from spawning
            # near the player.  It creates the list (-20, -19 ... -5, 5, 6, 7,
            # ... 20) and chooses a value from it. Since the player starts at 0
            # and this list doesn't contain anything from -4 to 4, it won't be
            # close to the player.
            asteroid.setX(
                choice(
                    tuple(range(-SCREEN_X, -5)) + tuple(range(5, SCREEN_X))))
            # Same thing for Y
            asteroid.setZ(
                choice(
                    tuple(range(-SCREEN_Y, -5)) + tuple(range(5, SCREEN_Y))))

            # Heading is a random angle in radians
            heading = random() * 2 * pi

            # Converts the heading to a vector and multiplies it by speed to
            # get a velocity vector
            v = LVector3(sin(heading), 0, cos(heading)) * AST_INIT_VEL
            self.setVelocity(self.asteroids[i], v)

    # This is our main task function, which does all of the per-frame
    # processing.  It takes in self like all functions in a class, and task,
    # the task object returned by taskMgr.
    def gameLoop(self, task):
        # Get the time elapsed since the next frame.  We need this for our
        # distance and velocity calculations.
        dt = globalClock.getDt()

        if not self.alive:
            return Task.cont

        # Net Update Action
        action = self.net_update_action()
        a_turn = action.get('turn', 0)
        a_accel = action.get('accel', -1)
        a_fire = action.get('fire', -1)
        a_turn2 = action.get('turn2', 0)
        a_accel2 = action.get('accel2', -1)
        a_fire2 = action.get('fire2', -1)
        # Net Update End

        # Reset By Agent Begin
        if action.get('restart', False):
            self.resetGame(restart=1)
            return Task.cont
        # Reset End

        # update ship position
        self.ship1.updateShip(dt, a_turn, a_accel)
        if ONE_SHIP_ONLY:
            self.ship1.hide()
            self.ship_arrow.hide()
            self.text_agent1.hide()
        else:
            self.ship1.updateFire(task, a_fire)
        # AI vs Player Begin
        if DOG_FIGHT == 2:
            a_turn2 = self.keys["turnRight"] - self.keys["turnLeft"]
            a_accel2 = self.keys["accel"]
            a_fire2 = self.keys["fire"]
            # slower turn_rate for human
            turn_ra = TURN_RATE * 0.66
        # AVP End
        else:
            turn_ra = TURN_RATE
        self.ship2.updateShip(dt, a_turn2, a_accel2, turn_ra=turn_ra)
        self.ship2.updateFire(task, a_fire2)

        # check crash to each other
        if DOG_FIGHT:
            self.ship1.checkCrash(self.ship2.ship)
            self.ship2.checkCrash(self.ship1.ship)
        # end

        # update asteroids
        for obj in self.asteroids:
            self.updatePos(obj, dt)

        # update bullets
        newBulletArray = []
        for obj in self.bullets:
            self.updatePos(obj, dt)  # Update the bullet
            # Bullets have an experation time (see definition of fire)
            if self.getExpires(obj) > task.time:
                newBulletArray.append(obj)
            else:
                obj.removeNode()  # Otherwise, remove it from the scene.
        # Set the bullet array to be the newly updated array
        self.bullets = newBulletArray

        for bullet in self.bullets:
            # check ship1 vs ship2
            if DOG_FIGHT:
                if self.ship1.checkHit(bullet):
                    if self.ship1.alive:
                        self.ship2.game_score += 10
                    else:
                        self.ship2.game_score += 100
                        self.wins2s += self.ship2.alive
                elif self.ship2.checkHit(bullet):
                    if self.ship2.alive:
                        self.ship1.game_score += 10
                    else:
                        self.ship1.game_score += 100
                        self.wins1s += self.ship1.alive
            # end
            for i in range(len(self.asteroids) - 1, -1, -1):
                asteroid = self.asteroids[i]
                if ((bullet.getPos() - asteroid.getPos()).lengthSquared() <
                    (((bullet.getScale().getX() + asteroid.getScale().getX()) *
                      .5)**2)):
                    # Schedule the bullet for removal
                    self.setExpires(bullet, 0)
                    self.asteroidHit(i)  # Handle the hit
                    # Scoring Begin
                    if self.getAttacker(bullet) == id(self.ship1):
                        self.ship1.game_score += 10
                    else:
                        self.ship2.game_score += 10
                    # Scoring End

        # DEBUG BEGIN
        wrn = self.count_win / 100.
        wr1 = sum(self.wins1) / wrn
        wr2 = sum(self.wins2) / wrn
        drr = sum(self.draws) / wrn
        self.debug_text.setText(
            "r%d: A1 %d:%d, wr%% %d:%d, dr %d%%, crash %d:%d" %
            (self.rounds, self.wins1s, self.wins2s, wr1, wr2, drr,
             self.ship1.crash, self.ship2.crash))
        # DEBUG END

        # If the player has successfully destroyed all asteroids, respawn them
        if len(self.asteroids) == 0:
            self.spawnAsteroids()

        # Net Update State
        game_over = self.net_update_state(done=0)
        # Net Update End
        if game_over:
            # win rate begin
            self.wins1.append(self.ship1.alive)
            self.wins1.pop(0)
            self.wins2.append(self.ship2.alive)
            self.wins2.pop(0)
            self.draws.append(0 if self.ship1.alive + self.ship2.alive else 1)
            self.draws.pop(0)
            # win rate end
            self.resetGame()

        return Task.cont  # Since every return is Task.cont, the task will
        # continue indefinitely

    # Net Update Begin

    def resetGame(self, wait=0, restart=0):
        self.alive = False
        for i in self.asteroids + self.bullets:
            i.removeNode()
        self.bullets = []  # Clear the bullet list
        self.rounds += 1

        if restart:
            self.reset_hud()

        Sequence(
            Wait(wait),  # Wait 2 seconds
            Func(self.ship1.reset, restart),  # Show the ship
            Func(self.ship2.reset, restart),  # Show the ship
            Func(self.spawnAsteroids)).start()  # Remake asteroids

    def getFrame(self, render=0):
        """ 84x84 1 channel """
        if render:
            self.graphicsEngine.renderFrame()
        dr = self.camNode.getDisplayRegion(0)
        img = dr.getScreenshot().getRamImageAs('G')
        img = np.array(img, dtype=np.uint8).reshape((WIN_H, WIN_W))
        img = cv2.resize(img, (84, 84), interpolation=cv2.INTER_AREA)
        return img

    def net_update_state(self, done=0):
        """ 游戏状态, 输出到udp """
        ship1_state, ship1_obs, ship1_score, ast_critical1 = self.ship1.getState(
            self.ship2.ship, self.asteroids, invincible=ONE_SHIP_ONLY)
        ship2_state, ship2_obs, ship2_score, ast_critical2 = self.ship2.getState(
            self.ship1.ship, self.asteroids, shuffle=SHUFFLE_AST)

        if done:
            game_done = 1
        else:
            game_done = 0 if self.ship1.alive and self.ship2.alive else 1

        # HUD Begin
        self.bullets_text.setText("bullets %d:%d [%d]" %
                                  (self.ship1.bullets_num,
                                   self.ship2.bullets_num, len(self.bullets)))
        self.life_text.setText("life %d:%d" %
                               (self.ship1.life, self.ship2.life))
        self.text_agent1.setPos(self.ship1.ship.getPos().getX() / 15 - 1,
                                self.ship1.ship.getPos().getZ() / 15 + 1)
        if SHOW_ARROW:
            self.ship_arrow.setPos(self.ship1.ship.getPos() / 15)
            self.ship_arrow.setR(self.ship1.ship.getR() +
                                 np.rad2deg(ast_critical1.azimuth))
            self.ship_arrow1.setPos(self.ship2.ship.getPos() / 15)
            self.ship_arrow1.setR(self.ship2.ship.getR() +
                                  np.rad2deg(ast_critical2.azimuth))
        # HUD End

        obs_state = (
            ship1_score,
            ship2_score,
            game_done,
            len(ship1_state),
            *ship1_state,
            len(ship1_obs),
            *ship1_obs,
            len(ship2_state),
            *ship2_state,
            len(ship2_obs),
            *ship2_obs,
        )

        if self.p3d_proto:
            self.p3d_proto.set_game_state('{}f'.format(len(obs_state)),
                                          obs_state, game_done)

        return game_done

    def net_update_action(self):
        """ upd 获取的动作输入 """
        action = {}
        if self.p3d_proto:
            action.update(self.p3d_proto.get_game_action())
        return action

    # Net Update End

    # Updates the positions of objects
    def updatePos(self, obj, dt):
        vel = self.getVelocity(obj)
        newPos = obj.getPos() + (vel * dt)

        # Check if the object is out of bounds. If so, wrap it
        radius = .5 * obj.getScale().getX()
        if newPos.getX() - radius > SCREEN_X:
            newPos.setX(-SCREEN_X)
        elif newPos.getX() + radius < -SCREEN_X:
            newPos.setX(SCREEN_X)
        if newPos.getZ() - radius > SCREEN_Y:
            newPos.setZ(-SCREEN_Y)
        elif newPos.getZ() + radius < -SCREEN_Y:
            newPos.setZ(SCREEN_Y)

        obj.setPos(newPos)

    # The handler when an asteroid is hit by a bullet
    def asteroidHit(self, index):
        # If the asteroid is small it is simply removed
        if self.asteroids[index].getScale().getX() <= AST_MIN_SCALE:
            self.asteroids[index].removeNode()
            # Remove the asteroid from the list of asteroids.
            del self.asteroids[index]
        else:
            # If it is big enough, divide it up into little asteroids.
            # First we update the current asteroid.
            asteroid = self.asteroids[index]
            newScale = asteroid.getScale().getX() * AST_SIZE_SCALE
            asteroid.setScale(newScale)  # Rescale it

            # The new direction is chosen as perpendicular to the old direction
            # This is determined using the cross product, which returns a
            # vector perpendicular to the two input vectors.  By crossing
            # velocity with a vector that goes into the screen, we get a vector
            # that is orthagonal to the original velocity in the screen plane.
            vel = self.getVelocity(asteroid)
            speed = vel.length() * AST_VEL_SCALE
            vel.normalize()
            vel = LVector3(0, 1, 0).cross(vel)
            vel *= speed
            self.setVelocity(asteroid, vel)

            # Now we create a new asteroid identical to the current one
            newAst = loadObject(scale=newScale)
            self.setVelocity(newAst, vel * -1)
            newAst.setPos(asteroid.getPos())
            newAst.setTexture(asteroid.getTexture(), 1)
            self.asteroids.append(newAst)
Beispiel #23
0
class CharGen():
    def __init__(self):
        self.text = "CharGen"
        self.textObject = OnscreenText(text=self.text,
                                       pos=(0.95, -0.95),
                                       scale=0.07,
                                       fg=(1, 0.5, 0.5, 1),
                                       align=TextNode.ACenter,
                                       mayChange=1)

        self.f = DirectFrame(frameColor=(1, 1, 1, 0.5),
                             frameSize=(-1, 1, -0.4, 0.4))
        self.f.setPos(-0.5, 0, -0.5)

        self.flavorText = OnscreenText("Primary Colour",
                                       pos=(0, 0, 0.4),
                                       scale=0.07,
                                       align=TextNode.ACenter,
                                       mayChange=1,
                                       fg=(1, 1, 1, 1))
        self.flavorText.reparent_to(self.f)
        self.flavorText.setPos(0, 0.2)
        #slider R
        self.sR = DirectSlider(self.f,
                               range=(0, 1),
                               value=0,
                               pageSize=3,
                               command=self.setCol)
        self.sR.setScale(0.5, 0.5, 0.5)
        self.sR.setPos(0, 0, 0)
        self.sR.setColor(1, 0, 0)

        #slider G
        self.sG = DirectSlider(self.f,
                               range=(0, 1),
                               value=0,
                               pageSize=3,
                               command=self.setCol)
        self.sG.setScale(0.5, 0.5, 0.5)
        self.sG.setPos(0, 0, -0.1)
        self.sG.setColor(0, 1, 0)

        #slider B
        self.sB = DirectSlider(self.f,
                               range=(0, 1),
                               value=0,
                               pageSize=3,
                               command=self.setCol)
        self.sB.setScale(0.5, 0.5, 0.5)
        self.sB.setPos(0, 0, -0.2)
        self.sB.setColor(0, 0, 1)

        self.pandaActor = Actor("models/panda-model",
                                {"walk": "models/panda-walk4"})
        self.pandaActor.setScale(0.005, 0.005, 0.005)
        self.pandaActor.setPos(0.8, 12, -0.5)
        self.pandaActor.reparentTo(base.render)

    def setCol(self):
        #print(self.s['value'])
        self.pandaActor.setColor(self.sR['value'], self.sG['value'],
                                 self.sB['value'])
class VirtualWorld(ShowBase): 

    def __init__(self, scene_file, pedestrian_file, dir, mode):
        ShowBase.__init__(self)

        self.globalClock = ClockObject.getGlobalClock()
        self.globalClock.setMode(ClockObject.MSlave)
        
        self.directory = dir
        self.model = Model(dir)
        self.loadScene(scene_file)
        self.loadPedestrians(pedestrian_file)
        
        self.cam_label = OST("Top Down", pos=(0, 0.95), fg=(1,1,1,1), 
                             scale=0.05, mayChange=True)
        self.time_label = OST("Time: 0.0", pos=(-1.3, 0.95), fg=(1,1,1,1), 
                              scale=0.06, mayChange=True, align=TextNode.ALeft)
                                       
        self.accept("arrow_right", self.changeCamera, [1])
        self.accept("arrow_left", self.changeCamera, [-1])
        self.accept("escape", self.exit)
        self.accept("aspectRatioChanged", self.setAspectRatio)
        self.accept("window-event", self.windowChanged)

        #base.disableMouse()
        lens = OrthographicLens()
        lens.setFilmSize(1550, 1000)
        self.display_region = base.win.makeDisplayRegion()
        self.default_camera = render.attachNewNode(Camera("top down"))
        self.default_camera.node().setLens(lens)
        self.default_camera.setPosHpr(Vec3( -75, 0, 2200), Vec3(0, -90, 0))

        self.setCamera(0)

        self.controller = Controller(self, mode)
        self.taskMgr.add(self.updateCameraModules, "Update Camera Modules", 80)
        
        self.globalClock.setFrameTime(0.0)
        self.width = WIDTH
        self.height = HEIGHT

        props = WindowProperties( ) 
        props.setTitle( 'Virtual Vision Simulator' ) 
        base.win.requestProperties( props ) 


    def getModel(self):
        """
        Returns the model that stores all of the cameras, pedestrians and 
        static objects in the scene.
        """
        return self.model


    def getController(self):
        """
        Returns a controller that is used to control the world time.
        """
        return self.controller


    def getTime(self):
        """
        Returns the current time in the world.
        """
        return self.globalClock.getFrameTime()


    def loadScene(self, scene_file):
        """
        Loads the static objects that make up the scene. Also loads the lights
        that illuminate the scene and for performance implications, sets what 
        lights affect what objects.
        """
        if not os.path.exists(scene_file):
            logging.error("The path '%s' does not exist" % scene_file)
            sys.exit()
        light_builder = LightBuilder(self)
        object_builder = ObjectBuilder(self, self.directory)
        parser = SceneFileParser(self.model, object_builder, light_builder)
        parser.parse(scene_file)
        
        self.setUpLights()


    def setUpLights(self):
        # Set what lights illuminate what objects
        light_list = self.model.getLightList()
        static_objects = self.model.getObjectList()
        for object in static_objects:
            if object.hasLighting():
                model_root = object.getModel().getChildren()[0]
                children = model_root.getChildren()
                for child in children:
                    light_map = {}
                    for index, light in enumerate(light_list):
                        distance = Length(child.getPos(render), light.getPos())
                        half_fov = light.node().getLens().getFov()[0] / 2.0
                        height = light.getPos()[2]
                        radius = height * tan(radians(half_fov))
                        if distance > radius ** 2 + 2500 + 10:
                            continue
                        if distance not in light_map:
                            light_map[distance] = [index]
                        else:
                            light_map[distance].append(index)

                    sorted_lights = sorted(light_map.keys())
                    light_count = 0
                    for key in sorted_lights:
                        for i in light_map[key]:
                            child.setLight(light_list[i])
                            light_count += 1
                            if light_count > LIGHTS_PER_OBJECT:
                                break
                        if light_count > LIGHTS_PER_OBJECT:
                            break
                    child.flattenStrong()
        
        # Apply a directional light to the static models        
        light_list = self.model.getLightList(DIRECTIONALLIGHT)
        if light_list:
            for object in static_objects:
                if object.hasLighting():
                    model_root = object.getModel().getChildren()[0]
                    model_root.setLight(light_list[0])

        render.setShaderAuto()
        render.setAntialias(AntialiasAttrib.MLine)


    def loadPedestrians(self, pedestrian_file):
        """Loads the pedestrians into the scene."""
        if not os.path.exists(pedestrian_file):
            logging.error("The path '%s' does not exist" % pedestrian_file)
            sys.exit()
        pedestrian_builder = PedestrianBuilder(self, "../media/characters/")
        parser = PedestrianFileParser(self.model, pedestrian_builder)
        parser.parse("../media/characters/pedestrians.xml")
        parser.parse(pedestrian_file)


    def addCamera(self, config):
        """
        This method is used to add a new panda camera to the world. The panda
        camera is returned so that it can be linked with a camera module.
        """
        type = config.type
        cam_builder = PandaCameraBuilder(self)
        if type == WIDE_FOV_CAMERA:
            pass
        else:
            camera = cam_builder.buildPandaPTZCamera(config)
            self.model.addCamera(camera)
        return camera


    def setAspectRatio(self):
        """
        This method is called when the aspect ratio of the window changes.
        It updates the aspect ratios of all the cameras.
        """
        width = base.win.getXSize()
        height = base.win.getYSize()
        ratio = self.camLens.getAspectRatio()
        camera_list = self.model.getCameraList()
        for camera in camera_list:
            camera.setAspectRatio(ratio)
            camera.setImageSize(width, height)

        self.default_camera.node().getLens().setAspectRatio(ratio)
        r =  width / float(height)
        self.time_label.setPos(-r, 0.95)


    def changeCamera(self, num):
        """
        This method is used to toggle the camera that is viewed in the main 
        window. Typically num is either 1 or -1 denoting whether to toggle up
        or down the camera list.
        """
        number = self.cur_camera + 1 + num
        num_cameras = len(self.model.getCameraList())
        if number > num_cameras:
            number = 0
        elif number < 0:
            number = num_cameras
        self.setCamera(number)


    def setCamera(self, num):
        """
        This method sets which cameras view is shown in the panda3d window.
        """
        if MANUAL_CAMERA:
            self.cur_camera = num -1
            return
        
        self.display_region.setClearColor(VBase4(0, 0, 0, 1))
        self.display_region.setClearColorActive(True)
        self.display_region.setClearDepthActive(True)
        if num == 0:
            self.cur_camera = -1
            self.display_region.setCamera(self.default_camera)
            self.cam_label.setText("Top Down")
        else:
            camera_list = self.model.getCameraList()
            index = num - 1
            if index < len(camera_list):
                self.cur_camera = index
                camera = camera_list[index]
                camera_np = camera.getCameraNode()
                self.display_region.setCamera(camera_np)
                name = camera.getName()
                status_label = camera.getStatusLabel()
                label = "%s: %s" %(name, status_label)
                self.cam_label.setText(label)


    def step(self, increment):
        """
        This method updates the world by one time step.
        """
        if increment:
            new_time = self.globalClock.getFrameTime() + increment
        else:
            new_time = self.globalClock.getRealTime()
            
        self.globalClock.setFrameTime(new_time)
        self.time_label.setText("Time: %.2f" % new_time)
        
        self.updateActors()
        self.updateCameras()


    def updateActors(self):
        """
        This method updates the pedestrians in the scene by calling their update
        functions.
        """
        pedestrians = self.model.getPedestrianList()
        time = self.getTime()
        for pedestrian in pedestrians:
            if pedestrian.isActive(time):
                pedestrian.update(time)


    def updateCameras(self):
        """
        This method updates the panda cameras which are used to provide the
        higher level camera modules with rendered images of the scene. There
        is one panda camera for each camera module.
        """
        time = self.getTime()
        camera_list = self.model.getCameraList()
        for camera in camera_list:
            camera.update(time)
        
        if self.cur_camera != -1:
            cur_camera = camera_list[self.cur_camera]
            if cur_camera.statusChanged():
                name = cur_camera.getName()
                status_label = cur_camera.getStatusLabel()
                label = "%s: %s" %(name, status_label)
                self.cam_label.setText(label)


    def updateCameraModules(self, task):
        """
        This method updates the camera modules by calling their update function.
        This allows the camera modules to process messages and complete any
        tasks that were assigned to them.
        """
        time = self.getTime()
        for camera in self.model.getCameraModules():
            camera.update(time)
        return Task.cont


    def windowChanged(self, window):
        """
        This function is called when the window is modified. It updates the
        image size used by the cameras when getting the rendered image from the 
        texture.
        """
        wp = window.getProperties()
        width = wp.getXSize()
        height = wp.getYSize()
        if width != self.width or height != self.height:
            self.width = width
            self.height = height
            camera_list = self.model.getCameraList()
            for camera in camera_list:
                camera.setImageSize(width, height)
        self.windowEvent(window)


    def exit(self):
        sys.exit()