class CharacterGUI: """Widget with the selected character info.""" def __init__(self): self.char = None # the chosen character self.rest_list_shown = False self._status_lab = None self._rest_buttons = {} self._char_desc_wids = [] self._char_desc_shown = False self._fr = DirectFrame( parent=base.a2dTopLeft, # noqa: F821 frameSize=(-0.31, 0.31, -0.1, 0.115), pos=(0.31, 0, -1.9), frameTexture=GUI_PIC + "metal1.png", state=DGG.NORMAL, ) self._fr.setTransparency(TransparencyAttrib.MAlpha) # a "?" button to open a detailed description of the character self._char_desc_but = DirectButton( parent=self._fr, pos=(0.27, 0, 0.0675), command=self._show_char_desc, clickSound=base.main_menu.click_snd, # noqa: F821 **ABOUT_BUT_PARAMS, ) DirectLabel( # Name: parent=self._fr, text=base.labels.CHARACTERS[0], # noqa: F821 text_font=base.main_font, # noqa: F821 frameSize=(0.1, 0.1, 0.1, 0.1), text_scale=0.03, text_fg=RUST_COL, pos=(-0.22, 0, 0.07), ) self._char_name = DirectLabel( parent=self._fr, text="", frameSize=(0.1, 0.1, 0.1, 0.1), text_scale=0.03, text_fg=SILVER_COL, pos=(-0.09, 0, 0.069), ) self._traits = DirectLabel( parent=self._fr, text="", frameSize=(0.1, 0.1, 0.1, 0.1), text_scale=(0.028, 0.028), text_fg=SILVER_COL, text_font=base.main_font, # noqa: F821 pos=(0, 0, 0.025), ) DirectLabel( # Class: parent=self._fr, text=base.labels.CHARACTERS[1], # noqa: F821 text_font=base.main_font, # noqa: F821 frameSize=(0.1, 0.1, 0.1, 0.1), text_scale=0.03, text_fg=RUST_COL, pos=(0.05, 0, 0.07), ) self._char_class = DirectLabel( parent=self._fr, text="", frameSize=(0.1, 0.1, 0.1, 0.1), text_scale=0.03, text_fg=SILVER_COL, pos=(0.17, 0, 0.068), ) DirectLabel( # Health parent=self._fr, text=base.labels.CHARACTERS[2], # noqa: F821 text_font=base.main_font, # noqa: F821 frameSize=(0.1, 0.1, 0.1, 0.1), text_scale=0.03, text_fg=RUST_COL, pos=(-0.22, 0, -0.015), ) self._char_health = DirectWaitBar( parent=self._fr, frameSize=(-0.17, 0.17, -0.002, 0.002), frameColor=(0.35, 0.35, 0.35, 1), value=0, barColor=(0.85, 0.2, 0.28, 1), pos=(0.07, 0, -0.008), ) DirectLabel( # Energy parent=self._fr, text=base.labels.CHARACTERS[3], # noqa: F821 text_font=base.main_font, # noqa: F821 frameSize=(0.1, 0.1, 0.1, 0.1), text_scale=0.03, text_fg=RUST_COL, pos=(-0.216, 0, -0.06), ) self._char_energy = DirectWaitBar( parent=self._fr, frameSize=(-0.17, 0.17, -0.002, 0.002), frameColor=(0.35, 0.35, 0.35, 1), value=0, barColor=(0.46, 0.61, 0.53, 1), pos=(0.07, 0, -0.053), ) self._tip = OnscreenText( parent=base.render2d, # noqa: F821 text="", font=base.main_font, # noqa: F821 scale=(0.021, 0.027), fg=SILVER_COL, bg=(0, 0, 0, 0.4), ) self._tip.hide() self._disease = DirectFrame( parent=self._fr, frameSize=(-0.02, 0.02, -0.02, 0.02), pos=(0.27, 0, -0.008), frameTexture=GUI_PIC + "disease.png", ) self._disease.setTransparency(TransparencyAttrib.MAlpha) self.clear_char_info() def _update_char_info(self, task): """Track the chosen character parameters in the GUI.""" if self.char.is_dead: self.clear_char_info() return task.done self._char_health["value"] = self.char.health self._char_energy["value"] = self.char.energy self._traits["text"] = ", ".join(self.char.traits) if self.char.is_diseased: self._disease.show() else: self._disease.hide() if self._char_desc_shown: self._update_desc() return task.again def _update_desc(self): """Update the chosen character description.""" to_del = [] for wid in self._char_desc_wids: if wid["text"] not in ( # Traits base.labels.CHARACTERS[5], # noqa: F821 # Status base.labels.CHARACTERS[4], # noqa: F821 "", ): wid.destroy() to_del.append(wid) for del_wid in to_del: self._char_desc_wids.remove(del_wid) self._fill_status(self._fill_traits(0.64)) def _fill_traits(self, shift): """Fill the chosen character traits. Args: shift (float): Z-coor for the new widgets. Returns: float: Z-coor including the new widgets shift. """ shift -= 0.03 for trait in self.char.traits + self.char.disabled_traits: self._char_desc_wids.append( DirectLabel( parent=self._fr, text=trait, frameSize=(0.1, 0.1, 0.1, 0.1), text_scale=0.03, text_font=base.main_font, # noqa: F821 text_fg=SILVER_COL if trait in self.char.traits else (0.3, 0.3, 0.3, 1), pos=(0, 0, shift), ) ) self._char_desc_wids.append( DirectLabel( parent=self._fr, text=base.labels.TRAIT_DESC[trait], # noqa: F821 text_font=base.main_font, # noqa: F821 frameSize=(0.1, 0.1, 0.1, 0.1), text_scale=0.029, text_fg=SILVER_COL if trait in self.char.traits else (0.3, 0.3, 0.3, 1), pos=(0, 0, shift - 0.045), ) ) shift -= 0.1 return shift def _fill_status(self, shift): """Fill the chosen character status. Args: shift (float): Z-coor for the new widgets. """ shift -= 0.04 for status in self.char.statuses: self._char_desc_wids.append( DirectLabel( parent=self._fr, text=status, text_font=base.main_font, # noqa: F821 frameSize=(0.1, 0.1, 0.1, 0.1), text_scale=0.029, text_fg=SILVER_COL, pos=(0, 0, shift), ) ) shift -= 0.045 def _show_char_desc(self): """Show detailed character description. Includes description of every character's trait and their current status. """ if self._char_desc_shown: self._fr["frameSize"] = (-0.31, 0.31, -0.1, 0.115) clear_wids(self._char_desc_wids) self._status_lab = None else: shift = 0.7 self._fr["frameSize"] = (-0.31, 0.31, -0.1, shift) shift -= 0.06 self._char_desc_wids.append( DirectLabel( parent=self._fr, # Traits text=base.labels.CHARACTERS[5], # noqa: F821, text_font=base.main_font, # noqa: F821, frameSize=(0.1, 0.1, 0.1, 0.1), text_scale=0.03, text_fg=RUST_COL, pos=(-0.225, 0, shift), ) ) if self.char.id in base.team.chars.keys(): # noqa: F821 traits_but = DirectButton( parent=self._fr, text="", frameSize=(-0.025, 0.025, -0.025, 0.025), frameTexture=GUI_PIC + "like.png", relief="flat", pos=(0.265, 0, shift + 0.013), command=base.traits_gui.show, # noqa: F821 ) traits_but.bind( DGG.ENTER, self._highlight_traits_but, extraArgs=[traits_but] ) traits_but.bind( DGG.EXIT, self._dehighlight_traits_but, extraArgs=[traits_but] ) self._char_desc_wids.append(traits_but) shift = self._fill_traits(shift) self._status_lab = DirectLabel( # Status parent=self._fr, # Status text=base.labels.CHARACTERS[4], # noqa: F821 text_font=base.main_font, # noqa: F821 frameSize=(0.1, 0.1, 0.1, 0.1), text_scale=0.03, text_fg=RUST_COL, pos=(-0.221, 0, shift), ) self._char_desc_wids.append(self._status_lab) self._fill_status(shift) self._char_desc_shown = not self._char_desc_shown def _dehighlight_traits_but(self, button, _): """Dehighlight traits tweaking button. Args: button (panda3d.gui.DirectGui.DirectButton): Button to dehighlight. """ button["frameTexture"] = GUI_PIC + "like.png" def _highlight_traits_but(self, button, _): """Hightlight traits tweaking button. Args: button (panda3d.gui.DirectGui.DirectButton): Button to highlight. """ button["frameTexture"] = GUI_PIC + "hover_like.png" def clear_char_info(self, clear_resting=True): """Clear the character GUI. Args: clear_resting (bool): Optional. A flag indicating if the list of the resting characters should also be closed. """ for wid in ( self._char_name, self._char_class, self._char_health, self._char_energy, self._traits, self._char_desc_but, self._disease, ): wid.hide() if self._char_desc_shown: self._show_char_desc() taskMgr.remove("track_char_info") # noqa: F821 self.char = None if clear_resting: for but in self._rest_buttons.values(): but.destroy() self.rest_list_shown = False def destroy_char_button(self, char_id): """Hide the given character button from the resting characters list. Args: char_id (str): Character id. """ if char_id in self._rest_buttons.keys(): self._rest_buttons[char_id].destroy() self._rest_buttons.pop(char_id) def hide_tip(self): """Hide the tooltip.""" self._tip.hide() def show_char_info(self, char): """Show the given character status. Args: char (units.crew.character.Character): The chosen character object. """ self._char_name["text"] = char.name self._char_class["text"] = char.class_.capitalize() self._traits["text"] = ", ".join(char.traits) self._char_health["range"] = char.class_data["health"] self._char_health["value"] = char.health self._char_energy["value"] = char.energy if char.is_diseased: self._disease.show() else: self._disease.hide() self.char = char self._char_name.show() self._char_class.show() self._char_health.show() self._char_energy.show() self._traits.show() self._char_desc_but.show() if self._char_desc_shown: self._show_char_desc() self._show_char_desc() taskMgr.doMethodLater( # noqa: F821 0.5, self._update_char_info, "track_char_info" ) def show_tooltip(self, text): """Show tooltip with the given text. Args: text (str): Text to show in the tooltip. """ if not base.mouseWatcherNode.hasMouse(): # noqa: F821 return if self.rest_list_shown and text == "Rest zone": return self._tip.setText(text) self._tip.setX(base.mouseWatcherNode.getMouseX()) # noqa: F821 self._tip.setY(base.mouseWatcherNode.getMouseY()) # noqa: F821 self._tip.show() def show_resting_chars(self, part): """Show a list of the characters resting in this part. Args: part (Train.RestPart): Rest part of the Train. """ if self.rest_list_shown: return self._tip.hide() self.rest_list_shown = True x = base.mouseWatcherNode.getMouseX() # noqa: F821 z = base.mouseWatcherNode.getMouseY() # noqa: F821 self._rest_buttons["title"] = DirectButton( pos=(x, 0, z), text=base.labels.TIPS[0], # noqa: F821 text_fg=RUST_COL, text_font=base.main_font, # noqa: F821 frameColor=(0, 0, 0, 0.6), scale=(0.04, 0, 0.03), ) shift = -0.039 for char in part.chars: if char.is_dead: continue self._rest_buttons[char.id] = DirectButton( pos=(x, 0, z + shift), text=char.name, text_fg=SILVER_COL, frameColor=(0, 0, 0, 0.6), command=base.common_ctrl.choose_char, # noqa: F821 extraArgs=[char.id], scale=(0.04, 0, 0.03), ) shift -= 0.033 def move_status_label(self, place): """Move the status label widget. Args: place (int): Place to shift the widget. """ if self._status_lab is not None: self._status_lab.setZ(self._status_lab.getZ() + place / 10) def update_resting_chars(self, part): """Update the list of the resting characters. Args: part (train.part.TrainPart): Rest train part. """ for key, but in self._rest_buttons.items(): if key != "title": but.destroy() self._rest_buttons[key] = None x, _, z = self._rest_buttons["title"].getPos() shift = -0.039 for char in part.chars: self._rest_buttons[char.id] = DirectButton( pos=(x, 0, z + shift), text=char.name, text_fg=SILVER_COL, frameColor=(0, 0, 0, 0.6), command=base.common_ctrl.choose_char, # noqa: F821 extraArgs=[char.id], scale=(0.04, 0, 0.03), ) shift -= 0.033
class SMGUICounter(): def __init__(self, icon, maxValue): self.value = 0 self.life = 0.0 self.basePos = Vec2(0.7, POS_TOP) self.maxValue = maxValue # Must be 1 or higher to activate. self.iconImg = OnscreenImage(image = ("../res/icons/gui_" + str(icon) + ".png"), pos = (self.basePos.getX(), 0, self.basePos.getY()), scale = 0.1) self.iconImg.setTransparency(TransparencyAttrib.MAlpha) strValue = str(self.value) if(self.maxValue > 0): strValue += ("/" + str(self.maxValue)) self.textObj = OnscreenText(text = strValue, style = 1, fg = (0,0,0,1), pos = (self.basePos.getX() + COUNT_OFFSET_X, self.basePos.getY() + COUNT_OFFSET_Y), align = TextNode.ARight, scale = .2) self.state = ST_IDLE #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Returns the GUI element type. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def getGUIType(self): return 1 #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Summons a 100-foot tall unicorn with chainsaws strapped to its back. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def updateGUI(self): dt = globalClock.getDt() state = self.state # State-based control if(state == ST_PEEK_IN): y = self.getYPos() if(y <= MIN_PEEK_HEIGHT): self.setState(ST_PEEK_WAIT) else: self.setYPos(y - PEEK_RATE * dt) elif(state == ST_PEEK_OUT): y = self.getYPos() if(y >= MAX_PEEK_HEIGHT): self.setState(ST_IDLE) self.life = 0.0 else: self.setYPos(y + PEEK_RATE * dt) elif(state == ST_PEEK_WAIT): if(self.getLife() > PEEK_TIME): self.setState(ST_PEEK_OUT) else: self.addLife() self.updateText() self.updatePos() def updatePos(self): x = self.basePos.getX() y = self.basePos.getY() self.iconImg.setX(x) self.iconImg.setZ(y) self.textObj.setX(x + COUNT_OFFSET_X) self.textObj.setY(y + COUNT_OFFSET_Y) def updateText(self): txt = str(self.value) if(self.maxValue > 0): txt += ("/" + str(self.maxValue)) self.textObj.setText(txt) #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Returns the peek state as an integer. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def getState(self): return self.state #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Sets the peek state. # setState(int a {0 - 3}) #------------------------------------------------------------------------------------------------------------------------------------------------------------ def setState(self, state): self.state = state; def setMaxValue(self, value): self.maxValue = value #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Adds 1 to the peek life counter. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def addLife(self): self.life += globalClock.getDt() #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Resets the peek life counter to 0. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def resetLife(self): self.life = 0.0 #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Makes this class get a freaking life and stop sitting on its lazy a- Wait, what? Oh, returns the current peek life. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def getLife(self): return self.life #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Gets the value of the tracked variable. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def getValue(self): return self.value #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Changes the variable behind the scenes with no peeking. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def setValue(self, value): self.value = value #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Adds a value to the tracked variable and peeks the counter out. Use negatives to subtract. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def increment(self): self.setState(ST_PEEK_IN) self.value += 1 #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Returns the OnScreenText object. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def getTextObj(self): return self.textObj #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Gets the vertical position of the text. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def getYPos(self): return self.basePos.getY() #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Sets the Y position of both the label and value. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def setYPos(self, ypos): self.basePos = Vec2(self.basePos.getX(), ypos)
class MouseTunnel(ShowBase): def __init__(self): # 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.stimtype = 'random image' # session_start self.session_start_time = datetime.datetime.now() # self.accept("escape", sys.exit, [0])#don't let the user do this, because then the data isn't saved. self.accept('q', self.close) self.accept('Q', self.close) self.upArrowIsPressed = base.mouseWatcherNode.isButtonDown(KeyboardButton.up()) self.downArrowIsPressed = base.mouseWatcherNode.isButtonDown(KeyboardButton.down()) self.rightArrowIsPressed = base.mouseWatcherNode.isButtonDown(KeyboardButton.right()) self.leftArrowIsPressed = base.mouseWatcherNode.isButtonDown(KeyboardButton.left()) self.AUTO_REWARD = AUTO_REWARD # disable mouse control so that we can place the camera base.disableMouse() camera.setPosHpr(0, 0, 10, 0, -90, 0) mat = Mat4(camera.getMat()) mat.invertInPlace() base.mouseInterfaceNode.setMat(mat) # base.enableMouse() props = WindowProperties() # props.setOrigin(0, 0) props.setFullscreen(True) props.setCursorHidden(True) props.setMouseMode(WindowProperties.M_relative) base.win.requestProperties(props) base.setBackgroundColor(0, 0, 0) # set the background color to black print('FULSCREEN:') print(props.getFullscreen()) print('=============') # set up the textures # we now get buffer thats going to hold the texture of our new scene altBuffer = self.win.makeTextureBuffer("hello", 1524, 1024) # altBuffer.getDisplayRegion(0).setDimensions(0.5,0.9,0.5,0.8) # altBuffer = base.win.makeDisplayRegion() # altBuffer.makeDisplayRegion(0,1,0,1) # now we have to setup a new scene graph to make this scene self.dr2 = base.win.makeDisplayRegion(0, 0.001, 0, 0.001)#make this really,really small so it's not seeable by the subject altRender = NodePath("new render") # this takes care of setting up ther camera properly self.altCam = self.makeCamera(altBuffer) self.dr2.setCamera(self.altCam) self.altCam.reparentTo(altRender) self.altCam.setPos(0, -10, 0) self.bufferViewer.setPosition("lrcorner") # self.bufferViewer.position = (-.1,-.4,-.1,-.4) self.bufferViewer.setCardSize(1.0, 0.0) print(self.bufferViewer.position) self.imagesTexture = MovieTexture("image_sequence") # success = self.imagesTexture.read("models/natural_images.avi") # success = self.imagesTexture.read("models/movie_5hz.mpg") self.imagesTexture.setPlayRate(1.0) self.imagesTexture.setLoopCount(10) # self.imageTexture =loader.loadTexture("models/NaturalImages/BSDs_8143.tiff") # self.imagesTexture.reparentTo(altRender) self.fixationPoint = OnscreenImage(image='models/fixationpoint.jpg', pos=(0, 0,0),scale=0.01) cm = CardMaker("stimwindow") cm.setFrame(-4, 4, -3, 3) # cm.setUvRange(self.imagesTexture) self.card = NodePath(cm.generate()) self.card.reparentTo(altRender) if self.stimtype == 'image_sequence': self.card.setTexture(self.imagesTexture, 1) # add the score display self.scoreLabel = OnscreenText(text='Current Score:', pos=(-1, 0.9), scale=0.1, fg=(0.8, 0.8, 0.8, 1)) self.scoreText = OnscreenText(text=str(0), pos=(-1, 0.76), scale=0.18, fg=(0, 1, 0, 1), shadow=(0.1, 1, 0.1, 0.5)) self.feebackScoreText = OnscreenText(text='+ ' + str(0), pos=(-0.5, 0.5), scale=0.3, fg=(0, 1, 0, 1), shadow=(0.1, 1, 0.1, 0.5)) self.feebackScoreText.setX(3.) # self.imagesTexture.play() # self.bufferViewer.setPosition("lrcorner") # self.bufferViewer.setCardSize(1.0, 0.0) self.accept("v", self.bufferViewer.toggleEnable) self.accept("V", self.bufferViewer.toggleEnable) # Load the tunnel self.initTunnel() # initialize some things # for the tunnel construction: self.boundary_to_add_next_segment = -1 * TUNNEL_SEGMENT_LENGTH self.current_number_of_segments = 8 # task flow booleans self.in_waiting_period = False self.stim_started = False self.looking_for_a_cue_zone = True self.in_reward_window = False self.show_stimulus = False # for task control self.interval = 0 self.time_waiting_in_cue_zone = 0 self.wait_time = 1.83 self.stim_duration = 0 # in seconds # self.distribution_type = np.random.uniform# # self.distribution_type_inputs = [0.016,0.4] #change the min & max stim duration times #New lines EAS: set weights higher for faster image durations self.durWeights = list() a = np.linspace(0.016,0.4,10) for i,j in enumerate(a): if j<0.1: p1 = 0.25 self.durWeights.append(p1) elif j > 0.1 and j < 0.21: p1 = 0.1 self.durWeights.append(p1) elif j> 0.21: p1 = 0.04 self.durWeights.append(p1) self.rng = np.random.default_rng() a = np.asarray(a) self.distribution_type_inputs = a #subset_size = len(p) #End new lines # self.distribution_type_inputs = [0.05,1.5] #can be anytong should match # self.distribution_type_inputs = [0.016,0.4] #change the min & max stim duration times # self.distribution_type_inputs = [0.016,0.4, 10] #change the min & max stim duration times self.max_stim_duration = 1.0 # in seconds self.stim_elapsed = 0.0 # in seconds self.last_position = base.camera.getZ() self.position_on_track = base.camera.getZ() # for reward control self.reward_window = REWARD_WINDOW # in seconds self.reward_elapsed = 0.0 # self.new_dt = list() # self.reward_volume = 0.008 # in mL. this is for the hardcoded 0.1 seconds of reward time self.reward_volume = int(REWARD_VOLUME) # in uL, for the stepper motor self.reward_time = 0.1 # in sec, based on volume. hard coded right now but should be modified by the (1) calibration and (2) optionally by the main loop for dynamic reward scheduling # self.lick_buffer = [] self.current_score = 0 self.score = 0 self.feedback_score_startime = -2 # INITIALIZE NIDAQ self.nidevice = 'Dev2' self.encodervinchannel = 1 self.encodervsigchannel = 0 self.invertdo = False self.diport = 1 self.lickline = 1 self.doport = 0 self.rewardline = 0 self.rewardlines = [0] self.encoder_position_diff = 0 if have_nidaq: self._setupDAQ() self.do.WriteBit(1, 1) self.do.WriteBit(3, 1) # set reward high, because the logic is flipped somehow. possibly by haphazard wiring of the circuit (12/24/2018 djd) self.previous_encoder_position = self.ai.data[0][self.encodervsigchannel] else: self.previous_encoder_position = 0 self.encoder_gain = 3 # INITIALIZE LICK SENSOR self._lickSensorSetup() # INITIALIZE output data self.lickData = [] self.x = [] self.t = [] self.trialData = [] self.reactionTimeData = [] self.rewardData = [] self.rightKeyData = [] self.leftKeyData = [] self.imageData = [] self.imageTimeData = [] self.scoreData = [] self.trialDurationData = [] self.new_dt = [] # INITIALIZE KEY SENSOR, for backup inputs and other user controls self.keys = key.KeyStateHandler() self.accept('r', self._give_reward, [self.reward_volume]) self.accept('l', self._toggle_reward) # initialize the image list and populate what images you want included # self.img_list = glob.glob('models/2AFC_IMAGES_HUMAN/*.tif') # self.img_list = glob.glob('models/2AFC_IMAGES_HUMAN2/*.tif') # self.img_list = glob.glob('/Users/elizabethstubblefield/Desktop/cheetah_or_elephant/composite_images/masks/all_same_num_ea/*.tif') #Newest images self.img_list = glob.glob('models/all_same_ea/*.tif') #Newest images #No longer hard-coded: self.original_indices = [0,0] #this was manually counted... first number must was the index of the first easy img; was [43, -18] for ndx, name in enumerate(self.img_list): if 'Cheetah255' in name: self.original_indices[0] = ndx elif 'Elephant0' in name: self.original_indices[1] = ndx # print(self.img_list) # self.original_indices = [43,-18] #manually counted, grump #Problematic w/out at least 43 images in the folder self.imageTextures =[loader.loadTexture(img) for img in self.img_list] self.img_id = None #this variable is used so we know which stimulus is being presented self.img_mask = None #this tells us what the image mask being presented is # self._setupEyetracking() # self._startEyetracking() if AUTO_MODE: self.gameTask = taskMgr.add(self.autoLoop2, "autoLoop2") self.rewardTask = taskMgr.add(self.rewardControl, "reward") self.cue_zone = concatenate((self.cue_zone, arange( \ self.current_number_of_segments * -TUNNEL_SEGMENT_LENGTH-50, \ self.current_number_of_segments * -TUNNEL_SEGMENT_LENGTH - TUNNEL_SEGMENT_LENGTH - 100, \ -1))) self.auto_position_on_track = 0 self.auto_restart = False self.auto_running = True self.contTunnel() else: # Now we create the task. taskMgr is the task manager that actually # calls the function each frame. The add method creates a new task. # The first argument is the function to be called, and the second # argument is the name for the task. It returns a task object which # is passed to the function each frame. self.gameTask = taskMgr.add(self.gameLoop, "gameLoop") # self.stimulusTask = taskMgr.add(self.stimulusControl, "stimulus") self.lickTask = taskMgr.add(self.lickControl, "lick") self.rewardTask = taskMgr.add(self.rewardControl, "reward") self.keyTask = taskMgr.add(self.keyControl, "Key press") # Code to initialize the tunnel def initTunnel(self): self.tunnel = [None] * 8 for x in range(8): # Load a copy of the tunnel self.tunnel[x] = loader.loadModel('models/tunnel') # The front segment needs to be attached to render if x == 0: self.tunnel[x].reparentTo(render) # The rest of the segments parent to the previous one, so that by moving # the front segement, the entire tunnel is moved else: self.tunnel[x].reparentTo(self.tunnel[x - 1]) # We have to offset each segment by its length so that they stack onto # each other. Otherwise, they would all occupy the same space. self.tunnel[x].setPos(0, 0, -TUNNEL_SEGMENT_LENGTH) # Now we have a tunnel consisting of 4 repeating segments with a # hierarchy like this: # render<-tunnel[0]<-tunnel[1]<-tunnel[2]<-tunnel[3] self.tunnel[0] = loader.loadModel('models/grating') self.tunnel[0].reparentTo(render) self.cue_zone = arange(0, TUNNEL_SEGMENT_LENGTH, -1)-280 # This function is called to snap the front of the tunnel to the back # to simulate traveling through it def contTunnel(self): self.auto_position_on_track -= 50 position_on_track = self.auto_position_on_track print(str(int(position_on_track)) + ' ' + str(self.cue_zone)) if int(position_on_track) in np.array(self.cue_zone): # check for cue zone if not self.auto_restart: print('STOP!') self.tunnelMove.pause() self.auto_presentation = True # self.current_number_of_segments +=1 else: self.auto_restart = True self.tunnelMove.resume() else: self.in_waiting_period = False self.auto_presentation = False # base.setBackgroundColor([1,0 , 0]) if self.looking_for_a_cue_zone == False: self.looking_for_a_cue_zone = True if self.stim_started == True: self.stop_a_presentation() # This line uses slices to take the front of the list and put it on the # back. For more information on slices check the Python manual self.tunnel = self.tunnel[1:] + self.tunnel[0:1] # Set the front segment (which was at TUNNEL_SEGMENT_LENGTH) to 0, which # is where the previous segment started self.tunnel[0].setZ(0) # Reparent the front to render to preserve the hierarchy outlined above self.tunnel[0].reparentTo(render) # Set the scale to be apropriate (since attributes like scale are # inherited, the rest of the segments have a scale of 1) self.tunnel[0].setScale(.155, .155, .305) # Set the new back to the values that the rest of the segments have self.tunnel[3].reparentTo(self.tunnel[2]) self.tunnel[3].setZ(-TUNNEL_SEGMENT_LENGTH) self.tunnel[3].setScale(1) # Set up the tunnel to move one segment and then call contTunnel again # to make the tunnel move infinitely self.tunnelMove = Sequence( LerpFunc(self.tunnel[0].setZ, duration=TUNNEL_TIME, fromData=0, toData=TUNNEL_SEGMENT_LENGTH * .305), Func(self.contTunnel) ) self.tunnelMove.start() def get_trial_duration(self): #EAS updated 10.5.20 self.stim_duration = self.rng.choice(self.distribution_type_inputs, 1, p=self.durWeights) #pull out one value in array a, w/ probability based on weights return self.stim_duration[0] # return self.distribution_type(*self.distribution_type_inputs) def start_a_presentation(self): self.save_data() self.stim_duration = self.get_trial_duration() self.fixationPoint.destroy() # import pickle # with open('objs.pkl', 'wb') as f: # Python 3: open(..., 'wb') # pickle.dump([self.stim_duration,self.distribution_type_inputs], f) # print('variables saved!!!') self.in_reward_window = True print("start") if have_nidaq: self.do.WriteBit(2, 1) # self.bufferViewer.toggleEnable() self.lick_buffer = [] self.trialData.extend([globalClock.getFrameTime()]) self.reactionTimeData.extend([-1]) if self.stimtype == 'random image': if len(self.trialData) < 4: i=self.original_indices[int(np.round(np.random.random()))] #commented out due to <43 images [see l. 290ish] self.stim_duration = 2.0 else: #commented out due to <43 images i = randint(len(self.imageTextures)) self.card.setTexture(self.imageTextures[i],0) self.dr2.setDimensions(0.25, 0.75, 0.25, 0.75) # floats (left, right, bottom, top) self.img_id = self.img_list[i] #this assigns the current presented image to self.image_id print(self.img_id) self.imageData.extend(self.img_id) if self.stimtype == 'image_sequence': self.imagesTexture.setTime(0.) self.dr2.setDimensions(0.4, 0.8, 0.4, 0.70) # floats (left, right, bottom, top) self.imagesTexture.play() self.imageTimeData.extend([globalClock.getFrameTime()]) self.imageData.extend(self.img_id) def check_arrows(self): # this function will report which arrow was pressed. right = 1, left = 2, no press = 0 if self.rightArrowIsPressed: #print('check arrows RIGHT') return 1 # time.sleep(2) elif self.leftArrowIsPressed: #print('check arrows LEFT') return 2 # time.sleep(2) else: return 0 def stop_a_presentation(self): if self.stim_started == True: if self.stim_elapsed > self.stim_duration: self.trialDurationData.append(self.stim_duration) else: self.trialDurationData.append(self.stim_duration) self.dr2.setDimensions(0, 0.001, 0, 0.001)#make this really,really small so it's not seeable by the subject # self.bufferViewer.toggleEnable() self.stim_started = False self.stim_elapsed = 0. self.stim_duration = 0. self.stim_off_time = globalClock.getFrameTime() if have_nidaq: self.do.WriteBit(2, 0) # if globalClock.getFrameTime() > self.feedback_score_startime + 1.5: # arbitrary wait to make sure this isn't after a correct trial # self.feebackScoreText.setText('+' + str(0)) # self.feebackScoreText.setFg((1, 0, 0, 1)) # self.feebackScoreText.setX(.5) # self.feedback_score_startime = globalClock.getFrameTime() self.scoreData.append(self.current_score) self.fixationPoint = OnscreenImage(image='models/fixationpoint.jpg', pos=(0, 0,0),scale=0.01) # def keySensorSetup(self): def show_the_score(self): self.feebackScoreText.setText('+' + str(self.score)) if self.score == 0: self.feebackScoreText.setFg((1, 0, 0, 1)) else: self.feebackScoreText.setFg((0, 1, 0, 1)) self.feebackScoreText.setX(.5) self.feedback_score_startime = globalClock.getFrameTime() # sets up the task to listen for user input from the keys def _lickSensorSetup(self): """ Attempts to set up lick sensor NI task. """ ##TODO: Make lick sensor object if necessary. Let user select port and line. if have_nidaq: if self.di: self.lickSensor = self.di # just use DI for now licktest = [] for i in range(30): licktest.append(self.rightArrowIsPressed.Read()[self.lickline]) time.sleep(0.01) licktest = np.array(licktest, dtype=np.uint8) if len(licktest[np.where(licktest > 0)]) > 25: self.lickSensor = None self.lickData = [np.zeros(len(self.rewardlines))] print("Lick sensor failed startup test.") else: print('lick sensor setup succeeded.') self.keycontrol = True else: print("Could not initialize lick sensor. Ensure that NIDAQ is connected properly.") self.keycontrol = True self.lickSensor = None self.lickData = [np.zeros(len(self.rewardlines))] self.keys = key.KeyStateHandler() # self.window.winHandle.push_handlers(self.keys) else: print("Could not initialize lick sensor. Ensure that NIDAQ is connected properly.") self.keycontrol = True self.lickSensor = None self.lickData = [np.zeros(len(self.rewardlines))] self.keys = key.KeyStateHandler() def reactiontime_to_score(self): rt = globalClock.getFrameTime() - self.trialData[-1] self.reactionTimeData[-1] = rt score = 100. / rt # scale the reaction time, with faster producing more points return int(score / 20.) # def _read_licks(self): # not yet implemented; should be replaces with check to beam break def _give_reward(self, volume): print("reward!") self.rewardData.extend([globalClock.getFrameTime()]) # for humans self.score = self.reactiontime_to_score() self.current_score += self.score self.show_the_score() self.scoreText.setText(str(self.current_score)) # for mice if have_nidaq: self.do.WriteBit(3, 0) time.sleep(self.reward_time) self.do.WriteBit(3, 1) # put a TTL on a line to indicate that a reward was given s.dispense(volume) # pass # not yet implemented def _toggle_reward(self): if self.AUTO_REWARD: self.AUTO_REWARD = False print('switched to lick sensing for reward.') else: self.AUTO_REWARD = True print('switched to automatic rewards after stimuli.') def autoLoop2(self, task): dt = globalClock.getDt() current_time = globalClock.getFrameTime() self.x.extend([self.auto_position_on_track]) self.t.extend([globalClock.getFrameTime()]) if self.auto_presentation: self.auto_running = False if self.in_waiting_period: self.time_waited += dt else: self.time_waited = 0 self.in_waiting_period = True if self.time_waited > self.wait_time: # if in cue zone,see if we have been ther for long enough # start a trial self.start_position = self.auto_position_on_track self.start_time = current_time if not self.stim_started: self.start_a_presentation() # print(self.stim_duration) self.stim_started = True self.show_stimulus = True else: self.stim_elapsed += dt if self.stim_elapsed > self.stim_duration: self.show_stimulus = False self.in_reward_window = True self.stop_a_presentation() self.auto_restart = False # print(self.current_number_of_segments) self.current_number_of_segments += 9 # redefine the cue zone as the next one self.cue_zone = arange(self.current_number_of_segments * -TUNNEL_SEGMENT_LENGTH, self.current_number_of_segments * -TUNNEL_SEGMENT_LENGTH - TUNNEL_SEGMENT_LENGTH - 280, -1) # extend cue zone, keeping old ones # self.cue_zone = concatenate((self.cue_zone,arange(self.current_number_of_segments*-TUNNEL_SEGMENT_LENGTH-40, # self.current_number_of_segments*-TUNNEL_SEGMENT_LENGTH-TUNNEL_SEGMENT_LENGTH-40, # -1))) self.contTunnel() self.time_waited = 0 self.looking_for_a_cue_zone = False # base.setBackgroundColor([0, 0, 1]) else: pass # base.setBackgroundColor([0, 1, 0]) else: self.auto_running = True return Task.cont # Since every return is Task.cont, the task will def gameLoop(self, task): # get the time elapsed since the next frame. dt = globalClock.getDt() self.new_dt.append(dt) #Store the append here for dt current_time = globalClock.getFrameTime() #This is for the key press if current_time > self.feedback_score_startime + 1.5: self.feebackScoreText.setX(3.) # get the camera position. position_on_track = base.camera.getZ() # get the encoder position from NIDAQ Analog Inputs channel 2 if have_nidaq: encoder_position = self.ai.data[0][self.encodervsigchannel] # zeroth sample in buffer [0], from ai2 [2] # convert to track coordinates encoder_position_diff = (encoder_position - self.previous_encoder_position) if encoder_position_diff > 4.5: encoder_position_diff -= 5. if encoder_position_diff < -4.5: encoder_position_diff += 5. self.encoder_position_diff = encoder_position_diff * self.encoder_gain self.previous_encoder_position = encoder_position else: self.read_keys() if self.upArrowIsPressed: self.encoder_position_diff = -1 * self.encoder_gain if self.downArrowIsPressed: self.encoder_position_diff = 1 * self.encoder_gain if not self.downArrowIsPressed: if not self.upArrowIsPressed: self.encoder_position_diff = 0 position_on_track = base.camera.getZ() + self.encoder_position_diff # reset the camera position self.camera.setPos(base.camera.getX(), base.camera.getY(), position_on_track) self.x.extend([position_on_track]) self.t.extend([globalClock.getFrameTime()]) # first check if the mouse moved on the last frame. if abs(self.last_position - position_on_track) < 1.5: # the mouse didn't move more than 0.5 units on the track self.moved = False if int(position_on_track) in self.cue_zone: # check for cue zone if self.looking_for_a_cue_zone: # make sure we transitioning from the tunnel to a cue zone # increment how long we've been waiting in the cue zone. if self.in_waiting_period: self.time_waited += dt else: self.time_waited = 0 self.in_waiting_period = True if self.time_waited > self.wait_time: # if in cue zone,see if we have been ther for long enough # start a trial self.start_position = position_on_track self.start_time = current_time if not self.stim_started: self.start_a_presentation() print(self.stim_duration) self.stim_started = True self.show_stimulus = True else: self.stim_elapsed += dt if self.stim_elapsed > self.stim_duration: self.show_stimulus = False self.stop_a_presentation() self.time_waited = 0 self.looking_for_a_cue_zone = False # base.setBackgroundColor([0, 0, 1]) else: pass # base.setBackgroundColor([0, 1, 0]) else: self.in_waiting_period = False # base.setBackgroundColor([1,0 , 0]) if self.looking_for_a_cue_zone == False: self.looking_for_a_cue_zone = True if self.stim_started == True: self.stop_a_presentation() else: # the mouse did move self.moved = True if self.stim_started == True: # check if it moved during a presenation self.stop_a_presentation() self.time_waited = 0 self.looking_for_a_cue_zone = False self.show_stimulus = False # if we need to add another segment, do so if position_on_track < self.boundary_to_add_next_segment: self.tunnel.extend([None]) x = self.current_number_of_segments if x % 8 == 0: self.tunnel[x] = loader.loadModel('models/grating') self.cue_zone = concatenate((self.cue_zone, arange( \ self.current_number_of_segments * -TUNNEL_SEGMENT_LENGTH - 50, \ self.current_number_of_segments * -TUNNEL_SEGMENT_LENGTH - TUNNEL_SEGMENT_LENGTH - 100, \ -1))) else: self.tunnel[x] = loader.loadModel('models/tunnel') self.tunnel[x].setPos(0, 0, -TUNNEL_SEGMENT_LENGTH) self.tunnel[x].reparentTo(self.tunnel[x - 1]) # increment self.boundary_to_add_next_segment -= TUNNEL_SEGMENT_LENGTH self.current_number_of_segments += 1 else: pass # print('current:'+str(position_on_track) +' next boundary:' + str(self.boundary_to_add_next_segment)) self.last_position = position_on_track # lick_times = self. # self._read_licks() return Task.cont # Since every return is Task.cont, the task will # continue indefinitely, under control of the mouse (animal) def stimulusControl(self, task): if self.show_stimulus and not self.bufferViewer.isEnabled(): # self.bufferViewer.toggleEnable() self.dr2.setDimensions(0.5, 0.9, 0.5, 0.8) if not self.show_stimulus and self.bufferViewer.isEnabled(): # self.bufferViewer.toggleEnable() self.dr2.setDimensions(0, 0.1, 0, 0.1) return Task.cont def lickControl(self, task): """ Checks to see if a lick is occurring. """ ##TODO: Let user select line for lick sensing. if self.lickSensor: if self.lickSensor.Read()[self.lickline]: self.lickData.extend([globalClock.getFrameTime()]) print('lick happened at: ' + str(self.lickData[-1])) elif self.keycontrol == True: # NO NI BOARD. KEY INPUT? if self.keys[key.SPACE]: data = [globalClock.getFrameTime()] elif self.keys[key.NUM_1]: # print(self.lickData) # elif self.keys[key.NUM_3]: # data = [0,1] # else: # data = [0,0] self.lickData.extend(data) return Task.cont def keyControl(self, task): # listen to and record when the arrows are pressed self.read_keys() if self.rightArrowIsPressed: self.rightKeyData.extend([globalClock.getFrameTime()]) print('right arrow at: ' + str(self.rightKeyData[-1])) # time.sleep(.2) #EAS changed this only allows for one keystroke to be recorded every 0.5s elif self.leftArrowIsPressed: self.leftKeyData.extend([globalClock.getFrameTime()]) print('left arrow at: ' + str(self.leftKeyData[-1])) # time.sleep(.2) #EAS changed this only allows for one keystroke to be recorded every 0.5s return Task.cont def rewardControl(self, task): # print(self.in_reward_window) if self.in_reward_window == True: if self.reward_elapsed < self.reward_window: self.reward_elapsed += globalClock.getDt() # self.new_reward_elapsed.append(self.reward_elapsed) # import pickle # with open('objs.pkl', 'wb') as f: # Python 3: open(..., 'wb') # pickle.dump([self.stim_duration,self.distribution_type_inputs, self.new_rew_control], f) # print('variables saved!!!') self.check_arrows() if not self.AUTO_REWARD: if self.check_arrows() == 1: # if check arrows returns a 1 the right arrow was pressed during stimulus presentation # note reaction time if self.img_id.find("Elephant") != -1: #if the current image file contains the string in () the value is not -1 self._give_reward(self.reward_volume) print('correct: image was mostly elephant') self.in_reward_window = False; self.reward_elapsed = 0. # reset elif 'Same' in self.img_id: #updated 8.24.20: reward 50/50 images 1/2 the time if round(np.random.random(1)[0]): self._give_reward(self.reward_volume) print('correct: image was same') self.in_reward_window = False; self.reward_elapsed = 0. # reset else: print(self.img_mask) print('incorrect: image was same') self.in_reward_window = False self.reward_elapsed = 0. # reset self.score=0 self.show_the_score() else: print(self.img_mask) print('image was not mostly elephant!') self.in_reward_window = False self.reward_elapsed = 0. # reset self.score=0 self.show_the_score() if self.check_arrows() == 2: #if check arrows returns a 2 the left arrow was pressed during stimulus presentation if self.img_id.find("Cheetah") != -1: #if the current image file contains the string in () the value is not -1 self._give_reward(self.reward_volume) print('correct: image was mostly cheetah') self.in_reward_window = False; self.reward_elapsed = 0. # reset elif 'Same' in self.img_id: #updated 8.24.20: reward 50/50 images 1/2 the time if round(np.random.random(1)[0]): self._give_reward(self.reward_volume) print('correct: image was same') self.in_reward_window = False; self.reward_elapsed = 0. # reset else: print(self.img_mask) print('incorrect: image was same') self.in_reward_window = False self.reward_elapsed = 0. # reset self.score=0 self.show_the_score() else: print(self.img_mask) print('image was not mostly cheetah!') self.in_reward_window = False self.reward_elapsed = 0. # reset self.score=0 self.show_the_score() else: self._give_reward(self.reward_volume) self.in_reward_window = False; self.reward_elapsed = 0. # reset # base.setBackgroundColor([1, 1, 0]) # # if self.keys[key.NUM_1]: # # print('reward!') else: self.score=0 self.show_the_score() self.in_reward_window = False self.reward_elapsed = 0. else: pass#print('not listening for reward'+str(globalClock.getFrameTime())) return Task.cont def _setupEyetracking(self): """ sets up eye tracking""" try: eyetrackerip = "DESKTOP-EE5KKDO" eyetrackerport = 10000 trackeyepos = False from aibs.Eyetracking.EyetrackerClient import Client self.eyetracker = Client(outgoing_ip=eyetrackerip, outgoing_port=eyetrackerport, output_filename=str(datetime.datetime.now()).replace(':', '').replace('.', '').replace( ' ', '-')) self.eyetracker.setup() # eyedatalog = [] # if trackeyepos: # eyeinitpos = None except: print("Could not initialize eyetracker:") self.eyetracker = None def _startEyetracking(self): if self.eyetracker: self.eyetracker.recordStart() def _setupDAQ(self): """ Sets up some digital IO for sync and tiggering. """ print('SETTING UP DAQ') try: if self.invertdo: istate = 'low' else: istate = 'high' self.do = DigitalOutput(self.nidevice, self.doport, initial_state='low') self.do.StartTask() except: # Exception, e: print("Error starting DigitalOutput task:") self.do = None try: self.di = DigitalInput(self.nidevice, self.diport) self.di.StartTask() except: # Exception, e: print("Error starting DigitalInput task:") self.di = None # try: # set up 8 channels, only use 2 though for now self.ai = AnalogInput(self.nidevice, range(8), buffer_size=25, terminal_config='RSE', clock_speed=6000.0, voltage_range=[-5.0, 5.0]) self.ai.StartTask() # except:# Exception, e: # print("Error starting AnalogInput task:") # self.ai = None try: self.ao = AnalogOutput(self.nidevice, channels=[0, 1], terminal_config='RSE', voltage_range=[0.0, 5.0]) self.ao.StartTask() except: # Exception, e: print("Error starting AnalogOutput task:") self.ao = None def read_keys(self): self.upArrowIsPressed = base.mouseWatcherNode.isButtonDown(KeyboardButton.up()) self.downArrowIsPressed = base.mouseWatcherNode.isButtonDown(KeyboardButton.down()) self.rightArrowIsPressed = base.mouseWatcherNode.isButtonDown(KeyboardButton.right()) self.leftArrowIsPressed = base.mouseWatcherNode.isButtonDown(KeyboardButton.left()) def save_data(self): if not os.path.isdir(os.path.join(os.getcwd(), 'data')): os.mkdir(os.path.join(os.getcwd(), 'data')) save_path = os.path.join(os.getcwd(), 'data', str(MOUSE_ID) + '_' + \ str(self.session_start_time.year) + '_' + \ str(self.session_start_time.month) + '_' + \ str(self.session_start_time.day) + '-' + \ str(self.session_start_time.hour) + '_' + \ str(self.session_start_time.minute) + '_' + \ str(self.session_start_time.second)) if not os.path.isdir(save_path): os.mkdir(save_path) print("saving data to " + save_path) np.save(os.path.join(save_path, 'licks.npy'), self.lickData) np.save(os.path.join(save_path, 'x.npy'), self.x) np.save(os.path.join(save_path, 't.npy'), self.t) np.save(os.path.join(save_path, 'trialData.npy'), self.trialData) np.save(os.path.join(save_path, 'rewardData.npy'), self.rewardData) np.save(os.path.join(save_path, 'rtData.npy'), self.reactionTimeData) np.save(os.path.join(save_path, 'rightKeyData.npy'), self.rightKeyData) np.save(os.path.join(save_path, 'leftKeyData.npy'), self.leftKeyData) np.save(os.path.join(save_path, 'imageData.npy'), self.imageData) np.save(os.path.join(save_path, 'imageTimeData.npy'), self.imageTimeData) np.save(os.path.join(save_path, 'scoreData.npy'), self.scoreData) np.save(os.path.join(save_path, 'trialDurationData.npy'), self.trialDurationData) np.save(os.path.join(save_path, 'dT.npy'), self.new_dt) def close(self): self.save_data() print('rewardData:') print(np.shape(self.rewardData)) try: #push anonymized data to Denman Lab Open Science Framework project for human psychophysics subprocess.call('osf -p 7xruh -u [email protected] upload -r '+save_path+' data/'+os.path.basename(save_path),shell=True) #commented these lines out to test if saving to osf is the hangup; it's not except:pass sys.exit(0)
class MyApp(ShowBase): gameMode = "Intro" def __init__(self): ShowBase.__init__(self) #self.cameraSetup() self.setupKeyboard() self.initIntro() def gameChangeMode(self): if base.gameMode == "Intro": self.initIntro() elif base.gameMode == "Convo": self.initConvo() def initIntro(self): self.fadeAlpha = 0.0 self.fadeTime = 30.0 self.fadeInc = 1.0 / self.fadeTime self.fadeDir = "up" self.sceneImage = OnscreenImage(image="images/scene.png", scale=(1920.0 / 1080.0, 1, 1)) self.sceneImage.setTransparency(TransparencyAttrib.MAlpha) self.sceneImage.setAlphaScale(self.fadeAlpha) self.imageNumber = 0 self.sceneImageList = ["images/scene.png", "images/image1.jpg"] #self.texty = OnscreenText(str(self.fadeAlpha)) taskMgr.add(self.gameIntroUpdate, "GameIntroUpdate") def gameIntroUpdate(self, task): self.slideManager() if (base.gameMode != "Intro"): self.gameChangeMode() return Task.done return Task.cont def cameraSetup(self): base.camLens.setAspectRatio(1920.0 / 1080.0) def slideManager(self): if self.fadeDir == "up" and self.fadeAlpha < 1: self.fadeAlpha += self.fadeInc self.sceneImage.setAlphaScale(self.fadeAlpha) #self.texty.setText(str(self.fadeAlpha)) if self.fadeDir == "down" and self.fadeAlpha > 0: self.fadeAlpha -= self.fadeInc self.sceneImage.setAlphaScale(self.fadeAlpha) if self.fadeDir == "up" and self.fadeAlpha >= 1: self.fadeDir = "down" if self.fadeDir == "down" and self.fadeAlpha <= 0: if self.imageNumber < 1: self.fadeDir = "up" self.sceneImage.setImage(self.nextImage()) self.sceneImage.setTransparency(TransparencyAttrib.MAlpha) self.sceneImage.setAlphaScale(self.fadeAlpha) else: self.fadeDir = "up" base.gameMode = "Convo" self.sceneImage.setImage(self.sceneImageList[self.imageNumber]) self.sceneImage.setTransparency(TransparencyAttrib.MAlpha) self.sceneImage.setAlphaScale(self.fadeAlpha) def nextImage(self): self.imageNumber += 1 return self.sceneImageList[self.imageNumber] def initConvo(self): self.textToType = "This will be used for talking\nThis is a good conversation box" self.textVisible = "" self.strOptionA = "Yes" self.strOptionB = "No" self.strOptionC = "Maybe" self.convoResponseSelected = False self.convoDepth = "1" self.intOptionCount = 3 #self.txtConvo = OnscreenText(self.textVisible, align = TextNode.ALeft) self.txtConvo = TextNode("Texty Bastard") self.txtConvo.setText(self.textToType) self.txtReply = TextNode("reply") self.txtReply.setText("") self.intHover = 0 #self.txtConvo.setFrameColor(0, 0, 1, 1) #self.txtConvo.setFrameAsMargin(0.2, 0.2, 0.1, 0.1) myFrame = DirectFrame(frameColor=(0.8, 0.8, 0.8, 0.4), frameSize=(-1, 0, -1, 0)) nodePathConvo = aspect2d.attachNewNode(self.txtConvo) nodePathConvo.setScale(0.07) nodePathConvo.setPos(-1, 0, -0.1) self.i = 0 self.indent = 0.0 self.selectedResponse = 0 self.txtOptionA = OnscreenText(text="", pos=(-1, -0.6), align=TextNode.ALeft) self.txtOptionB = OnscreenText(text="", pos=(-1, -0.7), align=TextNode.ALeft) self.txtOptionC = OnscreenText(text="", pos=(-1, -0.8), align=TextNode.ALeft) taskMgr.add(self.gameConvoUpdate, "GameConvoUpdate") def gameConvoUpdate(self, task): if (len(self.textVisible) != len(self.textToType)): task.delayTime = 0.001 while (self.i < len(self.textToType)): self.textVisible += self.textToType[self.i] self.txtConvo.setText(self.textVisible) self.i += 1 return Task.again else: taskMgr.add(self.gameConvoOptions, "ConvoOptions") return Task.done def gameConvoOptions(self, task): self.txtOptionA.setText(self.strOptionA) self.txtOptionB.setText(self.strOptionB) self.txtOptionC.setText(self.strOptionC) if self.convoResponseSelected == True: if self.convoCheckBranch("01", self.convoDepth): #self.txtConvo.setText(self.convoGetStrings("01", self.convoDepth)) self.convoNextDialogue("01", self.convoDepth) else: #self.txtConvo.setText("It DIDn't worked") self.convoDepth = "1" self.convoNextDialogue("01", self.convoDepth) return Task.done elif self.selectedResponse == 0: if self.intOptionCount > 0: self.txtOptionA.setX(-1 + self.indent) self.txtOptionA.setFg(fg=(1, 0, 0, 1)) if self.intOptionCount > 1: self.txtOptionB.setX(-1) self.txtOptionB.setFg(fg=(0, 0, 0, 1)) if self.intOptionCount > 2: self.txtOptionC.setX(-1) self.txtOptionC.setFg(fg=(0, 0, 0, 1)) self.indent = self.getIndent(self.indent, 0.01, 0.1) return Task.again elif self.selectedResponse == 1: if self.intOptionCount > 0: self.txtOptionA.setX(-1) self.txtOptionA.setFg(fg=(0, 0, 0, 1)) if self.intOptionCount > 1: self.txtOptionB.setX(-1 + self.indent) self.txtOptionB.setFg(fg=(1, 0, 0, 1)) if self.intOptionCount > 2: self.txtOptionC.setX(-1) self.txtOptionC.setFg(fg=(0, 0, 0, 1)) self.indent = self.getIndent(self.indent, 0.01, 0.1) return Task.again elif self.selectedResponse == 2: if self.intOptionCount > 0: self.txtOptionA.setX(-1) self.txtOptionA.setFg(fg=(0, 0, 0, 1)) if self.intOptionCount > 1: self.txtOptionB.setX(-1) self.txtOptionB.setFg(fg=(0, 0, 0, 1)) if self.intOptionCount > 2: self.txtOptionC.setX(-1 + self.indent) self.txtOptionC.setFg(fg=(1, 0, 0, 1)) self.indent = self.getIndent(self.indent, 0.01, 0.1) return Task.again def convoGetStrings(self, npcId, depth): if self.convoCheckBranch(npcId, depth) != True: return "#Error# String Not Found\nLooking for: " + "(" + str( npcId) + ")." + depth + ":" char = "" line = "" feed = "" path = os.path.abspath(os.getcwd()) f = open(path + "\\text\\stringsConvo.txt", "r") while line != "(" + str(npcId) + ")." + depth + ":": while char != ":": char = f.readline(1) line += char feed += "\n" + line if line != "(" + str(npcId) + ")." + depth + ":": char = "" line = "" f.readline() print(feed + " Selected") f.readline(1) line = f.readline() line = line.replace("##", "\n") f.close() return line def convoCheckBranch(self, npcId, depth): path = os.path.abspath(os.getcwd()) f = open(path + "\\text\\stringsConvo.txt", "r") char = "" line = "" branchFound = False while line != "<END>:": char = "" line = "" while char != ":": char = f.readline(1) line += char if line == "<END>:": f.close() return False elif line == "(" + str(npcId) + ")." + str(depth) + ":": f.close() return True else: f.readline() def convoNextDialogue(self, npcId, depth): self.textToType = self.convoGetStrings(npcId, depth) self.intOptionCount = self.convoGetOptionCount(npcId, depth) if self.intOptionCount == 1: self.strOptionA = self.convoGetStrings(npcId, depth + ".A") self.strOptionB = "" self.strOptionC = "" elif self.intOptionCount == 2: self.strOptionA = self.convoGetStrings(npcId, depth + ".A") self.strOptionB = self.convoGetStrings(npcId, depth + ".B") self.strOptionC = "" elif self.intOptionCount == 3: self.strOptionA = self.convoGetStrings(npcId, depth + ".A") self.strOptionB = self.convoGetStrings(npcId, depth + ".B") self.strOptionC = self.convoGetStrings(npcId, depth + ".C") else: self.strOptionA = "" self.strOptionB = "" self.strOptionC = "" self.textVisible = "" self.txtOptionA.setText("") self.txtOptionB.setText("") self.txtOptionC.setText("") self.txtConvo.setText(self.textVisible) #self.intOptionCount = 2 self.selectedResponse = 0 self.i = 0 self.convoResponseSelected = False taskMgr.add(self.gameConvoUpdate, "GameConvoUpdate") def convoGetOptionCount(self, npcId, depth): if self.convoCheckBranch( npcId, depth + ".A") and self.convoCheckBranch( npcId, depth + ".B") and self.convoCheckBranch( npcId, depth + ".C"): return 3 elif self.convoCheckBranch(npcId, depth + ".A") and self.convoCheckBranch( npcId, depth + ".B"): return 2 elif self.convoCheckBranch(npcId, depth + ".A"): return 1 else: return 0 def getIndent(self, value, increment, limit): if (value + increment >= limit): return limit else: return value + increment def setupKeyboard(self): self.accept("arrow_down", self.convoOptionDown) self.accept("arrow_up", self.convoOptionUp) self.accept("enter", self.convoOptionSelect) def convoOptionUp(self): self.indent = 0.0 if self.selectedResponse == 0: self.selectedResponse = self.intOptionCount - 1 elif self.selectedResponse > 0: self.selectedResponse -= 1 def convoOptionDown(self): self.indent = 0.0 if self.selectedResponse < self.intOptionCount - 1: self.selectedResponse += 1 elif self.selectedResponse == self.intOptionCount - 1: self.selectedResponse = 0 def convoOptionSelect(self): if self.selectedResponse == 0: self.convoDepth += ".A.1" elif self.selectedResponse == 1: self.convoDepth += ".B.1" elif self.selectedResponse == 2: self.convoDepth += ".C.1" self.convoResponseSelected = True
class MyApp(ShowBase): gameMode = "Intro" def __init__(self): ShowBase.__init__(self) #self.cameraSetup() self.setupKeyboard() self.initIntro() def gameChangeMode(self): if base.gameMode == "Intro": self.initIntro() elif base.gameMode == "Convo": self.initConvo() def initIntro(self): self.fadeAlpha = 0.0 self.fadeTime = 30.0 self.fadeInc = 1.0/self.fadeTime self.fadeDir = "up" self.sceneImage = OnscreenImage(image = "images/scene.png", scale = (1920.0/1080.0,1,1)) self.sceneImage.setTransparency(TransparencyAttrib.MAlpha) self.sceneImage.setAlphaScale(self.fadeAlpha) self.imageNumber = 0 self.sceneImageList = ["images/scene.png","images/image1.jpg"] #self.texty = OnscreenText(str(self.fadeAlpha)) taskMgr.add(self.gameIntroUpdate, "GameIntroUpdate") def gameIntroUpdate(self, task): self.slideManager() if (base.gameMode != "Intro"): self.gameChangeMode() return Task.done return Task.cont def cameraSetup(self): base.camLens.setAspectRatio(1920.0/1080.0) def slideManager(self): if self.fadeDir == "up" and self.fadeAlpha<1: self.fadeAlpha += self.fadeInc self.sceneImage.setAlphaScale(self.fadeAlpha) #self.texty.setText(str(self.fadeAlpha)) if self.fadeDir == "down" and self.fadeAlpha > 0: self.fadeAlpha -= self.fadeInc self.sceneImage.setAlphaScale(self.fadeAlpha) if self.fadeDir == "up" and self.fadeAlpha >= 1: self.fadeDir = "down" if self.fadeDir == "down" and self.fadeAlpha <= 0: if self.imageNumber < 1: self.fadeDir = "up" self.sceneImage.setImage(self.nextImage()) self.sceneImage.setTransparency(TransparencyAttrib.MAlpha) self.sceneImage.setAlphaScale(self.fadeAlpha) else: self.fadeDir = "up" base.gameMode = "Convo" self.sceneImage.setImage(self.sceneImageList[self.imageNumber]) self.sceneImage.setTransparency(TransparencyAttrib.MAlpha) self.sceneImage.setAlphaScale(self.fadeAlpha) def nextImage(self): self.imageNumber += 1 return self.sceneImageList[self.imageNumber] def initConvo(self): self.textToType = "This will be used for talking\nThis is a good conversation box" self.textVisible = "" self.strOptionA = "Yes" self.strOptionB = "No" self.strOptionC = "Maybe" self.convoResponseSelected = False self.convoDepth = "1" self.intOptionCount = 3 #self.txtConvo = OnscreenText(self.textVisible, align = TextNode.ALeft) self.txtConvo = TextNode("Texty Bastard") self.txtConvo.setText(self.textToType) self.txtReply = TextNode("reply") self.txtReply.setText("") self.intHover = 0 #self.txtConvo.setFrameColor(0, 0, 1, 1) #self.txtConvo.setFrameAsMargin(0.2, 0.2, 0.1, 0.1) myFrame = DirectFrame(frameColor=(0.8, 0.8, 0.8, 0.4), frameSize=(-1, 0, -1, 0)) nodePathConvo = aspect2d.attachNewNode(self.txtConvo) nodePathConvo.setScale(0.07) nodePathConvo.setPos(-1, 0, -0.1) self.i = 0 self.indent = 0.0 self.selectedResponse = 0 self.txtOptionA = OnscreenText(text = "", pos = (-1,-0.6), align = TextNode.ALeft) self.txtOptionB = OnscreenText(text = "", pos = (-1,-0.7), align = TextNode.ALeft) self.txtOptionC = OnscreenText(text = "", pos = (-1,-0.8), align = TextNode.ALeft) taskMgr.add(self.gameConvoUpdate, "GameConvoUpdate") def gameConvoUpdate(self, task): if (len(self.textVisible) != len(self.textToType)): task.delayTime = 0.001 while (self.i < len(self.textToType)): self.textVisible += self.textToType[self.i] self.txtConvo.setText(self.textVisible) self.i += 1 return Task.again else: taskMgr.add(self.gameConvoOptions, "ConvoOptions") return Task.done def gameConvoOptions(self, task): self.txtOptionA.setText(self.strOptionA) self.txtOptionB.setText(self.strOptionB) self.txtOptionC.setText(self.strOptionC) if self.convoResponseSelected == True: if self.convoCheckBranch("01", self.convoDepth): #self.txtConvo.setText(self.convoGetStrings("01", self.convoDepth)) self.convoNextDialogue("01", self.convoDepth) else: #self.txtConvo.setText("It DIDn't worked") self.convoDepth = "1" self.convoNextDialogue("01", self.convoDepth) return Task.done elif self.selectedResponse == 0: if self.intOptionCount > 0: self.txtOptionA.setX(-1+self.indent) self.txtOptionA.setFg(fg = (1,0,0,1)) if self.intOptionCount > 1: self.txtOptionB.setX(-1) self.txtOptionB.setFg(fg = (0,0,0,1)) if self.intOptionCount > 2: self.txtOptionC.setX(-1) self.txtOptionC.setFg(fg = (0,0,0,1)) self.indent = self.getIndent(self.indent,0.01,0.1) return Task.again elif self.selectedResponse == 1: if self.intOptionCount > 0: self.txtOptionA.setX(-1) self.txtOptionA.setFg(fg = (0,0,0,1)) if self.intOptionCount > 1: self.txtOptionB.setX(-1+self.indent) self.txtOptionB.setFg(fg = (1,0,0,1)) if self.intOptionCount > 2: self.txtOptionC.setX(-1) self.txtOptionC.setFg(fg = (0,0,0,1)) self.indent = self.getIndent(self.indent,0.01,0.1) return Task.again elif self.selectedResponse == 2: if self.intOptionCount > 0: self.txtOptionA.setX(-1) self.txtOptionA.setFg(fg = (0,0,0,1)) if self.intOptionCount > 1: self.txtOptionB.setX(-1) self.txtOptionB.setFg(fg = (0,0,0,1)) if self.intOptionCount > 2: self.txtOptionC.setX(-1+self.indent) self.txtOptionC.setFg(fg = (1,0,0,1)) self.indent = self.getIndent(self.indent,0.01,0.1) return Task.again def convoGetStrings(self,npcId,depth): if self.convoCheckBranch(npcId,depth) != True: return "#Error# String Not Found\nLooking for: "+"("+str(npcId)+")."+depth+":" char = "" line = "" feed = "" path = os.path.abspath(os.getcwd()) f = open(path+"\\text\\stringsConvo.txt","r") while line != "("+str(npcId)+")."+depth+":": while char != ":": char = f.readline(1) line += char feed += "\n"+line if line != "("+str(npcId)+")."+depth+":": char = "" line = "" f.readline() print(feed + " Selected") f.readline(1) line = f.readline() line = line.replace("##", "\n") f.close() return line def convoCheckBranch(self,npcId,depth): path = os.path.abspath(os.getcwd()) f = open(path+"\\text\\stringsConvo.txt","r") char = "" line = "" branchFound = False while line != "<END>:": char = "" line = "" while char != ":": char = f.readline(1) line += char if line == "<END>:": f.close() return False elif line == "("+str(npcId)+")."+str(depth)+":": f.close() return True else: f.readline() def convoNextDialogue(self,npcId,depth): self.textToType = self.convoGetStrings(npcId, depth) self.intOptionCount = self.convoGetOptionCount(npcId, depth) if self.intOptionCount == 1: self.strOptionA = self.convoGetStrings(npcId, depth+".A") self.strOptionB = "" self.strOptionC = "" elif self.intOptionCount == 2: self.strOptionA = self.convoGetStrings(npcId, depth+".A") self.strOptionB = self.convoGetStrings(npcId, depth+".B") self.strOptionC = "" elif self.intOptionCount == 3: self.strOptionA = self.convoGetStrings(npcId, depth+".A") self.strOptionB = self.convoGetStrings(npcId, depth+".B") self.strOptionC = self.convoGetStrings(npcId, depth+".C") else: self.strOptionA = "" self.strOptionB = "" self.strOptionC = "" self.textVisible = "" self.txtOptionA.setText("") self.txtOptionB.setText("") self.txtOptionC.setText("") self.txtConvo.setText(self.textVisible) #self.intOptionCount = 2 self.selectedResponse = 0 self.i = 0 self.convoResponseSelected = False taskMgr.add(self.gameConvoUpdate, "GameConvoUpdate") def convoGetOptionCount(self,npcId,depth): if self.convoCheckBranch(npcId,depth+".A") and self.convoCheckBranch(npcId,depth+".B") and self.convoCheckBranch(npcId,depth+".C"): return 3 elif self.convoCheckBranch(npcId,depth+".A") and self.convoCheckBranch(npcId,depth+".B"): return 2 elif self.convoCheckBranch(npcId,depth+".A"): return 1 else: return 0 def getIndent(self, value, increment, limit): if (value + increment >= limit): return limit else: return value+increment def setupKeyboard(self): self.accept("arrow_down", self.convoOptionDown) self.accept("arrow_up", self.convoOptionUp) self.accept("enter",self.convoOptionSelect) def convoOptionUp(self): self.indent = 0.0 if self.selectedResponse == 0: self.selectedResponse = self.intOptionCount-1 elif self.selectedResponse > 0: self.selectedResponse -= 1 def convoOptionDown(self): self.indent = 0.0 if self.selectedResponse < self.intOptionCount-1: self.selectedResponse += 1 elif self.selectedResponse == self.intOptionCount-1: self.selectedResponse = 0 def convoOptionSelect(self): if self.selectedResponse == 0: self.convoDepth += ".A.1" elif self.selectedResponse == 1: self.convoDepth += ".B.1" elif self.selectedResponse == 2: self.convoDepth += ".C.1" self.convoResponseSelected = True