def _renderItemsIcons(self): self.iconsNode.node().removeAllChildren() for icon in self.itemIcons: icon.destroy() self.itemIcons = [] startItem = 0 endItem = self.inventory.getSlotsCount() if self.itemsRange is not None: startItem = self.itemsRange[0] endItem = self.itemsRange[1] for i in xrange(endItem - startItem): itemNum = startItem + i s = self.inventory.getSlotByNum(itemNum) if not s.isFree(): # get slot position and size in aspect2d space p, sz = self.slotsLayout.getRelativeSlotPosSize(s.getNum()) itemImage = s.getItem().getImage() imagePath = self.game.getResources().getResourceFullPath( PanoConstants.RES_TYPE_TEXTURES, itemImage) iconNode = OnscreenImage(parent=self.iconsNode, image=imagePath, pos=(p[0] + sz[0] / 2.0, 0.0, p[1] + sz[1] / 2.0), scale=0.2) iconNode.setTransparency(TransparencyAttrib.MAlpha) iconNode.setBin("fixed", PanoConstants.RENDER_ORDER_INVENTORY_ITEMS) self.itemIcons.append(iconNode)
class SplashCard(object): '''this class shows up a splash message''' #------------------------------------------------------------ # def __init__(self, image, backgroundColor): self.loadingimage = OnscreenImage(image, color=(1, 1, 1, 1), scale=.5, parent=aspect2d) self.loadingimage.setTransparency(1) # this image will be on top of all therefore we use setBin 'fixed' and with the higher sort value self.loadingimage.setBin("fixed", 20) self.curtain = OnscreenImage('textures/curtain.png', parent=render2d, color=backgroundColor) self.curtain.setTransparency(1) # this is to set it below the loading panel self.curtain.setBin("fixed", 10) # the loading panel faders self.loadingOut = self.loadingimage.colorInterval(1, Vec4(1, 1, 1, 0), Vec4(1, 1, 1, 1)) # the black curtain faders self.openCurtain = self.curtain.colorScaleInterval(1, Vec4(1, 1, 1, 0), Vec4(1, 1, 1, 1)) for i in range(4): base.graphicsEngine.renderFrame() #------------------------------------------------------------ # def destroy(self): Sequence(self.loadingOut, self.openCurtain).start() #Sequence(self.openCurtain).start() #self.loadingimage.destroy() #self.curtain.destroy()
class ItemIcon(): def __init__(self, itemName, parentNode): print 'itemicon', itemName, parentNode self.parentNode = parentNode # The node of its parent (e.g. the inventory) self.itemName = itemName # The filename of the icon self.image = None # The actual icon #self.iconNode = aspect2d.attachNewNode('iconnode') self.LoadContent() def LoadContent(self): self.itemImage = OnscreenImage(image = "Assets/Images/Items/%s.png" % (self.itemName)) self.itemImage.setScale((self.itemImage.getTexture().getOrigFileXSize() / 1024.0, 1, self.itemImage.getTexture().getOrigFileYSize() / 1024.0)) self.itemImage.setTransparency(TransparencyAttrib.MAlpha) self.itemImage.reparentTo(self.parentNode) def setBin(self, binType, value): print 'set bin', binType, value self.itemImage.setBin(binType, value) def SetPos(self, pos): self.itemImage.setPos(pos) def Destroy(self): self.itemImage.destroy()
class SplashCard(object): '''this class shows up a splash message''' #------------------------------------------------------------ # def __init__(self, image, backgroundColor): self.loadingimage = OnscreenImage(image, color=(1, 1, 1, 1), scale=.5, parent=aspect2d) self.loadingimage.setTransparency(1) # this image will be on top of all therefore we use setBin 'fixed' and with the higher sort value self.loadingimage.setBin("fixed", 20) self.curtain = OnscreenImage('textures/curtain.png', parent=render2d, color=backgroundColor) self.curtain.setTransparency(1) # this is to set it below the loading panel self.curtain.setBin("fixed", 10) # the loading panel faders self.loadingOut = self.loadingimage.colorInterval( 1, Vec4(1, 1, 1, 0), Vec4(1, 1, 1, 1)) # the black curtain faders self.openCurtain = self.curtain.colorScaleInterval( 1, Vec4(1, 1, 1, 0), Vec4(1, 1, 1, 1)) for i in range(4): base.graphicsEngine.renderFrame() #------------------------------------------------------------ # def destroy(self): Sequence(self.loadingOut, self.openCurtain).start()
class RankingGui(Gui): def __init__(self, mdt, background, font, fg_col): Gui.__init__(self, mdt) self.ranking_texts = [] self.background_path = background self.font = font self.fg_col = fg_col def show(self): self.background = OnscreenImage(self.background_path, scale=(1.77778, 1, 1.0)) self.background.setBin('background', 10) items = self.mdt.logic.ranking.items() sorted_ranking = reversed(sorted(items, key=lambda el: el[1])) font = eng.load_font(self.font) self.ranking_texts = [] for i, (name, score) in enumerate(sorted_ranking): txt = OnscreenText('%s %s' % (name, score), pos=(0, .5 - .2 * i), font=font, fg=self.fg_col, scale=.12) self.ranking_texts += [txt] def hide(self): map(lambda wdg: wdg.destroy(), self.ranking_texts + [self.background]) def destroy(self): self.ranking_texts = None Gui.destroy(self)
def LoadContent(self): bg = OnscreenImage(image = 'Assets/Images/Menus/MainMenu/background.png', scale = (2, 1, 1)) bg.setTransparency(TransparencyAttrib.MAlpha) bg.reparentTo(self.node) bg.setBin('fixed', 1) title = OnscreenImage(image = 'Assets/Images/Menus/MainMenu/title.png') title.setTransparency(TransparencyAttrib.MAlpha) title.reparentTo(self.node) self.spinner = OnscreenImage(image = 'Assets/Images/Menus/MainMenu/loadingSpinner.png', pos = (-0.15, 1, 0.15), scale = 128.0/1024.0) self.spinner.setTransparency(TransparencyAttrib.MAlpha) self.spinner.reparentTo(base.a2dBottomRight) self.spinner.setBin('gui-popup', 0) self.spinner.hide() self.LoadButton('Button_Offline', 'offline', 'offline_over', 0, 0.2, self.OnButtonClicked, ['offline']) self.LoadButton('Button_Multiplayer', 'multiplayer', 'multiplayer_over', 0, 0, self.OnButtonClicked, ['multiplayer']) self.LoadButton('Button_Options', 'options', 'options_over', 0, -0.2, self.OnButtonClicked, ['options']) self.LoadButton('Button_Exit', 'exit', 'exit_over', 0, -0.4, self.OnButtonClicked, ['exit'])
class TuningGui(Gui): def __init__(self, mdt, tuninggui_props): Gui.__init__(self, mdt) self.props = tuninggui_props def show(self): self.background = OnscreenImage(self.props.background, scale=(1.77778, 1, 1.0)) self.background.setBin('background', 10) self.buttons = [ ImageButton(scale=.4, pos=(-1.2, 1, .1), frameColor=(0, 0, 0, 0), image=self.props.tuning_imgs[0], command=self.on_btn, extraArgs=['engine']) ] self.buttons += [ ImageButton(scale=.4, pos=(0, 1, .1), frameColor=(0, 0, 0, 0), image=self.props.tuning_imgs[1], command=self.on_btn, extraArgs=['tires']) ] self.buttons += [ ImageButton(scale=.4, pos=(1.2, 1, .1), frameColor=(0, 0, 0, 0), image=self.props.tuning_imgs[2], command=self.on_btn, extraArgs=['suspensions']) ] def on_btn(self, val): tun = self.mdt.logic.tunings[self.props.car] setattr(tun, val, getattr(tun, val) + 1) self.notify('on_tuning_done') def hide(self): map(lambda wdg: wdg.destroy(), self.buttons + [self.background])
class Cursor: def __init__(self, path, scale, hotspot): if not path: return self.__set_standard_curson(False) self.cursor_img = OnscreenImage(path) self.cursor_img.setTransparency(True) self.cursor_img.setScale(scale) self.cursor_img.setBin('gui-popup', 50) self.hotspot_dx = scale[0] * (1 - 2 * hotspot[0]) self.hotspot_dy = scale[2] * (1 - 2 * hotspot[1]) eng.event.attach(self.on_frame) def __set_standard_curson(self, show): props = WindowProperties() props.setCursorHidden(not show) base.win.requestProperties(props) def show(self): self.cursor_img.show() def show_standard(self): self.__set_standard_curson(True) def hide(self): self.cursor_img.hide() def hide_standard(self): self.__set_standard_curson(False) def cursor_top(self): self.cursor_img.reparent_to(self.cursor_img.get_parent()) def on_frame(self): if base.mouseWatcherNode.hasMouse(): x = base.mouseWatcherNode.getMouseX() y = base.mouseWatcherNode.getMouseY() h_x = x * base.getAspectRatio() + self.hotspot_dx self.cursor_img.setPos(h_x, 0, y - self.hotspot_dy)
class InventoryView: """ Renders the inventory screen. """ ButtonStateNormal = 1 ButtonStatePressed = 2 ButtonStateHover = 3 POINTER_NAME = "inventory_pointer" INVENTORY_SCENE_NODE = "inventory_sceneNode" ICONS_NODE = "inventory_icons_node" BACKDROP_NODE = "backdrop" TEXT_NODE = "item_text" def __init__(self, game): self.log = logging.getLogger('pano.inventoryView') self.game = game self.msn = Messenger( self ) # the messenger is used to broadcast user events related to the interface self.inventory = None # the inventory to render self.node = None # the root scenegraph node for inventory rendering nodes self.iconsNode = None # the parent node for all OnscreenImages that render items' icons self.pos = (0.0, 0.0) # position in absolute screen coordinates self.size = (1.0, 1.0) # size in absolute screen coordinates self.textPos = (0.0, 0.0) # position of the item's description text self.textScale = 0.07 # the text scale self.opacity = 1.0 # controls the opacity of all rendering elements included in the inventory self.backdropImage = None # the name of the image to use as a backdrop self.backdropImageObject = None # the OnscreenImage object used to render the backdrop self.backdropNode = None # the scenegraph node that parents the backdrop self.updateIcons = False # if True then we need to update the rendering of the items' icons self.itemText = None # the TextNode used to render the text self.itemTextNode = None # nodepath that acts as a parent to the TextNode self.fontName = None # the name of the font to use when rendering items' descriptions self.font = None # the Panda3D font resource self.fontColor = (1.0, 1.0, 1.0, 1.0 ) # colour of the text for an item's description self.fontBgColor = (0.0, 0.0, 0.0, 1.0 ) # background colour of the text # scrolling and paging buttons are DirectButton instances self.nextPageButton = None self.prevPageButton = None self.scrollNextButton = None self.scrollPrevButton = None # specifies the range of items to be rendered in the next frame as a list [start_item_index, end_item_index] # used for scrolling and paging self.itemsRange = None # number of items displayed per page self.pageSize = 0 # provides the layout of the slots self.slotsLayout = None # stores image objects for each item's icon self.itemIcons = [] self.mousePointer = InventoryView.POINTER_NAME self.debugLayout = False def initialize(self, inventory): """ Initialises the inventory, call this method only once otherwise resources could be leaked and rendering artifacts created. """ if self.node is not None: self.node.removeNode() # self.node.detachNode() self.node = aspect2d.attachNewNode(InventoryView.INVENTORY_SCENE_NODE) self.iconsNode = self.node.attachNewNode(InventoryView.ICONS_NODE) # from here on we just initialize the member fields according to the cvars... cfg = self.game.getConfig() if not self._validateConfig(cfg): self.log.error('Missing or invalid inventory configuration') return view = self.game.getView() if self.backdropImageObject is not None: self.backdropImageObject.destroy() self.backdropImageObject = None self.pos = cfg.getVec2(PanoConstants.CVAR_INVENTORY_POS) if self.pos is None: self.pos = cfg.getVec2(PanoConstants.CVAR_INVENTORY_REL_POS) self.pos = view.relativeToAbsolute(self.pos) self.textPos = cfg.getVec2(PanoConstants.CVAR_INVENTORY_TEXT_POS) if self.textPos is None: self.textPos = cfg.getVec2(PanoConstants.CVAR_INVENTORY_REL_POS) self.textPos = view.relativeToAbsolute(self.textPos) self.pos, self.textPos = PandaUtil.convertScreenToAspectCoords( [self.pos, self.textPos]) self.size = cfg.getVec2(PanoConstants.CVAR_INVENTORY_SIZE, (1.0, 1.0)) self.textScale = cfg.getFloat(PanoConstants.CVAR_INVENTORY_TEXT_SCALE, 0.07) self.opacity = cfg.getFloat(PanoConstants.CVAR_INVENTORY_OPACITY) self.fontName = cfg.get(PanoConstants.CVAR_INVENTORY_FONT) self.fontColor = cfg.getVec4(PanoConstants.CVAR_INVENTORY_FONT_COLOR) if self.fontColor is None: self.fontColor = (1.0, 1.0, 1.0, 1.0) self.fontBgColor = cfg.getVec4( PanoConstants.CVAR_INVENTORY_FONT_BG_COLOR) if self.fontBgColor is None: self.fontBgColor = (0.0, 0.0, 0.0, 0.0) self.mousePointer = cfg.get(PanoConstants.CVAR_INVENTORY_POINTER) layout = cfg.get(PanoConstants.CVAR_INVENTORY_SLOTS) self._parseLayout(layout) slotsCount = self.slotsLayout.getNumSlots() self.log.debug('Setting slots count to %i' % slotsCount) # by default render all items, the controller state can later overridde this self.itemsRange = [0, slotsCount] if cfg.hasVar(PanoConstants.CVAR_INVENTORY_PAGESIZE): self.pageSize = cfg.getInt(PanoConstants.CVAR_INVENTORY_PAGESIZE) else: self.pageSize = slotsCount self.inventory = inventory self.inventory.setSlotsCount(slotsCount) self.backdropImage = cfg.get(PanoConstants.CVAR_INVENTORY_BACKDROP) if self.backdropImage is not None: self._createBackdrop(show=False) # create the scrolling and paging gui buttons self._createButtons(cfg) # force an initial rendering of the icons self.updateIcons = True # start as hidden self.node.hide() def update(self, millis): """ Re-renders anything that has updated. """ if self.isVisible() and self.updateIcons: self._renderItemsIcons() self.updateIcons = False def redraw(self): """ Called to indicate that the underlying inventory has updated its state and now we should redraw it. """ self.updateIcons = True def show(self): """ Shows the inventory. """ self.node.show() if self.nextPageButton: self.nextPageButton.show() if self.prevPageButton: self.prevPageButton.show() if self.scrollNextButton: self.scrollNextButton.show() if self.scrollPrevButton: self.scrollPrevButton.show() if self.debugLayout: self.enableDebugRendering() def hide(self): """ Hides the inventory. """ self.node.hide() if self.nextPageButton: self.nextPageButton.hide() if self.prevPageButton: self.prevPageButton.hide() if self.scrollNextButton: self.scrollNextButton.hide() if self.scrollPrevButton: self.scrollPrevButton.hide() if self.debugLayout: self.disableDebugRendering() def isVisible(self): """ Returns True if the inventory is visible and False if otherwise. """ return (self.node is not None) and (not self.node.isHidden()) def getMousePointerName(self): return self.mousePointer def getSlotAtScreenPos(self, x, y): return self.slotsLayout.getSlotAtScreenPos(x, y) def getBackdropImage(self): return self.backdropImage def setBackdropImage(self, imageName): self.backdropImage = imageName self._createBackdrop() def getText(self): return self.text def setText(self, text): self.text = text self._updateText() def clearText(self): self.text = "" if self.itemTextNode is not None: self.itemTextNode.hide() def getNode(self): return self.node def enableDebugRendering(self): self.slotsLayout.enableDebugRendering(self.game) self.debugLayout = True def disableDebugRendering(self): self.slotsLayout.disableDebugRendering(self.game) self.debugLayout = False def _validateConfig(self, config): return (config.hasVar(PanoConstants.CVAR_INVENTORY_BACKDROP) and (config.hasVar(PanoConstants.CVAR_INVENTORY_POS) or config.hasVar(PanoConstants.CVAR_INVENTORY_REL_POS)) and (config.hasVar(PanoConstants.CVAR_INVENTORY_TEXT_POS) or config.hasVar(PanoConstants.CVAR_INVENTORY_REL_POS)) and config.hasVar(PanoConstants.CVAR_INVENTORY_SIZE) and config.hasVar(PanoConstants.CVAR_INVENTORY_FONT) and config.hasVar(PanoConstants.CVAR_INVENTORY_POINTER) and config.hasVar(PanoConstants.CVAR_INVENTORY_SLOTS)) def _createBackdrop(self, show=True): """ Setups rendering for the inventory's backdrop image. The backdrop image is rendered through a OnscreenImage object and is attached under the scenegraph node named Inventory.BACKDROP_NODE. If the parameter show is True then the backdrop image becomes visible as well, otherwise it is hidden. """ if self.backdropImageObject is not None: self.backdropImageObject.destroy() self.backdropImageObject = None if self.backdropNode is not None: self.backdropNode.removeNode() imagePath = self.game.getResources().getResourceFullPath( PanoConstants.RES_TYPE_TEXTURES, self.backdropImage) self.backdropNode = self.node.attachNewNode( InventoryView.BACKDROP_NODE) self.backdropImageObject = OnscreenImage(parent=self.node, image=imagePath, pos=(self.pos[0], 0.0, self.pos[1]), sort=0) self.backdropImageObject.setTransparency(TransparencyAttrib.MAlpha) self.backdropImageObject.setBin("fixed", PanoConstants.RENDER_ORDER_INVENTORY) if not show: self.backdropNode.hide() def _updateText(self): if self.itemText is not None: self.itemText.destroy() self.itemText = None if self.itemTextNode is None: self.itemTextNode = self.node.attachNewNode(self.TEXT_NODE) self.itemTextNode.setPos(self.textPos[0], 0.0, self.textPos[1]) self.itemTextNode.show() i18n = self.game.getI18n() translated = i18n.translate(self.text) localizedFont = i18n.getLocalizedFont(self.fontName) fontPath = self.game.getResources().getResourceFullPath( PanoConstants.RES_TYPE_FONTS, localizedFont) self.font = loader.loadFont(fontPath) self.itemText = DirectButton( parent=self.itemTextNode, text=translated, text_font=self.font, text_bg=(self.fontBgColor[0], self.fontBgColor[1], self.fontBgColor[2], self.fontBgColor[3]), text_fg=(self.fontColor[0], self.fontColor[1], self.fontColor[2], self.fontColor[3]), text_scale=self.textScale, frameColor=(0, 0, 0, 0), text_wordwrap=None, text_align=TextNode.ALeft, sortOrder=10, pressEffect=0) self.itemText.setBin("fixed", PanoConstants.RENDER_ORDER_INVENTORY_ITEMS) def _parseLayout(self, layoutName): layoutName = layoutName.strip() if layoutName.startswith('grid'): # pos, res, size, offset grid_re = re.compile( r'grid\(\s*(\d+)\D+(\d+)\D+(\d+)\D+(\d+)\D+(\d+)\D+(\d+)\D+(\d+)\D+(\d+)\D+' ) m = grid_re.match(layoutName) self.slotsLayout = GridSlotsLayout( self.game, (int(m.group(1)) + self.pos[0], int(m.group(2)) + self.pos[1]), # position within inventory (int(m.group(3)), int(m.group(4))), # grid resolution (int(m.group(5)), int(m.group(6))), # slot size (int(m.group(7)), int(m.group(8)))) # slots offset elif layoutName.starts_with('image'): self.slotsLayout = ImageBasedSlotsProvider(layoutName) # a default to avoid None else: self.slotsLayout = GridSlotsLayout(self.game, 100, 100, 5, 5, 50, 50) def _renderItemsIcons(self): self.iconsNode.node().removeAllChildren() for icon in self.itemIcons: icon.destroy() self.itemIcons = [] startItem = 0 endItem = self.inventory.getSlotsCount() if self.itemsRange is not None: startItem = self.itemsRange[0] endItem = self.itemsRange[1] for i in xrange(endItem - startItem): itemNum = startItem + i s = self.inventory.getSlotByNum(itemNum) if not s.isFree(): # get slot position and size in aspect2d space p, sz = self.slotsLayout.getRelativeSlotPosSize(s.getNum()) itemImage = s.getItem().getImage() imagePath = self.game.getResources().getResourceFullPath( PanoConstants.RES_TYPE_TEXTURES, itemImage) iconNode = OnscreenImage(parent=self.iconsNode, image=imagePath, pos=(p[0] + sz[0] / 2.0, 0.0, p[1] + sz[1] / 2.0), scale=0.2) iconNode.setTransparency(TransparencyAttrib.MAlpha) iconNode.setBin("fixed", PanoConstants.RENDER_ORDER_INVENTORY_ITEMS) self.itemIcons.append(iconNode) def _createButtons(self, cfg): ''' Creates DirectGui elements for displaying the paging and scrolling buttons. The sprite names are read from the configuration. The create DirectButtons use sprites as images. @param cfg: a ConfigVars instance ''' # button to display next page of items nxPgBtnSprite = cfg.get(PanoConstants.CVAR_INVENTORY_NEXTPAGE_SPRITE) nxPgBtnPressedSprite = cfg.get( PanoConstants.CVAR_INVENTORY_NEXTPAGE_PRESSED_SPRITE) nxPgBtnHoverSprite = cfg.get( PanoConstants.CVAR_INVENTORY_NEXTPAGE_HOVER_SPRITE) nxPgBtnPos = cfg.getVec2(PanoConstants.CVAR_INVENTORY_NEXTPAGE_POS) # button to display previous page of items pvPgBtnSprite = cfg.get(PanoConstants.CVAR_INVENTORY_PREVPAGE_SPRITE) pvPgBtnPressedSprite = cfg.get( PanoConstants.CVAR_INVENTORY_PREVPAGE_PRESSED_SPRITE) pvPgBtnHoverSprite = cfg.get( PanoConstants.CVAR_INVENTORY_PREVPAGE_HOVER_SPRITE) pvPgBtnPos = cfg.getVec2(PanoConstants.CVAR_INVENTORY_PREVPAGE_POS) # button to scroll to next items scrNxBtnSprite = cfg.get( PanoConstants.CVAR_INVENTORY_SCROLLNEXT_SPRITE) scrNxBtnPressedSprite = cfg.get( PanoConstants.CVAR_INVENTORY_SCROLLNEXT_PRESSED_SPRITE) scrNxBtnHoverSprite = cfg.get( PanoConstants.CVAR_INVENTORY_SCROLLNEXT_HOVER_SPRITE) scrNxBtnPos = cfg.getVec2(PanoConstants.CVAR_INVENTORY_SCROLLNEXT_POS) # button to scroll to previous items scrPvBtnSprite = cfg.get( PanoConstants.CVAR_INVENTORY_SCROLLPREV_SPRITE) scrPvBtnPressedSprite = cfg.get( PanoConstants.CVAR_INVENTORY_SCROLLPREV_PRESSED_SPRITE) scrPvBtnHoverSprite = cfg.get( PanoConstants.CVAR_INVENTORY_SCROLLPREV_HOVER_SPRITE) scrPvBtnPos = cfg.getVec2(PanoConstants.CVAR_INVENTORY_SCROLLPREV_POS) sprites = self.game.getView().getSpritesFactory() origin = aspect2d.getRelativePoint(screen2d, VBase3(0, 0, 0)) # for every button define property name, position, callback, list of sprites for normal, pressed and hover state pagingButtons = [ ('nextPageButton', nxPgBtnPos, self._nextPageCallback, [(nxPgBtnSprite, 'next_page_sprite'), (nxPgBtnPressedSprite, 'next_page_pressed_sprite'), (nxPgBtnHoverSprite, 'next_page_hover_sprite')]), ('prevPageButton', pvPgBtnPos, self._previousPageCallback, [(pvPgBtnSprite, 'previous_page_sprite'), (pvPgBtnPressedSprite, 'previous_page_pressed_sprite'), (pvPgBtnHoverSprite, 'previous_page_hover_sprite')]), ('scrollNextButton', scrNxBtnPos, self._scrollNextCallback, [(scrNxBtnSprite, 'scroll_next_sprite'), (scrNxBtnPressedSprite, 'scroll_next_pressed_sprite'), (scrNxBtnHoverSprite, 'scroll_next_hover_sprite')]), ('scrollPrevButton', scrPvBtnPos, self._scrollPreviousCallback, [(scrPvBtnSprite, 'scroll_previous_sprite'), (scrPvBtnPressedSprite, 'scroll_previous_pressed_sprite'), (scrPvBtnHoverSprite, 'scroll_previous_hover_sprite')]), ] for buttonName, buttonPos, buttonCallback, spritesList in pagingButtons: buttonGeoms = [None, None, None, None] btnScrBounds = [0, 0, 0] i = 0 for spriteFile, spriteName in spritesList: print 'adding sprite %s' % spriteName if spriteFile is not None: spr = None if spriteFile.rindex('.') >= 0: ext = spriteFile[spriteFile.rindex('.'):] print ext if ResourcesTypes.isExtensionOfType( ext, PanoConstants.RES_TYPE_IMAGES): spr = Sprite(spriteName) spr.image = spriteFile else: spr = self.game.getResources().loadSprite(spriteFile) if spr: buttonGeoms[i] = sprites.createSprite(spr).nodepath buttonGeoms[i].setScale(1.0) btnScrBounds = aspect2d.getRelativePoint( screen2d, VBase3(spr.width, 1.0, spr.height)) - origin btnScrBounds[2] *= -1 i += 1 if buttonGeoms[0] is not None: b = DirectButton( geom=(buttonGeoms[0], buttonGeoms[1] if buttonGeoms[1] else buttonGeoms[0], buttonGeoms[2] if buttonGeoms[2] else buttonGeoms[0], buttonGeoms[3] if buttonGeoms[3] else buttonGeoms[0]), relief=None) b['geom_pos'] = (0, 0, 0) b.setTransparency(1) # if position is omitted from the configuration, put the button on the upper left corner if buttonPos is not None: b.setPos( aspect2d.getRelativePoint( screen2d, VBase3(buttonPos[0], 1.0, buttonPos[1]))) else: b.setPos(origin[0], 1.0, origin[2]) b.setScale(btnScrBounds[0], 1.0, btnScrBounds[2]) b.setFrameSize((0, btnScrBounds[0], 1.0, btnScrBounds[2])) b['command'] = buttonCallback b['extraArgs'] = (self.msn, ) b.hide() else: b = None setattr(self, buttonName, b) def _nextPageCallback(self, messenger): ''' Callback for next page button which only sends the appropriate message. ''' messenger.sendMessage(PanoConstants.EVENT_ITEMS_NEXT_PAGE) def _previousPageCallback(self, messenger): messenger.sendMessage(PanoConstants.EVENT_ITEMS_PREV_PAGE) def _scrollNextCallback(self, messenger): messenger.sendMessage(PanoConstants.EVENT_ITEMS_SCROLL_NEXT) def _scrollPreviousCallback(self, messenger): messenger.sendMessage(PanoConstants.EVENT_ITEMS_SCROLL_PREV)
class MainMenu(DirectObject): def __init__(self, skipIntro=False): render.show() engine.Mouse.showCursor() # In case we just got back from the tutorial, which hides everything # sometimes. engine.renderLit.show() self.backgroundSound = audio.FlatSound("menu/background.ogg", volume=0.3) self.backgroundSound.setVolume(0) self.backgroundSound.setLoop(True) self.clickSound = audio.FlatSound("menu/click.ogg", volume=0.3) self.active = True self.accept("escape", self.escape) self.accept("mouse1", self.click) self.cameraDistance = 20 self.globe = engine.loadModel("menu/Globe") self.globe.reparentTo(render) self.globe.setTransparency(TransparencyAttrib.MAlpha) self.globe.setColor(Vec4(1, 1, 1, 0.6)) self.globe.setTwoSided(True) self.globe.setRenderModeWireframe() self.overlay = camera.attachNewNode("overlay") self.overlay.setTransparency(TransparencyAttrib.MAlpha) self.overlay.setColor(Vec4(1, 1, 1, 0)) self.overlay.setPos(0, 0, 0) self.overlay.setPos(0, self.cameraDistance, 0) self.overlay1 = engine.loadModel("menu/overlay1") self.overlay1.setScale(4) self.overlay1.setTwoSided(True) self.overlay1.setRenderModeWireframe() self.overlay1.reparentTo(self.overlay) self.overlay2 = engine.loadModel("menu/overlay2") self.overlay2.setScale(4) self.overlay2.setTwoSided(True) self.overlay2.setRenderModeWireframe() self.overlay2.reparentTo(self.overlay) self.overlay3 = engine.loadModel("menu/overlay3") self.overlay3.setScale(4) self.overlay3.setTwoSided(True) self.overlay3.setRenderModeWireframe() self.overlay3.setR(uniform(0, 360)) self.overlay3.setP(uniform(0, 360)) self.overlay3.setH(uniform(0, 360)) self.overlay3.reparentTo(self.overlay) self.overlay4 = engine.loadModel("menu/overlay3") self.overlay4.setScale(4) self.overlay4.setTwoSided(True) self.overlay4.setRenderModeWireframe() self.overlay4.setH(uniform(0, 360)) self.overlay4.setR(uniform(0, 360)) self.overlay4.setP(uniform(0, 360)) self.overlay4.reparentTo(self.overlay) self.text = engine.loadModel("menu/text") self.text.setScale(4) self.text.setTwoSided(True) self.text.reparentTo(self.overlay) self.selector = engine.loadModel("menu/selector") self.selector.setScale(4) self.selector.setTwoSided(True) self.selector.reparentTo(self.overlay) self.selectedItem = 0 self.skyBox = engine.loadModel("menu/skybox") self.skyBox.setScale(self.cameraDistance * 5) self.skyBox.setRenderModeWireframe() self.skyBox.setTwoSided(True) self.skyBox.reparentTo(render) self.skyBox.setTransparency(TransparencyAttrib.MAlpha) self.skyBox.setColor(Vec4(1, 1, 1, 0)) cmbg = CardMaker("background") size = 10 cmbg.setFrame(-size * engine.aspectRatio, size * engine.aspectRatio, -size, size) self.background = camera.attachNewNode(cmbg.generate()) self.background.setTexture(loader.loadTexture("menu/background.jpg"), 1) self.background.setPos(0, size * 1.25, 0) self.background.setDepthWrite(False) self.belt = JunkBelt(5) self.angle = uniform(0, 360) self.period = 60 self.uiAngle = 0 self.logo = OnscreenImage(image="menu/logo.png", pos=(0, 0, 0), scale=((512.0 / 175.0) * 0.075, 0, 0.075)) self.logo.setTransparency(TransparencyAttrib.MAlpha) self.logo.setColor(1, 1, 1, 0) self.logo.setBin("transparent", 0) self.loadingScreen = OnscreenImage(image="menu/loading.jpg", pos=(0, 0, 0)) self.loadingScreen.setScale(render2d, VBase3(1)) self.loadingScreen.setSx(2) self.loadingScreen.hide() self.skipToEndOfTutorial = skipIntro global firstBoot firstBoot = False self.introTime = 2 if firstBoot and not skipIntro: self.introTime = 4 self.showLogin = firstBoot self.hostList = ui.HostList(self.startClient) self.mapList = ui.MapList(self.startServer) self.loginDialog = ui.LoginDialog(self.setUsername) self.loginDialogShown = False self.introSound = audio.FlatSound("menu/intro.ogg", volume=0.15) self.introSound.play() self.clientConnectAddress = None self.serverMapName = None self.serverMode = 0 # 0 for normal, 1 for tutorial self.serverGameType = 0 # 0 for deathmatch, 1 for survival self.username = "******" self.startTime = -1 self.goTime = -1 if base.appRunner is not None: token = base.appRunner.getToken("username") if token != "" and token != "Unnamed": self.setUsername(token) self.loginDialogShown = True def escape(self): if self.hostList.visible: self.hostList.hide() elif self.mapList.visible: self.mapList.hide() def startClient(self, host): self.clickSound.play() self.hostList.hide() self.loadingScreen.show() self.clientConnectAddress = host self.goTime = engine.clock.time def startServer(self, map, gametype): # Tutorial works on Point Control maps. if not (self.serverMode == 1 and gametype == 1): self.clickSound.play() self.mapList.hide() self.loadingScreen.show() self.serverMapName = map self.serverGameType = gametype self.goTime = engine.clock.time def setUsername(self, username): self.clickSound.play() self.username = username engine.savedUsername = self.username engine.saveConfigFile() self.loginDialog.hide() def update(self): if not self.active: return net.context.readTick() if self.startTime == -1: self.startTime = engine.clock.time elapsedTime = engine.clock.time - self.startTime if elapsedTime < self.introTime: blend = elapsedTime / self.introTime self.angle += engine.clock.timeStep * (1 - blend) self.cameraDistance = 20 + (1 - blend)**2 * 200 elif elapsedTime < self.introTime + 2: self.cameraDistance = 20 blend = (elapsedTime - self.introTime) / 2 self.overlay.setColor(Vec4(1, 1, 1, blend)) self.logo.setColor(1, 1, 1, blend) self.skyBox.setColor(Vec4(1, 1, 1, blend)) if not self.backgroundSound.isPlaying(): self.backgroundSound.play() self.backgroundSound.setVolume(blend * 0.5) else: self.cameraDistance = 20 self.overlay.setColor(Vec4(1, 1, 1, 1)) self.logo.setColor(1, 1, 1, 1) self.skyBox.setColor(Vec4(1, 1, 1, 1)) self.backgroundSound.setVolume(0.5) if elapsedTime > self.introTime: if not self.loginDialogShown and self.showLogin: self.loginDialog.show() self.loginDialogShown = True self.uiAngle -= engine.clock.timeStep * 2 self.text.setR(self.uiAngle) self.hostList.update() self.mapList.update() self.loginDialog.update() mouse = base.win.getPointer(0) props = base.win.getProperties() vector = Vec3((mouse.getX() / float(props.getXSize())) - 0.5, (mouse.getY() / float(props.getYSize())) - 0.5, 0) vector.normalize() angle = math.degrees(math.atan2(-vector.getX(), vector.getY())) + 180 angle -= self.uiAngle if not self.hostList.visible and not self.mapList.visible and not self.loginDialog.visible: self.selectedItem = int(round(angle / 90.0)) while self.selectedItem > 3: self.selectedItem -= 4 while self.selectedItem < 0: self.selectedItem += 4 self.selector.setR(self.uiAngle + self.selectedItem * 90) self.overlay1.setR(self.overlay1.getR() - engine.clock.timeStep * 2) self.overlay2.setR(self.overlay2.getR() + engine.clock.timeStep * 2) self.overlay3.setH(self.overlay3.getH() + engine.clock.timeStep * 10) self.overlay4.setP(self.overlay4.getP() - engine.clock.timeStep * 10) self.belt.update() self.angle += engine.clock.timeStep * 0.025 camera.setPos( math.cos(self.angle) * self.cameraDistance, math.sin(self.angle) * self.cameraDistance, math.cos(elapsedTime / 45 + 2) * 2) camera.lookAt(Point3(0, 0, 0)) backend = None game = None if self.goTime != -1 and engine.clock.time - self.goTime > 0.25: if self.clientConnectAddress is not None: self.delete() online.connectTo(self.clientConnectAddress) backend = ClientBackend(self.clientConnectAddress, self.username) game = Game(backend) elif self.serverMapName is not None: if self.serverMode == 0: # Normal server mode self.delete() if self.serverGameType == 0: backend = PointControlBackend( True, self.username) # Deathmatch else: backend = SurvivalBackend(True, self.username) # Survival game = Game(backend) game.localStart(self.serverMapName) elif self.serverMode == 1: # Tutorial mode self.delete() backend = PointControlBackend(False, self.username) game = Tutorial(backend, 2 if self.skipToEndOfTutorial else 0) game.localStart(self.serverMapName) net.context.writeTick() return backend, game def click(self): if self.mapList.visible or self.hostList.visible or self.loginDialog.visible or engine.clock.time - \ self.startTime < self.introTime + 0.5: return self.clickSound.play() if self.selectedItem == 0: # Join self.hostList.show() elif self.selectedItem == 1: # Tutorial self.mapList.show() self.serverMode = 1 elif self.selectedItem == 2: # Exit engine.exit() elif self.selectedItem == 3: # Host self.mapList.show() self.serverMode = 0 def delete(self): self.loadingScreen.destroy() self.hostList.delete() self.mapList.delete() self.loginDialog.delete() self.active = False self.overlay.removeNode() self.belt.delete() self.background.removeNode() self.globe.removeNode() self.skyBox.removeNode() self.ignoreAll() self.logo.destroy() self.introSound.stop() self.backgroundSound.stop()
class RankingGui(GuiColleague): def __init__(self, mediator, background_fpath, font, fg_col): GuiColleague.__init__(self, mediator) self.ranking_texts = [] self.background_path = background_fpath self.font = font self.fg_col = fg_col self.rank_menu = self.background = None @staticmethod def set_drv_txt_img(page, i, car_name, pos_x, top, text, players): drivers = [player.driver for player in players] info('drivers: ' + str([drv for drv in drivers])) info('i: %s - carname: %s - text: %s' % (i, car_name, text)) drv = next(player.driver for player in players if player.car == car_name) player_car_names = [ player.car for player in players if player.kind == Player.human ] is_player_car = car_name in player_car_names info('%s %s %s %s' % (text % drv.name, car_name, drv.img_idx, is_player_car)) name = text % drv.name if '@' in name: name = name.split('@')[0] + '\1smaller\1@' + name.split('@')[1] + \ '\2' txt = Text(name, align='left', scale=.072, pos=(pos_x, top - i * .16), font=page.font, fg=page.text_fg if is_player_car else page.text_bg) gprops = page.rprops.season_props.gameprops img = Img(gprops.cars_img % car_name, pos=(pos_x - .16, top + .02 - i * .16), scale=.074) filtervpath = RankingGui.eng.curr_path + \ 'yyagl/assets/shaders/filter.vert' with open(filtervpath) as fvs: vert = fvs.read() drvfpath = RankingGui.eng.curr_path + \ 'yyagl/assets/shaders/drv_car.frag' with open(drvfpath) as ffs: frag = ffs.read() shader = load_shader(vert, frag) if shader: img.set_shader(shader) img.set_transparent() t_s = TextureStage('ts') t_s.set_mode(TextureStage.MDecal) txt_path = gprops.drivers_img.path_sel % drv.img_idx img.set_texture(t_s, loader.loadTexture(txt_path)) return txt, img def show(self, rprops, sprops, ranking, players): self.background = OnscreenImage( sprops.gameprops.menu_props.background_img_path, scale=(1.77778, 1, 1)) self.background.setBin('background', 10) self.rank_menu = RankingMenu(rprops, sprops, ranking, players) def hide(self): self.background.destroy() self.rank_menu.destroy() def attach_obs(self, mth): self.rank_menu.attach_obs(mth) def detach_obs(self, mth): self.rank_menu.detach_obs(mth) def destroy(self): self.hide() self.rank_menu = self.ranking_texts = self.background = None GuiColleague.destroy(self)
class MousePointerDisplay: def __init__(self, game): self.log = logging.getLogger('pano.mouseDisplay') self.game = game self.resources = game.getResources() self.defaultScale = 0.05 self.pointer = None #the parent node of the mouse pointer self.pointerParentNP = None #the mouse pointer node, it can be a ModelNode if the cursor is animated and was read by an .egg file #or it can be a OnScreenImage if the cursor is static self.mousePointer = None #True if the pointer is a static image and therefore is rendered through a OnScreenImage object self.isImagePointer = False #True if the mouse pointer is hidden self.mouseHidden = True # the name of the image used as a pointer through a call to setImageAsPointer self.pointerImage = None def initialize(self): self.pointerParentNP = render2d.attachNewNode('mousePointer') # create a GUI Layer for the pointer CullBinManager.getGlobalPtr().addBin(PanoConstants.MOUSE_CULL_BIN_NAME, CullBinManager.BTUnsorted, PanoConstants.MOUSE_CULL_BIN_VAL) # add task that updates the location of the mouse pointer taskMgr.add(self.updatePointerLocationTask, PanoConstants.TASK_MOUSE_POINTER) def isShown(self): return not self.mouseHidden def show(self): self.mouseHidden = False self.pointerParentNP.show() def hide(self): """ Hides the mouse pointer. For image based pointers, the associated OnScreenImage is destroyed with a call to the member function destroy(). While for model based pointers the associated model node is simply removed from the scenegraph. """ self.mouseHidden = True self.pointerParentNP.hide() def _destroyPointer(self): if self.mousePointer is not None: if self.isImagePointer: self.mousePointer.destroy() self.mousePointer = None else: self.mousePointer.removeNode() # self.mousePointer.detachNode() if self.pointerParentNP is not None: self.pointerParentNP.node().removeAllChildren() self.isImagePointer = False self.pointerImage = None self.mousePointer = None self.pointer = None self.mouseHidden = True def getScale(self): return self.scale def setScale(self, scale): self.scale = scale def setByName(self, pointerName): """ Sets and displays the specified mouse pointer. If None is passed in place of the pointerName parameter, then the mouse pointer is hidden. Convention: A texture file or egg file with a base name equal to pointerName must exist in one of the resource locations associated with the cursors resource type. Convention: If the pointer name corresponds to an egg file, then the pointer is assumed to be animated. Otherwise the pointer is assumed to be a static image. Returns True if the pointer was set successfully and False if otherwise. """ pointerChanged = (self.pointer is None) or (pointerName != self.pointer.getName()) if (pointerName is None) or pointerChanged: self._destroyPointer() if pointerChanged: self.pointer = self.game.getResources().loadPointer(pointerName) if self.pointer is None: self.log.error("Could'nt find pointer: %s", pointerName) return False if self.pointer.getModelFile() is not None: self.isImagePointer = False self.mousePointer = self.game.getResources().loadModel(self.pointer.getModelFile()) self.mousePointer.setScale(self.pointer.getScale() if self.pointer.getScale() is not None else self.defaultScale) self.mousePointer.setTag('model', 'True') self.mousePointer.reparentTo(self.pointerParentNP) self.isImagePointer = False self.pointerImage = None else: self.setImageAsPointer(self.pointer.getTexture(), self.pointer.getScale()) self.mousePointer.setTransparency(TransparencyAttrib.MAlpha) self.mousePointer.setBin("fixed", PanoConstants.RENDER_ORDER_MOUSE_POINTER) self.mousePointer.setDepthTest(False) self.mousePointer.setDepthWrite(False) self.mouseHidden = False self.show() return True def setImageAsPointer(self, image, scale = None): self._destroyPointer() self.isImagePointer = True texPath = self.game.getResources().getResourceFullPath(PanoConstants.RES_TYPE_TEXTURES, image) if texPath is not None: x, y = 0, 0 if base.mouseWatcherNode.hasMouse(): x=base.mouseWatcherNode.getMouseX() y=base.mouseWatcherNode.getMouseY() self.mousePointer = OnscreenImage( parent=self.pointerParentNP, image = texPath, pos = Point3(x, 0, y), scale = scale if scale is not None else self.defaultScale ) self.pointerImage = image self.mousePointer.setTransparency(TransparencyAttrib.MAlpha) self.mousePointer.setBin("fixed", PanoConstants.RENDER_ORDER_MOUSE_POINTER) self.mousePointer.setDepthTest(False) self.mousePointer.setDepthWrite(False) self.mouseHidden = False self.show() return True else: return False def getPosition(self): ''' Returns the current location of the mouse pointer. @return: A (x, y) tuple containing the coordinates of the pointers in the coordinate of the render node. ''' if self.mousePointer is not None: pos = self.mousePointer.getPos(render) return (pos[0], pos[2]) else: return (-1, 1) def updatePointerLocationTask(self, task): if base.mouseWatcherNode.hasMouse(): if self.mousePointer is not None and not self.mouseHidden and base.mouseWatcherNode.hasMouse() and not self.game.isPaused(): x=base.mouseWatcherNode.getMouseX() y=base.mouseWatcherNode.getMouseY() self.mousePointer.setPos(Point3(x, 0, y)) return Task.cont def persistState(self, persistence): ctx = persistence.createContext('mouse_pointer') ctx.addVar('is_image', self.isImagePointer) ctx.addVar('scale', self.scale) ctx.addVar('pointer_name', self.pointer.getName() if self.pointer is not None else '') ctx.addVar('image', self.pointerImage if self.pointer is None else '') return ctx def resumeState(self, persistence): pass
class TuningGui(GuiColleague, DirectObject): def __init__(self, mediator, sprops): GuiColleague.__init__(self, mediator) self.buttons = self.background = None self.sprops = sprops self.txt = self.upg1_txt = self.upg2_txt = self.upg3_txt = \ self.hint1_txt = self.hint2_txt = self.hint3_txt = None def show(self, players): self.background = OnscreenImage( self.sprops.gameprops.menu_props.background_img_path, scale=(1.77778, 1, 1)) self.background.setBin('background', 10) bprops = {'scale': (.4, .4), 'cmd': self.on_btn} self.txt = OnscreenText( text=_('What do you want to upgrade?'), scale=.1, pos=(0, .76), font=loader.loadFont(self.sprops.font), fg=self.sprops.gameprops.menu_props.text_normal_col) self.buttons = [ ImgBtn(pos=(-1.2, .1), img=self.sprops.tuning_imgs[0], extra_args=['engine'], **bprops) ] self.buttons += [ ImgBtn(pos=(0, .1), img=self.sprops.tuning_imgs[1], extra_args=['tires'], **bprops) ] self.buttons += [ ImgBtn(pos=(1.2, .1), img=self.sprops.tuning_imgs[2], extra_args=['suspensions'], **bprops) ] self._set_events() # tuning = self.mediator.car2tuning[self.sprops.player_car_name] player_car_name = [ player.car for player in players if player.kind == Player.human ][0] tuning = [ player.tuning for player in players if player.car == player_car_name ][0] self.upg1_txt = OnscreenText( text=_('current upgrades: +') + str(tuning.engine), scale=.06, pos=(-1.53, -.36), font=loader.loadFont(self.sprops.font), wordwrap=12, align=TextNode.ALeft, fg=self.sprops.gameprops.menu_props.text_normal_col) self.upg2_txt = OnscreenText( text=_('current upgrades: +') + str(tuning.tires), scale=.06, pos=(-.35, -.36), font=loader.loadFont(self.sprops.font), wordwrap=12, align=TextNode.ALeft, fg=self.sprops.gameprops.menu_props.text_normal_col) self.upg3_txt = OnscreenText( text=_('current upgrades: +') + str(tuning.suspensions), scale=.06, pos=(.85, -.36), font=loader.loadFont(self.sprops.font), wordwrap=12, align=TextNode.ALeft, fg=self.sprops.gameprops.menu_props.text_normal_col) self.hint1_txt = OnscreenText( text=_("engine: it increases car's maximum speed"), scale=.06, pos=(-1.53, -.46), font=loader.loadFont(self.sprops.font), wordwrap=12, align=TextNode.ALeft, fg=self.sprops.gameprops.menu_props.text_normal_col) self.hint2_txt = OnscreenText( text=_("tires: they increase car's adherence"), scale=.06, pos=(-.35, -.46), font=loader.loadFont(self.sprops.font), wordwrap=12, align=TextNode.ALeft, fg=self.sprops.gameprops.menu_props.text_normal_col) self.hint3_txt = OnscreenText( text=_("suspensions: they increase car's stability"), scale=.06, pos=(.85, -.46), font=loader.loadFont(self.sprops.font), wordwrap=12, align=TextNode.ALeft, fg=self.sprops.gameprops.menu_props.text_normal_col) def _set_events(self): self._curr_btn = 0 self.buttons[0]._on_enter(None) self.accept('joypad0-dpad_left-up', self.__on_evt, ['left']) self.accept('joypad0-dpad_right-up', self.__on_evt, ['right']) self.accept('joypad0-face_a-up', self.__on_evt, ['enter']) nav = self.sprops.gameprops.menu_props.nav.navinfo_lst[0] self.accept(self.eng.lib.remap_str(nav.left), self.__on_evt, ['left']) self.accept(self.eng.lib.remap_str(nav.right), self.__on_evt, ['right']) self.accept(self.eng.lib.remap_str(nav.fire), self.__on_evt, ['enter']) def __on_evt(self, evt): self.buttons[self._curr_btn]._on_exit(None) d = 1 if evt == 'right' else (-1 if evt == 'left' else 0) self._curr_btn = min(2, max(0, self._curr_btn + d)) self.buttons[self._curr_btn]._on_enter(None) if evt == 'enter': self.on_btn(self.buttons[self._curr_btn].wdg['extraArgs'][0]) def on_btn(self, val): self.notify('on_tuning_sel', val) def hide(self): wdgs = [ self.background, self.txt, self.hint1_txt, self.hint2_txt, self.hint3_txt, self.upg1_txt, self.upg2_txt, self.upg3_txt ] list(map(lambda wdg: wdg.destroy(), self.buttons + wdgs)) self.ignore_all()
class QuestEmblemGui(DirectFrame): notify = directNotify.newCategory('QuestEmblemGui') def __init__(self, parent): DirectFrame.__init__(self, parent) self.emblem = OnscreenImage(image=loader.loadTexture( 'phase_5/maps/quest_available_emblem.png'), parent=self) self.emblem.setTransparency(TransparencyAttrib.MAlpha) self.emblem.setBillboardAxis() self.emblem.setTwoSided(1) glowMdl = loader.loadModel('phase_4/models/minigames/particleGlow.bam') self.glow = OnscreenImage(parent=self.emblem, image=glowMdl, color=(1.0, 1.0, 0.4, 1.0), scale=(3.0, 3.0, 3.0), pos=(0, 0.05, 0)) self.glow.setBin('gui-popup', 10) glowMdl.removeNode() self.track = None self.state = LOADED def setEmblem(self, questAvailable=QUEST_AVAILABLE): # Sets the texture of the emblem. texture = loader.loadTexture('phase_5/maps/quest_available_emblem.png') if questAvailable is 0: texture = loader.loadTexture( 'phase_5/maps/quest_scroll_emblem.png') self.state = questAvailable self.emblem.setImage(texture) self.emblem.setTransparency(TransparencyAttrib.MAlpha) self.emblem.setBillboardAxis() self.emblem.setTwoSided(1) def start(self, bobMinHeight=0.5, bobMaxHeight=0.5): # Shows the emblem and starts the bobbing animation. # Stops so we don't have two animations running at once. self.stop() # Shows the emblem self.show() # Let's create the animation and run the animation. self.track = Sequence( LerpPosInterval(self.emblem, 1.35, pos=(0, 0, self.getZ() - bobMinHeight), startPos=(0, 0, bobMaxHeight), blendType='easeInOut'), LerpPosInterval(self.emblem, 1.35, pos=(0, 0, bobMaxHeight), startPos=(0, 0, self.getZ() - bobMinHeight), blendType='easeInOut')).loop() def stop(self): # Hides the emblem and stops the animation. self.hide() if self.track: self.track.pause() self.track = None self.state = DISABLED def destroy(self): self.stop() self.glow.destroy() self.emblem.destroy() self.state = None DirectFrame.destroy(self)
class MenuGui(Gui): def __init__(self, mdt, menu_args): Gui.__init__(self, mdt) self.menu_args = menu_args self.background = None if self.menu_args.background: self.background = OnscreenImage(scale=(1.77778, 1, 1.0), image=self.menu_args.background) self.background.setBin('background', 10) @property def imgbtn_args(self): return { 'rolloverSound': self.menu_args.rollover, 'clickSound': self.menu_args.click } @property def btn_args(self): return { 'scale': self.menu_args.text_scale, 'text_font': self.menu_args.font, 'text_fg': self.menu_args.text_fg, 'frameColor': self.menu_args.btn_color, 'frameSize': self.menu_args.btn_size, 'rolloverSound': self.menu_args.rollover, 'clickSound': self.menu_args.click } @property def label_args(self): return { 'scale': self.menu_args.text_scale, 'text_fg': self.menu_args.text_fg, 'text_font': self.menu_args.font, 'frameColor': (1, 1, 1, 0) } @property def option_args(self): tfg = self.menu_args.text_fg return { 'scale': self.menu_args.text_scale, 'text_font': self.menu_args.font, 'text_fg': tfg, 'frameColor': self.menu_args.btn_color, 'frameSize': self.menu_args.btn_size, 'rolloverSound': self.menu_args.rollover, 'clickSound': self.menu_args.click, 'text_scale': .85, 'item_text_font': self.menu_args.font, 'item_frameColor': tfg, 'item_relief': FLAT, 'popupMarker_frameColor': self.menu_args.btn_color, 'textMayChange': 1, 'highlightColor': (tfg[0] * 1.2, tfg[1] * 1.2, tfg[2] * 1.2, .2) } @property def checkbtn_args(self): return { 'scale': self.menu_args.text_scale, 'text_font': self.menu_args.font, 'text_fg': self.menu_args.text_fg, 'frameColor': self.menu_args.btn_color, 'rolloverSound': self.menu_args.rollover, 'clickSound': self.menu_args.click } @property def text_args(self): return { 'scale': self.menu_args.text_scale, 'fg': self.menu_args.text_fg, 'font': self.menu_args.font } def destroy(self): Gui.destroy(self) if self.background: self.background.destroy()
class MainMenu(DirectObject): def __init__(self): self.node = aspect2d.attachNewNode('MainMenu') self.buttons = [] self.LoadContent() self.SetupEventHandlers() def SetupEventHandlers(self): self.accept(ServerJoinResponseEvent.EventName, self.OnServerJoinResponseEvent) def LoadContent(self): bg = OnscreenImage(image = 'Assets/Images/Menus/MainMenu/background.png', scale = (2, 1, 1)) bg.setTransparency(TransparencyAttrib.MAlpha) bg.reparentTo(self.node) bg.setBin('fixed', 1) title = OnscreenImage(image = 'Assets/Images/Menus/MainMenu/title.png') title.setTransparency(TransparencyAttrib.MAlpha) title.reparentTo(self.node) self.spinner = OnscreenImage(image = 'Assets/Images/Menus/MainMenu/loadingSpinner.png', pos = (-0.15, 1, 0.15), scale = 128.0/1024.0) self.spinner.setTransparency(TransparencyAttrib.MAlpha) self.spinner.reparentTo(base.a2dBottomRight) self.spinner.setBin('gui-popup', 0) self.spinner.hide() self.LoadButton('Button_Offline', 'offline', 'offline_over', 0, 0.2, self.OnButtonClicked, ['offline']) self.LoadButton('Button_Multiplayer', 'multiplayer', 'multiplayer_over', 0, 0, self.OnButtonClicked, ['multiplayer']) self.LoadButton('Button_Options', 'options', 'options_over', 0, -0.2, self.OnButtonClicked, ['options']) self.LoadButton('Button_Exit', 'exit', 'exit_over', 0, -0.4, self.OnButtonClicked, ['exit']) def LoadButton(self, egg, up, over, x, y, cmd, args): maps = loader.loadModel("Assets/Images/Menus/MainMenu/%s" % (egg)) b = DirectButton(geom = (maps.find('**/%s' % (up)), maps.find('**/%s' % (over)), maps.find('**/%s' % (over)), maps.find('**/%s' % (up))), command = cmd, extraArgs = args, pressEffect = 0, relief = None, rolloverSound = None, clickSound = None, pos = (x, 1, y), scale = (1, 1, 75.0/500.0)) b.reparentTo(self.node) self.buttons.append(b) def OnButtonClicked(self, buttonText): if(buttonText == 'multiplayer'): Globals.ROCKET_CONTEXT.LoadDocument('Assets/libRocket/multiplayer.rml').Show() self.DisableButtons() self.acceptOnce('multiplayerPopupClose', self.OnMultiplayerClose) elif(buttonText == 'options'): Globals.ROCKET_CONTEXT.LoadDocument('Assets/libRocket/options.rml').Show() self.DisableButtons() self.acceptOnce('optionsPopupClose', self.OnOptionsClose) elif(buttonText == 'exit'): self.CreateAlertPopup('Exit Game', 'Do you really want to exit?', self.OnExitPopupOkay, self.OnExitPopupCancel) elif(buttonText == 'offline'): Globals.ROCKET_CONTEXT.LoadDocument('Assets/libRocket/offline.rml').Show() self.DisableButtons() self.acceptOnce('offlinePopupClose', self.OnOfflineClose) def CreatePopup(self, title, fields, values, onOkay, onCancel): p = Popup(title, fields, values, onOkay, onCancel) self.OnPopupCreated(p) def CreateAlertPopup(self, title, text, onOkay, onCancel): p = AlertPopup(title, text, onOkay, onCancel) self.OnPopupCreated(p) def CreateFullScreenPopup(self, title, fields, values, onOkay, onCancel): p = FullscreenPopup(title, fields, values, onOkay, onCancel) self.OnPopupCreated(p) def OnOfflineClose(self, accept): if(accept): SettingsController.SaveClientSettings() taskMgr.doMethodLater(0.1, messenger.send, 'as', ['startOffline']) self.EnableButtons() def OnOptionsClose(self, accept): if(accept): SettingsController.SaveClientSettings() self.EnableButtons() def OnMultiplayerClose(self, accept): if(accept): SettingsController.SaveClientSettings() self.StartLoadingSpinner() self.DisableButtons() taskMgr.doMethodLater(0.1, messenger.send, 'as1', ['mainMenuMulti']) else: self.EnableButtons() def DisableButtons(self): for b in self.buttons: b['state'] = DGG.DISABLED def EnableButtons(self): for b in self.buttons: b['state'] = DGG.NORMAL def OnAlertPopupClose(self, popup): self.DestroyPopup(popup) def OnExitPopupOkay(self, popup): self.DestroyPopup(popup) messenger.send('mainMenuExit') def OnExitPopupCancel(self, popup): self.DestroyPopup(popup) def OnPopupCreated(self, popup): self.DisableButtons() def DestroyPopup(self, popup): popup.Destroy() del popup self.EnableButtons() def Hide(self): self.node.hide() def Show(self): self.node.show() def StartLoadingSpinner(self): self.spinner.show() self.spinSequence = Sequence(LerpHprInterval(self.spinner, 2, VBase3(0, 0, 180), VBase3(0, 0, 0)), LerpHprInterval(self.spinner, 2, VBase3(0, 0, 360), VBase3(0, 0, 180))) self.spinSequence.loop() def StopLoadingSpinner(self): self.spinSequence.finish() self.spinner.hide() def OnServerJoinResponseEvent(self, event): self.StopLoadingSpinner() self.EnableButtons() if(not event.GetResponse()): p = AlertPopup('Join Game Failed', event.GetReason(), self.ClosePopup, self.ClosePopup) self.OnPopupCreated(p) def ClosePopup(self, popup): self.DestroyPopup(popup)