class RhomdosRender: def __init__(self, game, duration=None, storage_path="storage/3d/frame", fps=30, as_gif=False, gif_name=None, size=(480, 480)): self.game = game self.duration = duration self.storage_path = storage_path self.fps = fps self.as_gif = as_gif self.gif_name = gif_name self.base = ShowBase(windowType='none') self.base.openWindow(type=('offscreen' if as_gif else 'onscreen'), size=size) depth, height, width = game.shape self.rhomdos = [] for z in range(depth): self.rhomdos.append([]) for y in range(height): self.rhomdos[-1].append([]) for x in range(width): rr = RhomdoRender((z, y, x), game.shape) render.attachNewNode(rr.geomnode) self.rhomdos[-1][-1].append(rr) plight = PointLight('plight') plight.setColor(VBase4(1, 1, 1, 1)) plight.setAttenuation((0, 0, .0005)) self.plnp = render.attachNewNode(plight) self.plnp.setPos(0, 0, (game.shape[0] * SR2) + 40) render.setLight(self.plnp) if self.as_gif: self.base.movie(self.storage_path, duration=self.duration, fps=self.fps) self.base.taskMgr.add(self.spinCameraTask, "SpinCameraTask") self.base.taskMgr.add(self.updateClock, "UpdateClock") self.frame = 0 self.game_step = 0 def spinCameraTask(self, task): angleDegrees = task.time * 40.0 angleRadians = angleDegrees * (pi / 180.0) self.base.camera.setPos(60 * sin(angleRadians), -60 * cos(angleRadians), 32) self.base.camera.setHpr(angleDegrees, -30, 0) return Task.cont def run(self): if self.as_gif: for i in tqdm(list(range(self.duration * self.fps))): self.base.taskMgr.step() self.generate_gif() else: while True: self.base.taskMgr.step() def updateClock(self, task): self.frame = task.time adjusted_time = task.time * 8 if ceil(adjusted_time) > self.game_step: self.updateRhomdos() self.game_step = ceil(adjusted_time) return Task.cont def generate_gif(self): with imageio.get_writer(self.gif_name, mode='I') as writer: for i in tqdm(list(range(3, self.duration * self.fps))): filename = f"{self.storage_path}_{str(i).rjust(4, '0')}.png" writer.append_data(imageio.imread(filename)) os.remove(filename) def updateRhomdos(self): self.game.advance() depth, height, width = self.game.shape for z in range(depth): for y in range(height): for x in range(width): rr = self.rhomdos[z][y][x] if self.game.grid[-1, z, y, x, 0] == 1: rr.show() else: rr.hide()
class BananaWorld(DirectObject): def __init__(self, movie_data_file, record, use_eye_data=False, use_lfp_data=False): DirectObject.__init__(self) self.record = record # make sure directory exists movie_name = '../movies/frames/game/game' environ = 'original' # environ = 'circle' data = MovieData(movie_data_file, use_eye_data) # Things that can affect camera: # options resolution resW resH self.base = ShowBase() lens = PerspectiveLens() # Fov is set in config for 60 lens.setFov(60) # aspect ratio should be same as window size # this was for 800x600 # field of view 60 46.8264... # aspect ratio 1.3333 movie_res = [800, 600] # set aspect ratio to original game #print resolution lens.setAspectRatio(data.resolution[0] / data.resolution[1]) #print lens.getAspectRatio() #lens.setAspectRatio(800.0 / 600.0) self.base.cam.node().setLens(lens) # print('Fov', lens.getFov()) # print('Aspect Ratio', lens.getAspectRatio()) # set near to be same as avatar's radius # affects how close you get to the bananas lens.setNear(0.1) #print('near camera', lens.getNear()) #base.cam.setPos(0, 0, 1) #print('x', base.win.getXSize()) #print('y', base.win.getYSize()) # when doing the calibration task I used the orthographic lens with normal render, # so the origin was in the center, but when using pixel2d the origin is in the top # left corner, so we must move the coordinate system to the right and down by half # the screen # covert resolution eye_factor = [movie_res[0]/data.resolution[0], movie_res[1]/data.resolution[1]] # print('move_res', movie_res) # print('actual movie res', self.base.win.getXSize(), self.base.win.getYSize()) # print('data_res', data.resolution) # print('eye factor', eye_factor) # calibration not very good... #fudge_factor_x = 50 #fudge_factor_y = 80 fudge_factor_x = 0 fudge_factor_y = 60 self.eye_data = deque() self.last_eye_ts = None # since for eye_data we are looping and adding to the end of the list, # but then we will be pulling from the front of the list, we have a queue, # so let's use deque. (Other data was reversed in movie_data). if use_eye_data: for i in data.raw_eye_data: x = (float(i[0]) * eye_factor[0]) + (self.base.win.getXSize() / 2) + fudge_factor_x y = (float(i[1]) * eye_factor[1]) - (self.base.win.getYSize() / 2) + fudge_factor_y self.eye_data.append((x, y)) #print self.eye_data # container for eye trace self.eyes = [] #print(len(self.eye_data)) # make generators for eye data self.last_eye = self.eye_data.popleft() #print(len(self.eye_data)) # time stamps are all reversed, so can use normal pop and then assign directly, # like other time variables self.last_eye_ts = data.eye_ts.pop() self.eye_ts = data.eye_ts # need to adjust y position for lfp self.lfp_gain = 0.05 # lfp_offset determines where each trace is on the y axis lfp_offset = -500 # bottom self.lfp_offset = [] #self.lfp_offset = -100 # top of screen self.last_lfp = [] self.gen_lfp = [] # make a generator for lfp data # this code is a little silliness, and I'm popping a giant list from the wrong end # when I start plotting lfp again, fix this! if use_lfp_data: for data in data.lfp_data: self.lfp_offset.append(lfp_offset) self.last_lfp.append([(data.pop(0) * self.lfp_gain) + lfp_offset]) lfp_offset += 100 # self.gen_lfp.append(get_data(data)) # last_lfp_x determines where on the x axis we start the lfp trace self.start_x_trace = 50 # bring in data we care about. self.avatar_pos = data.avatar_pos self.avatar_pt = data.avatar_pt self.avatar_h = data.avatar_h self.avatar_ht = data.avatar_ht self.fruit_status = data.fruit_status self.fruit_status_ts = data.fruit_status_ts self.fruit_pos = data.fruit_pos self.fruit_pos_ts = data.fruit_pos_ts self.trial_mark = data.trial_mark # print 'fruit pos timestamps', self.fruit_pos_ts # initialize other variables self.eye_spot = None # set starting point for avatar points = self.avatar_pos.pop() self.base.cam.setPos(Point3(points[0], points[1], points[2])) self.base.cam.setH(self.avatar_h.pop()) self.avatar_ht.pop() self.avatar_pt.pop() # get last time stamp (first of list) for avatar to calculate length of movie # add half a second buffer. movie_length = self.avatar_ht[0] + 0.8 print('movie length', movie_length) self.set_environment(environ) #load bananas # if we are not starting at the beginning of the trial, some of the bananas may # already be gone. Create them, and then stash them, so the index still refers to # the correct banana self.fruitModel = {} # print('fruit', self.fruit_pos) for k, v in self.fruit_pos.iteritems(): #print('i', i) # print('k', k) #print('v', v) if 'banana' in k: self.fruitModel[k] = self.base.loader.loadModel('../goBananas/models/bananas/banana.bam') self.fruitModel[k].setScale(0.5) elif 'cherry' in k: self.fruitModel[k] = self.base.loader.loadModel('../goBananas/models/fruit/cherries.egg') self.fruitModel[k].setScale(0.08) # position = self.fruit_pos[k]['position'].pop(0) # print position heading = v['head'] #print heading # self.fruitModel[k].setPos( # Point3(float(position[0]), float(position[1]), float(position[2]))) self.fruitModel[k].setH(float(heading)) self.fruitModel[k].reparentTo(self.base.render) # assume all fruit stashed to start self.fruitModel[k].stash() if k in data.alpha: print 'set alpha', data.alpha self.alpha_node_path = self.fruitModel[k] self.alpha_node_path.setTransparency(TransparencyAttrib.MAlpha) if self.record: print('make movie', movie_name) self.movie_task = self.base.movie(movie_name, movie_length, 30, 'png', 4) self.gameTask = taskMgr.add(self.frame_loop, "frame_loop") self.gameTask.last = 0 # Task time of the last frame #print('trialmarks', self.trial_mark) #print('start', self.gameTask.game_time) #print('head start', self.avatar_ht[-1]) #print('increment', (1 / 60) * 1000000) def set_environment(self, environ): if environ == 'original': terrainModel = self.base.loader.loadModel('../goBananas/models/play_space/field.bam') skyModel = self.base.loader.loadModel('../goBananas/models/sky/sky.bam') skyModel.setPos(Point3(0, 0, 0)) skyModel.setScale(1.6) treeModel = self.base.loader.loadModel('../goBananas/models/trees/palmTree.bam') treeModel.setPos(Point3(13, 13, 0)) treeModel.setScale(0.0175) treeModel.reparentTo(self.base.render) skyscraper = self.base.loader.loadModel('../goBananas/models/skyscraper/skyscraper.bam') skyscraper.setPos(Point3(-13, -13, 0)) skyscraper.setScale(0.3) skyscraper.reparentTo(self.base.render) stLightModel = self.base.loader.loadModel('../goBananas/models/streetlight/streetlight.bam') stLightModel.setPos(Point3(-13, 13, 0)) stLightModel.setScale(0.75) stLightModel.reparentTo(self.base.render) elif environ == 'circle': terrainModel = self.base.loader.loadModel('../goBananas/models/play_space/round_courtyard.bam') skyModel = self.base.loader.loadModel('../goBananas/models/sky/sky_kahana2.bam') skyModel.setPos(Point3(0, 0, -0.5)) skyModel.setScale(Point3(2, 2, 4)) terrainModel.setPos(Point3(0, 0, 0)) terrainModel.reparentTo(self.base.render) #print 'terrain', terrainModel.getPos() skyModel.reparentTo(self.base.render) #print 'sky', skyModel.getPos() self.eye_spot = self.base.loader.loadModel("models/ball") #eye_texture = base.loader.loadTexture('textures/spotlight.png') #self.eye_spot.setTexture(eye_texture, 1) self.eye_spot.setScale(50) self.eye_spot.setTransparency(TransparencyAttrib.MAlpha) self.eye_spot.setColor(1, 1, 1, 0.3) def frame_loop(self, task): dt = task.time - task.last task.last = task.time #print('time', task.time) #print('trial marker', self.trial_mark[-1]) # check to see if anything has happened. # there is a position and heading for every time stamp for the avatar. if self.avatar_pt: self.update_avt_p(task.time) else: # if we aren't moving the avatar anymore, assume done print 'done' return task.done if self.avatar_ht: self.update_avt_h(task.time) if self.fruit_pos_ts: self.move_fruit(task.time) if self.fruit_status_ts: self.update_fruit(task.time) # if len(self.banana_ts) > 0 and self.banana_ts[0] < task.time - 0.5: # self.update_banana() if self.last_eye_ts: self.update_eye(task.time) #if self.trial_mark and self.trial_mark[-1] < task.time: # self.move_fruit() for ind, last_lfps in enumerate(self.last_lfp): self.update_LFP(dt, last_lfps, self.lfp[ind], self.lfp_offset[ind], self.gen_lfp[ind]) return task.cont def update_avt_h(self, t_time): while self.avatar_ht[-1] < t_time: self.base.cam.setH(self.avatar_h.pop()) self.avatar_ht.pop() if not self.avatar_ht: break def update_avt_p(self, t_time): # print('avatar', self.avatar_pt[-1], 'time', t_time) while self.avatar_pt[-1] < t_time: points = self.avatar_pos.pop() # print points self.base.cam.setPos(Point3(points[0], points[1], points[2])) self.avatar_pt.pop() if not self.avatar_pt: break def update_fruit(self, t_time): # print self.avatar_pos[-1] while self.fruit_status_ts[-1] < t_time: current_list = self.fruit_status.pop() # print 'current list', current_list # list goes: fruit name, what happens, how much if current_list[1] == 'alpha': # sometimes alpha is one... if float(current_list[2]) <= 1: self.alpha_node_path.setAlphaScale(float(current_list[2])) if current_list[1] == 'stash': if current_list[2] == 'True': self.fruitModel[current_list[0]].stash() else: # print 'unstash', current_list[0] self.fruitModel[current_list[0]].unstash() # print self.fruitModel[current_list[0]].isStashed() self.fruit_status_ts.pop() if not self.fruit_status_ts: break def move_fruit(self, t_time): # did not reverse, since pain in the ass, and likely not many # print 'position', self.fruit_pos_ts[0][0] # print 'delete' self.fruit_pos_ts # print 'time', t_time while self.fruit_pos_ts[0][0] < t_time: ts, fruit = self.fruit_pos_ts.pop(0) # print('current time stamp', ts) position = self.fruit_pos[fruit]['position'].pop(0) # print('move fruit', fruit, position) self.fruitModel[fruit].setPos( Point3(float(position[0]), float(position[1]), float(position[2]))) # print('next timestamp', self.fruit_pos_ts[0]) if not self.fruit_pos_ts: break def update_LFP(self, dt, last_lfp, lfp_trace, offset, gen_lfp): # lfp data is taken at 1000Hz, and dt is the number of seconds since # the last frame was flipped, so plot number of points = dt * 1000 lfp = LineSegs() lfp.setThickness(1.0) #print('points to plot', int(dt * 1000)) #self.lfp_test += int(dt * 1000) #print('points so far', self.lfp_test) for i in range(int(dt * 1000)): try: last_lfp.append((next(gen_lfp) * self.lfp_gain) + offset) #last_lfp_x += 0.05 # only plotting 200 data points at a time while len(last_lfp) > 3500: last_lfp.pop(0) except StopIteration: #print('done with lfp') break if lfp_trace: lfp_trace[0].removeNode() lfp_trace.pop(0) lfp.moveTo(self.start_x_trace, 55, last_lfp[0]) x = self.start_x_trace for i in last_lfp: x += .1 lfp.drawTo(x, 55, i) node = self.base.pixel2d.attachNewNode(lfp.create()) lfp_trace.append(node) # get rid of lfp trace from a while ago.. #while len(self.lfp) > 50: # self.lfp[0].removeNode() # self.lfp.pop(0) def update_eye(self, t_time): #eye = LineSegs() #eye.setThickness(10.0) #print('last_eye', self.last_eye) group_eye = [] # get eye movements since the last frame while self.last_eye_ts < t_time: try: group_eye.append(self.eye_data.popleft()) self.last_eye_ts = self.eye_ts.pop() except StopIteration: #make the next eye movement something crazy in the future self.last_eye_ts = t_time + 10000 #print('break') taskMgr.remove('self.movie_task') break if group_eye: # plotting the average # have to sum in a loop, because tuples in a list #eye.moveTo(self.last_eye[0], 55, self.last_eye[1]) sum_x = 0 sum_y = 0 for i in group_eye: sum_x += i[0] sum_y += i[1] self.last_eye = [sum_x / len(group_eye), sum_y / len(group_eye)] self.eye_spot.setPos(self.last_eye[0], 55, self.last_eye[1]) self.eye_spot.reparentTo(self.base.pixel2d)
def __init__(self, agent=None, env=None, show_learning=True): ShowBase.__init__(self) ShowBase.movie(self, namePrefix='images/camera1/jmage', duration=60, fps=60, format='jpg', sd=4, source=None) self.agent = agent self.env = env self.bicycle = self.env.env current_state = self.env.reset() current_state = current_state[np.newaxis] self.action = self.agent.action(current_state) self.action = self.action.flatten() self.show_learning = show_learning if self.show_learning: self.theta_counter = 0 self.theta_index = 0 self.elapsed_time = 0 self.omegaText = self.genLabelText("", 1) self.thetaText = self.genLabelText("", 2) self.timeText = self.genLabelText("", 3) self.wheel_roll = 0 self.torque = 0 self.butt_displacement = 0 # Load the environment model. self.environ = self.loader.loadModel("maps/Ground2.egg") ## Reparent the model to render. self.environ.reparentTo(self.render) # Disable the use of the mouse to control the camera. self.disableMouse() # "out-of-body experience"; toggles camera control. self.accept('o', self.oobe) # Add the spinCameraTask procedure to the task manager. self.taskMgr.add(self.followBikeTask, "FollowBikeTask") self.taskMgr.add(self.simulateBicycleTask, "SimulateBicycleTask") self.rear_wheel = self.loader.loadModel("maps/wheel3.egg") self.rear_wheel.reparentTo(self.render) self.rear_wheel.setPos(0, 0, self.bicycle.r) self.frame = self.loader.loadModel("maps/frame.egg") self.frame.reparentTo(self.rear_wheel) self.frame.setColor(1, 0, 0) self.butt = self.loader.loadModel("maps/frame.egg") self.butt.reparentTo(self.frame) self.butt.setColor(1, 0, 0) self.butt.setScale(1, 0.1, 1) self.butt.setZ(1.5 * self.bicycle.r) self.butt.setY(0.3 * self.bicycle.L) # place goal self.goalPost = self.loader.loadModel("maps/fork.egg") self.goalPost.reparentTo(self.render) self.fork = self.loader.loadModel("maps/fork.egg") self.fork.reparentTo(self.frame) self.fork.setColor(0, 0, 1) self.fork.setPos(0, self.bicycle.L, self.bicycle.r) self.front_wheel = self.loader.loadModel("maps/wheel3.egg") self.front_wheel.reparentTo(self.fork) self.front_wheel.setColor(1, 1, 1) self.front_wheel.setPos(0, 0, -self.bicycle.r) self.handlebar = self.loader.loadModel("maps/fork.egg") self.handlebar.reparentTo(self.fork) self.handlebar.setColor(0, 0, 1) self.handlebar.setPos(0, 0, self.bicycle.r) self.handlebar.setHpr(0, 0, 90) self.torqueLeftIndicator = self.loader.loadModel("maps/fork.egg") self.torqueLeftIndicator.reparentTo(self.fork) self.torqueLeftIndicator.setColor(0, 0, 1) self.torqueLeftIndicator.setPos(-self.bicycle.r, 0, self.bicycle.r) self.torqueLeftIndicator.hide() self.torqueRightIndicator = self.loader.loadModel("maps/fork.egg") self.torqueRightIndicator.reparentTo(self.fork) self.torqueRightIndicator.setColor(0, 0, 1) self.torqueRightIndicator.setPos(self.bicycle.r, 0, self.bicycle.r) self.torqueRightIndicator.hide() self.camera.setPos(5, -5, 10)
class AvatarWorld(DirectObject): def __init__(self, datafile, record=True, distance_goal=None): DirectObject.__init__(self) # environ = 'circle' environ = 'original' movie_name = '../movies/frames/avatar/avatar' data = MovieData(datafile) # bring in data that we will use self.avatar_pos = [[j/2 for j in i] for i in data.avatar_pos] self.avatar_pt = data.avatar_pt self.fruit_status = data.fruit_status self.fruit_status_ts = data.fruit_status_ts self.fruit_pos = data.fruit_pos self.fruit_pos_ts = data.fruit_pos_ts self.trial_mark = data.trial_mark self.alpha = data.alpha self.scale_factor = 1 # print 'alpha', self.alpha # toggle to detect when a block of trials is finished self.block_done = False # print 'fruit status', self.fruit_status self.use_alpha = False # convoluted way to see if we are really using invisible fruit for i in self.fruit_status: if i[1] == 'alpha' and float(i[2]) < 1: self.use_alpha = True # print 'true', float(i[2]) # print 'use alpha', self.use_alpha # really should pull this from the config file (distance_goal) # everything is at 1/2 size if distance_goal: self.goal_radius = [i/2 for i in distance_goal] else: # total arbitrary guess self.goal_radius = [3/2, 3/2] # Things that can affect camera: # options resolution resW resH self.base = ShowBase() props = WindowProperties() # props.setSize(600, 600) self.base.win.requestProperties(props) self.drawing_layer = 25 #corner = 600/100 * 5/6 if environ == 'original': border = LineSegs() border.setThickness(2.0) corner = 5.5 # print corner # red border.setColor(1, 0, 0) border.moveTo(corner, 25, corner) border.drawTo(corner, 25, -corner) # purple border.setColor(1, 0, 1) border.moveTo(corner, 25, -corner) border.drawTo(-corner, 25, -corner) # white border.setColor(1, 1, 1) border.moveTo(-corner, 25, -corner) border.drawTo(-corner, 25, corner) # green border.setColor(0, 1, 0) border.moveTo(-corner, 25, corner) border.drawTo(corner, 25, corner) self.base.render.attachNewNode(border.create(True)) imageObject = OnscreenImage(image='textures/lightpost.png', pos=(-0.9, 25, 0.9), scale=(0.06, 1, 0.08), color=(0.9, 0.9, 0.9, 0.8)) imageObject.setTransparency(TransparencyAttrib.MAlpha) imageObject1 = OnscreenImage(image='textures/palm_tree.png', pos=(0.85, 25, 0.9), scale=0.09, color=(0.9, 0.9, 0.9, 0.8)) imageObject1.setTransparency(TransparencyAttrib.MAlpha) imageObject2 = OnscreenImage(image='textures/transamerica_thumb.png', pos=(-0.9, 25, -0.9), scale=0.2, color=(0.9, 0.9, 0.9, 0.8)) imageObject2.setTransparency(TransparencyAttrib.MAlpha) # background color doesn't show up anyway #base.setBackgroundColor(115 / 255, 115 / 255, 115 / 255) else: # circle # needs to be smaller self.scale_factor = 0.7 color = Point3(0.9, 0.9, 0.9) self.make_circle(8 * self.scale_factor, (0, 0, 0), color) last_avt = self.avatar_pos.pop() self.last_avt = [i * self.scale_factor for i in last_avt] #base.cam.setPos(Point3(points[0], points[1], points[2])) #base.cam.setH(self.avatar_h.pop(0)) #self.avatar_ht.pop(0) self.avatar_pt.pop() # get last time stamp (first of list) for avatar to calculate length of movie # add half a second buffer. movie_length = self.avatar_pt[0] + 0.5 print('movie length', movie_length) self.avatar_node = [] self.avatar_color = [1, 1, 1] self.alpha_circle_node = [] self.fruitModel = {} # print('fruit', self.fruit_pos) for k, v in self.fruit_pos.iteritems(): # print('i', i) # print('k', k) # print('v', v) if 'banana' in k: self.fruitModel[k] = self.base.loader.loadModel('models/ball') self.fruitModel[k].setScale(0.5) self.fruitModel[k].setColor(1, 1, 0, 1) elif 'cherry' in k: self.fruitModel[k] = self.base.loader.loadModel('models/ball') self.fruitModel[k].setScale(0.5) self.fruitModel[k].setColor(1, 0, 0, 1) # position = self.fruit_pos[k]['position'].pop(0) # print position heading = v['head'] #print heading # self.fruitModel[k].setPos( # Point3(float(position[0]), float(position[1]), float(position[2]))) self.fruitModel[k].setH(float(heading)) self.fruitModel[k].reparentTo(self.base.render) # assume all fruit stashed to start self.fruitModel[k].stash() if k in data.alpha: # print 'set alpha', data.alpha self.alpha_node_path = self.fruitModel[k] self.alpha_node_path.setTransparency(TransparencyAttrib.MAlpha) if record: self.movie_task = self.base.movie(movie_name, movie_length, 30, 'png', 4) #self.accept("space", base.taskMgr.add, [self.frame_loop, "frame_loop"]) self.gameTask = taskMgr.add(self.frame_loop, "frame_loop") self.gameTask.last = 0 # Task time of the last frame # start the clock at 1 second before the official start so has time to load #self.gameTask.game_time = start_time - 100 def frame_loop(self, task): #dt = task.time - task.last #task.last = task.time if self.avatar_pt: self.update_avt_p(task.time) else: # if we aren't moving the avatar anymore, assume done print 'done' return task.done if self.fruit_pos_ts: self.move_fruit(task.time) if self.fruit_status_ts: self.update_fruit(task.time) #if self.trial_mark and self.trial_mark[-1] <= task.time: # self.move_fruit() return task.cont def update_avt_p(self, t_time): avt = LineSegs() avt.setThickness(5) avt.setColor(self.avatar_color[0], self.avatar_color[1], self.avatar_color[2]) group_avatar = [] while self.avatar_pt[-1] < t_time: group_avatar.append(self.avatar_pos.pop()) # print points self.avatar_pt.pop() if not self.avatar_pt: break # print('positions', group_avatar) if group_avatar: avt.moveTo(self.last_avt[0], self.drawing_layer, self.last_avt[1]) self.last_avt = [i * self.scale_factor for i in group_avatar[0]] for i in group_avatar: # print(i[0], i[1], i[2]) pos = [j * self.scale_factor for j in i] avt.drawTo(pos[0], self.drawing_layer, pos[1]) self.avatar_node.append(self.base.render.attachNewNode(avt.create())) def update_fruit(self, t_time): # print self.avatar_pos[-1] while self.fruit_status_ts[-1] < t_time: current_list = self.fruit_status.pop() # print current_list # print 'alpha', self.alpha # list goes: fruit name, what happens, how much if current_list[1] == 'alpha': self.alpha_node_path.setAlphaScale(float(current_list[2])) # if we are changing banana alpha to something less than 1, turn on circle # print 'alpha', float(current_list[2]) if float(current_list[2]) == 0: # print 'make circle for invisible' self.block_done = True self.make_circle(self.goal_radius[1], self.alpha_node_path.getPos()) self.avatar_color = [0, 1, 1] elif float(current_list[2]) < 1: # print 'make circle for alpha' self.make_circle(self.goal_radius[0], self.alpha_node_path.getPos()) if current_list[1] == 'stash': if current_list[2] == 'True': self.fruitModel[current_list[0]].stash() # want if recall fruit turns off, circle goes away # if another fruit turns off, and the next fruit to # have an event is the alpha fruit, then # circle appears # this is almost certainly problematic for gobananas data # with alpha fruit, maybe # see what is next in line, if next is alpha and current is # recall stashing, # print self.fruit_status[-1] # if stashing the recall fruit, erase the circle, # return avatar line color to normal if current_list[0] in self.alpha: # print 'erase circle' self.erase_circle() self.avatar_color = [1, 1, 1] # this is not true for newer data, but leaving it here for old data: # no good way to tell the difference between an invisible recall fruit # and a solid recall fruit, other than looking at timing. ugh. Brute force. # can't use timing, self.fruit_status_ts[-1] # if we are stashing a cherry, and the next thing to happen is alpha 1 and # the next time stamp is not immediately, than must be invisible. if self.use_alpha: if current_list[0] not in self.alpha: if self.fruit_status[-1][2] == '1': # print 'next alpha?' # print self.fruit_status_ts[-2] - self.fruit_status_ts[-1] if self.fruit_status_ts[-2] - self.fruit_status_ts[-1] > 0.2: print 'should only reach here with old data' self.make_circle(self.goal_radius[1], self.alpha_node_path.getPos()) self.avatar_color = [0, 1, 1] else: # print 'unstash' self.fruitModel[current_list[0]].unstash() # print self.fruitModel[current_list[0]].isStashed() self.fruit_status_ts.pop() if not self.fruit_status_ts: break def move_fruit(self, t_time): # did not reverse, since pain in the ass, and likely not many while self.fruit_pos_ts[0][0] < t_time: # whenever we draw fruit, make the drawing layer closer to the camera, # since otherwise which lines are on top is a bit random self.drawing_layer -= 0.01 #print 'layer', self.drawing_layer ts, fruit = self.fruit_pos_ts.pop(0) # print('current time stamp', ts) # position = [float(i) * self.scale_factor * 0.5 for i in self.fruit_pos[fruit]['position'].pop(0)] # print('move fruit', fruit, position) self.fruitModel[fruit].setPos( Point3(position[0], 25, position[1])) # print 'fruit pos ts', self.fruit_pos_ts # print 'time', t_time if not self.fruit_pos_ts: break def make_circle(self, radius, center, color=None): circle = LineSegs() circle.setThickness(2.0) if not color: circle.setColor(1, 1, 0, 1) else: circle.setColor(color) angle_radians = radians(360) # print alpha_pos for i in range(50): a = angle_radians * i / 49 y = radius * sin(a) x = radius * cos(a) circle.drawTo((x + center[0], self.drawing_layer, y + center[2])) if not color: self.alpha_circle_node.append(self.base.render.attachNewNode(circle.create())) else: self.base.render.attachNewNode(circle.create()) def erase_circle(self): for i in self.alpha_circle_node: i.detachNode() if self.block_done: for i in self.avatar_node: i.detachNode() self.block_done = False