class HUD(DirectObject): def __init__(self): self.winXhalf = base.win.getXSize() / 2 self.winYhalf = base.win.getYSize() / 2 croshairsize = 0.05#17.0 self.crosshair = OnscreenImage( image = os.path.join("..", "data", "crosshair.png"), scale = (croshairsize, 1, croshairsize), #pos = (self.winXhalf - croshairsize/2.0, 0, -self.winYhalf - croshairsize/2.0) pos = (0, 0, 0) ) self.crosshair.setTransparency(1) self.ammo = DirectLabel( scale = 0.15, text = "100/100", pos = (base.a2dLeft + 0.025, 0.0, base.a2dBottom + 0.05), text_align = TextNode.ALeft, frameColor = (0, 0, 0, 0), text_fg = (1,1,1,1), text_shadow = (0, 0, 0, 1), text_shadowOffset = (0.05, 0.05) ) self.ammo.setTransparency(1) self.nowPlaying = DirectLabel( scale = 0.05, text = "Now Playing: Echovolt - Nothing to Fear", pos = (base.a2dLeft + 0.025, 0.0, base.a2dTop - 0.05), text_align = TextNode.ALeft, frameColor = (0, 0, 0, 0), text_fg = (1,1,1,1) ) self.nowPlaying.setTransparency(1) self.accept("window-event", self.recalcAspectRatio) self.hide() def show(self): self.crosshair.show() self.nowPlaying.show() self.ammo.show() def hide(self): self.crosshair.hide() self.nowPlaying.hide() self.ammo.hide() def updateAmmo(self, maxAmmo, ammo): self.ammo["text"] = "%02d/%02d" % (maxAmmo, ammo) def recalcAspectRatio(self, window): self.ammo.setPos(base.a2dLeft + 0.025, 0.0, base.a2dBottom + 0.05) self.ammo.setPos(base.a2dLeft + 0.025, 0.0, base.a2dTop - 0.05)
class TextDisplay(DirectObject): DEFAULT_COLOR = (1, 0, 0, 1) def __init__(self, font, parent=aspect2d): DirectObject.__init__(self) self.text = DirectLabel(parent=parent, relief=None, text='', text_align=TextNode.A_center, text_pos=(0, -0.35), text_scale=0.15, text_wordwrap=15, text_fg=self.DEFAULT_COLOR, textMayChange=1, state=DGG.DISABLED, sortOrder=80) self.FONT = font def destroy(self): self.ignoreAll() taskMgr.remove('clearDisplayedText') if self.text: self.text.destroy() self.text = None def displayText(self, text, color=None, timeout=5): if not color: color = self.DEFAULT_COLOR self.text['text'] = text self.text.show() self.text['text_font'] = self.FONT self.text['text_scale'] = 0.15 self.text['text_pos'] = (0, -0.35) self.text['text_fg'] = color taskMgr.doMethodLater(timeout, self.clearText, 'clearDisplayedText') def clearText(self, task=None): self.text['text'] = '' self.text['text_fg'] = self.DEFAULT_COLOR self.text.hide() if task: return task.done
class InputPageGui(ThanksPageGui): def __init__(self, mdt, menu_args, joystick, keys): self._joypad_cb = None self.joystick = joystick self.keys = keys ThanksPageGui.__init__(self, mdt, menu_args) def bld_page(self): menu_args = self.menu_args self.pagewidgets = [] self.buttons = [] joypad_lab = DirectLabel(text=_('Use the joypad when present'), pos=(-.1, 1, .8), text_align=TextNode.ARight, **menu_args.label_args) PageGui.transl_text(joypad_lab, 'Use the joypad when present', _('Use the joypad when present')) self._joypad_cb = DirectCheckButton( pos=(.09, 1, .82), text='', indicatorValue=self.joystick, indicator_frameColor=menu_args.text_fg, **menu_args.checkbtn_args) if not has_pygame(): self._joypad_cb['state'] = DISABLED def add_lab(text, pos_z): self.pagewidgets += [ DirectLabel(text=text, pos=(-.1, 1, pos_z), text_align=TextNode.ARight, **menu_args.label_args) ] def add_btn(text, pos_z): btn = DirectButton(pos=(.46, 1, pos_z), text=text, command=self.start_rec, **menu_args.btn_args) btn['extraArgs'] = [btn] self.pagewidgets += [btn] self.buttons += [btn] buttons_data = [(_('Accelerate'), 'forward', .6), (_('Brake/Reverse'), 'rear', .4), (_('Left'), 'left', .2), (_('Right'), 'right', 0), (_('Weapon'), 'button', -.2), (_('Respawn'), 'respawn', -.4)] for btn_data in buttons_data: add_lab(btn_data[0], btn_data[2]) add_btn(self.keys[btn_data[1]], btn_data[2]) l_a = menu_args.label_args.copy() l_a['scale'] = .065 self.hint_lab = DirectLabel(text=_('Press the key to record it'), pos=(0, 1, -.6), **l_a) self.hint_lab.hide() self.pagewidgets += [joypad_lab, self._joypad_cb, self.hint_lab] map(self.add_widget, self.pagewidgets) ThanksPageGui.bld_page(self) def start_rec(self, btn): numbers = [str(n) for n in range(10)] self.keys = list(ascii_lowercase) + numbers + [ 'backspace', 'insert', 'home', 'page_up', 'num_lock', 'tab', 'delete', 'end', 'page_down', 'caps_lock', 'enter', 'arrow_left', 'arrow_up', 'arrow_down', 'arrow_right', 'lshift', 'rshift', 'lcontrol', 'lalt', 'space', 'ralt', 'rcontrol' ] self.hint_lab.show() acc = lambda key: self.mdt.event.accept(key, self.rec, [btn, key]) map(acc, self.keys) def rec(self, btn, val): btn['text'] = val self.hint_lab.hide() map(self.mdt.event.ignore, self.keys)
class MatchMsgFrm(GameObject): def __init__(self, menu_args): GameObject.__init__(self) self.eng.log('created match message form') self.chat = None self.msg_frm = DirectFrame(frameSize=(-.02, 2.5, 0, 1.22), frameColor=(.2, .2, .2, .5), pos=(.04, 1, -1.69), parent=base.a2dTopLeft) t_a = menu_args.text_args t_a['scale'] = .05 t_a['fg'] = menu_args.text_normal self.dst_txt = OnscreenText(text='', pos=(0, 1.16), parent=self.msg_frm, align=TextNode.A_left, **t_a) self.ent = Entry(scale=.04, pos=(0, 1, .03), entryFont=menu_args.font, width=62, frameColor=menu_args.btn_color, parent=self.msg_frm, initialText=_('write here your message'), command=self.on_typed_msg, focusInCommand=self.on_focus, focusInExtraArgs=['in'], focusOutCommand=self.on_focus, focusOutExtraArgs=['out'], text_fg=menu_args.text_active) self.ent['state'] = DISABLED self.txt_frm = DirectScrolledFrame( frameSize=(-.02, 2.46, -.02, 1.02), canvasSize=(-.02, 2.42, -.02, 1.02), scrollBarWidth=.036, verticalScroll_relief=FLAT, verticalScroll_frameColor=(.2, .2, .2, .4), verticalScroll_thumb_relief=FLAT, verticalScroll_thumb_frameColor=(.8, .8, .8, .6), verticalScroll_incButton_relief=FLAT, verticalScroll_incButton_frameColor=(.8, .8, .8, .6), verticalScroll_decButton_relief=FLAT, verticalScroll_decButton_frameColor=(.8, .8, .8, .6), horizontalScroll_relief=FLAT, frameColor=(1, 1, 1, .0), pos=(.02, 1, .11), parent=self.msg_frm) t_a['scale'] = .046 self.msg_txt = OnscreenText(text='', pos=(0, .24), parent=self.txt_frm.getCanvas(), align=TextNode.A_left, wordwrap=52, **t_a) lab_args = menu_args.label_args lab_args['scale'] = .046 lab_args['text_fg'] = menu_args.text_normal self.lab_frm = Btn(frameSize=(-.02, 2.5, -.01, .05), frameColor=(1, 1, 1, 0), pos=(0, 1, 1.15), parent=self.msg_frm) self.lab_frm.bind(ENTER, self.on_enter) self.lab_frm.bind(EXIT, self.on_exit) self.tooltip = DirectLabel(text='', pos=(2.4, 1, -.06), parent=self.lab_frm, text_wordwrap=50, text_bg=(.2, .2, .2, .8), text_align=TextNode.A_right, **lab_args) self.tooltip.set_bin('gui-popup', 10) self.tooltip.hide() def on_enter(self, pos): self.tooltip.show() def on_exit(self, pos): self.tooltip.hide() def add_msg_txt(self, msg): self.msg_txt['text'] += ('\n' if self.msg_txt['text'] else '') + msg txt_height = self.msg_txt.textNode.getUpperLeft3d()[2] - \ self.msg_txt.textNode.getLowerRight3d()[2] self.txt_frm['canvasSize'] = (-.02, .72, .28 - txt_height, .28) def set_title(self, title): ttitle = self.trunc(title, 160) fix_name = lambda name: name if '@' not in name else name.split('@')[ 0] + '\1smaller\1@' + name.split('@')[1] + '\2' if title: if ',' in ttitle: is_muc = True ttitle = ttitle names = ttitle.split(',') names = [name.strip() for name in names] names = [fix_name(name) for name in names] ttitle = ', '.join(names) else: ttitle = fix_name(ttitle) self.dst_txt['text'] = ttitle self.tooltip['text'] = title @staticmethod def trunc(name, lgt): if len(name) > lgt: return name[:lgt] + '...' return name def on_typed_msg(self, val): #self.add_msg_txt('\1italic\1' + _('you') + '\2: ' + val) self.ent.set('') self.eng.xmpp.client.send_message( mfrom=self.eng.xmpp.client.boundjid.full, mto=self.chat.dst, mtype='groupchat', mbody=val) self.ent['focus'] = 1 def on_groupchat_msg(self, msg): src = str(JID(msg['mucnick'])) src = src.split('@')[0] + '\1smaller\1@' + src.split('@')[1] + '\2' self.eng.log('received groupchat message from %s in the chat %s' % (msg['mucnick'], JID(msg['from']).bare)) str_msg = '\1italic\1' + src + '\2: ' + str(msg['body']) if not self.chat: self.chat = MUC(str(JID(msg['from']).bare)) self.chat.messages += [str_msg] if self.dst_txt['text'] == '': self.set_chat(self.chat) elif self.chat.dst == str(JID(msg['from']).bare): self.add_msg_txt(str_msg) def on_presence_available_room(self, msg): room = str(JID(msg['muc']['room']).bare) nick = str(msg['muc']['nick']) self.eng.log('user %s has logged in the chat %s' % (nick, room)) self.chat.users += [nick] self.set_title(self.chat.title) def on_presence_unavailable_room(self, msg): room = str(JID(msg['muc']['room']).bare) nick = str(msg['muc']['nick']) self.eng.log('user %s has left the chat %s' % (nick, room)) self.chat.users.remove(nick) self.set_title(self.chat.title) def add_groupchat(self, room, usr): self.set_title(usr) if not self.chat: self.chat = MUC(room) self.set_chat(self.chat) def set_chat(self, chat): self.set_title(chat.title) self.msg_txt['text'] = '\n'.join(chat.messages) txt_height = self.msg_txt.textNode.getUpperLeft3d()[2] - \ self.msg_txt.textNode.getLowerRight3d()[2] self.txt_frm['canvasSize'] = (-.02, .72, .28 - txt_height, .28) self.ent['state'] = NORMAL def on_focus(self, val): if val == 'in' and self.ent.get() == _('write here your message'): self.ent.set('') self.notify('on_match_msg_focus', val) def destroy(self): self.eng.log('message form destroyed') self.msg_frm.destroy() GameObject.destroy(self)
class MessageFrm(GameObject): def __init__(self, menu_args): GameObject.__init__(self) self.eng.log('created message form') self.chats = [] self.curr_chat = None self.curr_match_room = None self.msg_frm = DirectFrame(frameSize=(-.02, .8, 0, .45), frameColor=(.2, .2, .2, .5), pos=(-.82, 1, .02), parent=base.a2dBottomRight) self.presences_sent = [] self.menu_args = menu_args t_a = menu_args.text_args t_a['scale'] = .05 t_a['fg'] = menu_args.text_normal self.dst_txt = OnscreenText(text='', pos=(0, .4), parent=self.msg_frm, align=TextNode.A_left, **t_a) self.arrow_btn = ImgBtn(parent=self.msg_frm, scale=.024, pos=(.7, 1, .42), frameColor=(1, 1, 1, 1), frameTexture='assets/images/gui/arrow.txo', command=self.on_arrow, **menu_args.imgbtn_args) self.arrow_btn.disable() self.close_btn = ImgBtn(parent=self.msg_frm, scale=.024, pos=(.76, 1, .42), frameColor=(1, 1, 1, 1), frameTexture='assets/images/gui/close.txo', command=self.on_close, **menu_args.imgbtn_args) self.close_btn.disable() self.ent = Entry(scale=.04, pos=(0, 1, .03), entryFont=menu_args.font, width=19.5, frameColor=menu_args.btn_color, parent=self.msg_frm, initialText=_('write here your message'), command=self.on_typed_msg, focusInCommand=self.on_focus, focusInExtraArgs=['in'], focusOutCommand=self.on_focus, focusOutExtraArgs=['out'], text_fg=menu_args.text_active) self.ent['state'] = DISABLED self.txt_frm = DirectScrolledFrame( frameSize=(-.02, .76, -.02, .28), canvasSize=(-.02, .72, -.02, .28), scrollBarWidth=.036, verticalScroll_relief=FLAT, verticalScroll_frameColor=(.2, .2, .2, .4), verticalScroll_thumb_relief=FLAT, verticalScroll_thumb_frameColor=(.8, .8, .8, .6), verticalScroll_incButton_relief=FLAT, verticalScroll_incButton_frameColor=(.8, .8, .8, .6), verticalScroll_decButton_relief=FLAT, verticalScroll_decButton_frameColor=(.8, .8, .8, .6), horizontalScroll_relief=FLAT, frameColor=(1, 1, 1, 0), pos=(.02, 1, .11), parent=self.msg_frm) t_a['scale'] = .046 self.msg_txt = OnscreenText(text='', pos=(0, .24), parent=self.txt_frm.getCanvas(), align=TextNode.A_left, wordwrap=14, **t_a) lab_args = menu_args.label_args lab_args['scale'] = .046 lab_args['text_fg'] = menu_args.text_normal self.lab_frm = Btn(frameSize=(-.02, .64, -.01, .05), frameColor=(1, 1, 1, 0), pos=(0, 1, .4), parent=self.msg_frm) self.lab_frm.bind(ENTER, self.on_enter) self.lab_frm.bind(EXIT, self.on_exit) self.tooltip = DirectLabel(text='', pos=(.78, 1, -.06), parent=self.lab_frm, text_wordwrap=16, text_bg=(.2, .2, .2, .8), text_align=TextNode.A_right, **lab_args) self.tooltip.set_bin('gui-popup', 10) self.tooltip.hide() def on_enter(self, pos): self.tooltip.show() def on_exit(self, pos): self.tooltip.hide() def show(self): self.msg_frm.show() def hide(self): self.msg_frm.hide() def add_msg_txt(self, msg): self.msg_txt['text'] += ('\n' if self.msg_txt['text'] else '') + msg txt_height = self.msg_txt.textNode.getUpperLeft3d()[2] - \ self.msg_txt.textNode.getLowerRight3d()[2] self.txt_frm['canvasSize'] = (-.02, .72, .28 - txt_height, .28) def set_title(self, title): ttitle = self.trunc(title, 32) fix_name = lambda name: name if '@' not in name else name.split('@')[ 0] + '\1smaller\1@' + name.split('@')[1] + '\2' if title: if ',' in ttitle: is_muc = True ttitle = ttitle names = ttitle.split(',') names = [name.strip() for name in names] names = [fix_name(name) for name in names] ttitle = ', '.join(names) else: ttitle = fix_name(ttitle) self.dst_txt['text'] = ttitle self.tooltip['text'] = title @staticmethod def trunc(name, lgt): if len(name) > lgt: return name[:lgt] + '...' return name def set_chat(self, chat): self.curr_chat = chat self.set_title(chat.title) self.msg_txt['text'] = '\n'.join(chat.messages) txt_height = self.msg_txt.textNode.getUpperLeft3d()[2] - \ self.msg_txt.textNode.getLowerRight3d()[2] self.txt_frm['canvasSize'] = (-.02, .72, .28 - txt_height, .28) if not self.chats: self.close_btn.disable() self.ent['state'] = DISABLED elif len(self.chats) == 1: self.close_btn.enable() self.ent['state'] = NORMAL self.arrow_btn.disable() else: self.close_btn.enable() self.ent['state'] = NORMAL self.arrow_btn.enable() if all(_chat.read for _chat in self.chats): self.arrow_btn['frameTexture'] = 'assets/images/gui/arrow.txo' else: self.arrow_btn['frameTexture'] = 'assets/images/gui/message.txo' def on_arrow(self): chat_idx = self.chats.index(self.curr_chat) next_idx = (chat_idx + 1) % len(self.chats) chat = self.chats[next_idx] self.set_title(chat.title) chat.read = True self.set_chat(chat) @property def open_chats(self): return [chat for chat in self.chats if not chat.closed] def on_close(self): if self.curr_chat not in self.open_chats: return curr_idx = self.open_chats.index(self.curr_chat) #self.chats.remove(self.curr_chat) self.curr_chat.closed = True if self.open_chats: self.set_chat(self.open_chats[curr_idx - 1]) else: self.set_chat(Chat('')) self.notify('on_close_all_chats') def on_typed_msg(self, val): self.add_msg_txt('\1italic\1' + _('you') + '\2: ' + val) self.ent.set('') if self.curr_chat.dst not in self.presences_sent and \ not str(self.curr_chat.dst).startswith('yorg'): self.eng.xmpp.client.send_presence( pfrom=self.eng.xmpp.client.boundjid.full, pto=self.curr_chat.dst) self.presences_sent += [self.curr_chat.dst] if str(self.curr_chat.dst).startswith('yorg'): self.eng.xmpp.client.send_message( mfrom=self.eng.xmpp.client.boundjid.full, mto=self.curr_chat.dst, mtype='groupchat', mbody=val) else: self.eng.xmpp.client.send_message( mfrom=self.eng.xmpp.client.boundjid.full, mto=self.curr_chat.dst, msubject='chat', mbody=val) msg = '\1italic\1' + _('you') + '\2: ' + val self.curr_chat.messages += [msg] self.ent['focus'] = 1 def on_msg(self, msg): src = str(JID(msg['from']).bare) src = src.split('@')[0] + '\1smaller\1@' + src.split('@')[1] + '\2' str_msg = '\1italic\1' + src + '\2: ' + str(msg['body']) chat = self.__find_chat(msg['from']) if not chat: chat = Chat(msg['from']) self.chats += [chat] chat.messages += [str_msg] if self.dst_txt['text'] == '': self.set_chat(chat) elif JID(self.curr_chat.dst).bare == JID(msg['from']).bare: self.add_msg_txt(str_msg) else: chat.read = False chat.closed = False self.arrow_btn['frameTexture'] = 'assets/images/gui/message.txo' def on_groupchat_msg(self, msg): if str(JID(msg['from']).bare) == self.curr_match_room: if self.match_msg_frm: # we're still in the room page self.match_msg_frm.on_groupchat_msg(msg) src = str(JID(msg['mucnick'])) src = src.split('@')[0] + '\1smaller\1@' + src.split('@')[1] + '\2' self.eng.log('received groupchat message from %s in the chat %s' % (msg['mucnick'], JID(msg['from']).bare)) str_msg = '\1italic\1' + src + '\2: ' + str(msg['body']) chat = self.curr_chat if not chat: chat = MUC(str(JID(msg['from']).bare)) self.chats += [chat] chat.messages += [str_msg] if self.dst_txt['text'] == '': self.set_chat(chat) elif self.curr_chat.dst == str(JID(msg['from']).bare): self.add_msg_txt(str_msg) else: chat.read = False chat.closed = False self.arrow_btn['frameTexture'] = 'assets/images/gui/message.txo' def on_presence_available_room(self, msg): if str(JID(msg['from']).bare) == self.curr_match_room: self.match_msg_frm.on_presence_available_room(msg) room = str(JID(msg['muc']['room']).bare) nick = str(msg['muc']['nick']) self.eng.log('user %s has logged in the chat %s' % (nick, room)) chat = self.__find_chat(room) chat.users += [nick] if str(JID(msg['from']).bare) != self.curr_match_room: if self.curr_chat.dst == room: self.set_title(chat.title) def on_presence_unavailable_room(self, msg): if self.match_msg_frm and str(JID( msg['from']).bare) == self.curr_match_room: self.match_msg_frm.on_presence_unavailable_room(msg) return room = str(JID(msg['muc']['room']).bare) nick = str(msg['muc']['nick']) self.eng.log('user %s has left the chat %s' % (nick, room)) chat = self.__find_chat(room) if nick == self.eng.xmpp.client.boundjid.bare: self.on_close() else: chat.users.remove(nick) if self.curr_chat.dst == room: self.set_title(chat.title) def __find_chat(self, dst): chats = [chat for chat in self.chats if chat.dst == dst] if chats: return chats[0] def add_chat(self, usr): self.set_title(JID(usr).bare) chat = self.__find_chat(usr) if not chat: chat = Chat(usr) self.chats += [chat] self.set_chat(chat) self.ent['focus'] = 1 def add_groupchat(self, room, usr): self.set_title(usr) chat = self.__find_chat(room) if not chat: chat = MUC(room) self.chats += [chat] chat.users += [usr] self.set_chat(chat) self.add_match_chat(room, usr) def remove_groupchat(self): self.match_msg_frm.detach(self.on_match_msg_focus) self.match_msg_frm = self.match_msg_frm.destroy() def on_focus(self, val): if val and self.ent.get() == _('write here your message'): self.ent.set('') self.notify('on_msg_focus', val) def on_match_msg_focus(self, val): self.notify('on_msg_focus', val) def on_room_back(self): self.curr_match_room = None self.match_msg_frm.destroy() def add_match_chat(self, room, usr): if self.curr_match_room: return self.curr_match_room = room self.match_msg_frm = MatchMsgFrm(self.menu_args) self.match_msg_frm.attach(self.on_match_msg_focus) self.match_msg_frm.add_groupchat(room, usr)
class GUI: def __init__(self, rootParent=None): self.background = loader.load_model("assets/models/highscoreBack.bam") self.background.reparent_to(render) x = -0.8 y = 0.8 xShift = 0.15 yShift = -0.15 lb = base.leaderboard.leaderboard() self.lbl1 = DirectLabel( frameColor=(0.8, 0.8, 0.8, 0.0), frameSize=(0.03750000149011612, 3.3125, -0.11250001192092896, 0.699999988079071), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(x, 0, y), scale=LVecBase3f(0.1, 0.1, 0.1), text='1 - {} : {}'.format(lb[0][0], lb[0][1]), text_align=TextNode.A_left, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(1, 1, 1, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=rootParent, ) self.lbl1.setTransparency(0) x += xShift y += yShift self.lbl2 = DirectLabel( frameColor=(0.8, 0.8, 0.8, 0.0), frameSize=(0.03750000149011612, 3.3125, -0.11250001192092896, 0.699999988079071), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(x, 0, y), scale=LVecBase3f(0.1, 0.1, 0.1), text='2 - {} : {}'.format(lb[1][0], lb[1][1]), text_align=TextNode.A_left, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(1, 1, 1, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=rootParent, ) self.lbl2.setTransparency(0) x += xShift y += yShift self.lbl3 = DirectLabel( frameColor=(0.8, 0.8, 0.8, 0.0), frameSize=(0.03750000149011612, 3.3125, -0.11250001192092896, 0.699999988079071), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(x, 0, y), scale=LVecBase3f(0.1, 0.1, 0.1), text='3 - {} : {}'.format(lb[2][0], lb[2][1]), text_align=TextNode.A_left, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(1, 1, 1, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=rootParent, ) self.lbl3.setTransparency(0) x += xShift y += yShift self.lbl4 = DirectLabel( frameColor=(0.8, 0.8, 0.8, 0.0), frameSize=(0.03750000149011612, 3.3125, -0.11250001192092896, 0.699999988079071), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(x, 0, y), scale=LVecBase3f(0.1, 0.1, 0.1), text='4 - {} : {}'.format(lb[3][0], lb[3][1]), text_align=TextNode.A_left, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(1, 1, 1, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=rootParent, ) self.lbl4.setTransparency(0) x += xShift y += yShift self.lbl5 = DirectLabel( frameColor=(0.8, 0.8, 0.8, 0.0), frameSize=(0.03750000149011612, 3.3125, -0.11250001192092896, 0.699999988079071), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(x, 0, y), scale=LVecBase3f(0.1, 0.1, 0.1), text='5 - {} : {}'.format(lb[4][0], lb[4][1]), text_align=TextNode.A_left, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(1, 1, 1, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=rootParent, ) self.lbl5.setTransparency(0) x += xShift y += yShift self.lbl6 = DirectLabel( frameColor=(0.8, 0.8, 0.8, 0.0), frameSize=(0.03750000149011612, 3.3125, -0.11250001192092896, 0.699999988079071), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(x, 0, y), scale=LVecBase3f(0.1, 0.1, 0.1), text='6 - {} : {}'.format(lb[5][0], lb[5][1]), text_align=TextNode.A_left, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(1, 1, 1, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=rootParent, ) self.lbl6.setTransparency(0) x += xShift y += yShift self.lbl7 = DirectLabel( frameColor=(0.8, 0.8, 0.8, 0.0), frameSize=(0.03750000149011612, 3.3125, -0.11250001192092896, 0.699999988079071), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(x, 0, y), scale=LVecBase3f(0.1, 0.1, 0.1), text='7 - {} : {}'.format(lb[6][0], lb[6][1]), text_align=TextNode.A_left, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(1, 1, 1, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=rootParent, ) self.lbl7.setTransparency(0) x += xShift y += yShift self.lbl8 = DirectLabel( frameColor=(0.8, 0.8, 0.8, 0.0), frameSize=(0.03750000149011612, 3.3125, -0.11250001192092896, 0.699999988079071), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(x, 0, y), scale=LVecBase3f(0.1, 0.1, 0.1), text='8 - {} : {}'.format(lb[7][0], lb[7][1]), text_align=TextNode.A_left, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(1, 1, 1, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=rootParent, ) self.lbl8.setTransparency(0) x += xShift y += yShift self.lbl9 = DirectLabel( frameColor=(0.8, 0.8, 0.8, 0.0), frameSize=(0.03750000149011612, 3.3125, -0.11250001192092896, 0.699999988079071), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(x, 0, y), scale=LVecBase3f(0.1, 0.1, 0.1), text='9 - {} : {}'.format(lb[8][0], lb[8][1]), text_align=TextNode.A_left, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(1, 1, 1, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=rootParent, ) self.lbl9.setTransparency(0) x += xShift y += yShift self.lbl10 = DirectLabel( frameColor=(0.8, 0.8, 0.8, 0.0), frameSize=(0.03750000149011612, 3.3125, -0.11250001192092896, 0.699999988079071), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(x, 0, y), scale=LVecBase3f(0.1, 0.1, 0.1), text='10 - {} : {}'.format(lb[9][0], lb[9][1]), text_align=TextNode.A_left, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(1, 1, 1, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=rootParent, ) self.lbl10.setTransparency(0) credits = ''' hendrik-jan - Lead design & Audio tizilogic - Procedural Generation fireclaw - Graphics rdb - Fireworks ''' self.credits = DirectLabel( frameColor=(0.8, 0.8, 0.8, 0.0), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(0, 0, 0), scale=LVecBase3f(0.1, 0.1, 0.1), text=credits, text_align=0, #TextNode.A_left, text_scale=(0.5, 0.5), text_pos=(-4, 4), text_fg=LVecBase4f(1, 1, 1, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=rootParent, ) self.credits.reparent_to(base.a2dBottomLeft) self.wait = 0.3 self.task = base.task_mgr.add(self.update) def update(self, task): if self.wait < 0: context = base.device_listener.read_context('player') if context['move'] or context['accelerate'] or context[ "decelerate"]: base.messenger.send("do_back") else: self.wait -= globalClock.get_dt() return task.cont def show(self): self.lbl1.show() self.lbl2.show() self.lbl3.show() self.lbl4.show() self.lbl5.show() self.lbl6.show() self.lbl7.show() self.lbl8.show() self.lbl9.show() self.lbl10.show() def hide(self): self.lbl1.hide() self.lbl2.hide() self.lbl3.hide() self.lbl4.hide() self.lbl5.hide() self.lbl6.hide() self.lbl7.hide() self.lbl8.hide() self.lbl9.hide() self.lbl10.hide() def destroy(self): self.task.remove() self.credits.destroy() self.background.detach_node() self.lbl1.destroy() self.lbl2.destroy() self.lbl3.destroy() self.lbl4.destroy() self.lbl5.destroy() self.lbl6.destroy() self.lbl7.destroy() self.lbl8.destroy() self.lbl9.destroy() self.lbl10.destroy()
class HUD(): def __init__(self): self.canPlantLabel = DirectLabel( frameColor=(0, 0, 0, 0.25), text_fg=(1, 1, 1, 1), scale=0.15, pos=(0, 0, 0.25), pad=(0.2,0.2), text=_("Plant Seed")) self.canPlantLabel.setTransparency(True) self.canPlantLabel.reparentTo(base.a2dBottomCenter) self.canPlantLabel.hide() self.speekLabel = DirectLabel( frameColor=(0, 0, 0, 0.25), text_fg=(1, 1, 1, 1), scale=0.15, pos=(0, 0, 0.5), pad=(0.2,0.2), text="...") self.speekLabel.reparentTo(render) self.speekLabel.hide() self.speekLabel.setTransparency(True) self.speekLabel.setEffect(BillboardEffect.makePointEye()) self.speekLabel.setBin("fixed", 11) self.speekLabel.setDepthWrite(False) self.storyText = DirectLabel( frameColor=(0, 0, 0, 0.25), text_fg=(1, 1, 1, 1), scale=0.08, pos=(0, 0, 0.25), pad=(0.2,0.2), text="Story text") self.storyText.setTransparency(True) self.storyText.reparentTo(base.a2dBottomCenter) self.storyText.hide() self.points = DirectLabel( frameColor=(0, 0, 0, 0.25), text_fg=(1, 1, 1, 1), scale=0.075, pos=(0.05, 0, -0.1), pad=(0.2,0.2), text_align=TextNode.ALeft, text=_("Points: %d")%0) self.points.setTransparency(True) self.points.reparentTo(base.a2dTopLeft) self.playerWater = DirectLabel( frameColor=(0, 0, 0, 0.25), text_fg=(1, 1, 1, 1), scale=0.075, pos=(0.05, 0, -0.2), pad=(0.2,0.2), text_align=TextNode.ALeft, text=_("Remaining Water: %d")%100) self.playerWater.setTransparency(True) self.playerWater.reparentTo(base.a2dTopLeft) self.helpInfo = DirectLabel( frameColor=(0, 0, 0, 0.25), text_fg=(1, 1, 1, 1), scale=0.075, pos=(-0.05, 0, -0.1), pad=(0.2,0.2), text_align=TextNode.ARight, text=_("F1 - show help")) self.helpInfo.setTransparency(True) self.helpInfo.reparentTo(base.a2dTopRight) self.hide() def show(self): self.points.show() self.playerWater.show() self.helpInfo.show() def hide(self): self.points.hide() self.playerWater.hide() self.helpInfo.hide() def hideAll(self): self.canPlantLabel.hide() self.speekLabel.hide() self.points.hide() self.playerWater.hide() self.helpInfo.hide() def showStory(self): self.storyText.show() def hideStory(self): self.storyText.hide() def cleanup(self): self.hideAll() self.canPlantLabel.destroy() self.speekLabel.destroy() self.points.destroy() self.playerWater.destroy() self.helpInfo.destroy() def showCanPlant(self): self.canPlantLabel.show() def hideCanPlant(self): self.canPlantLabel.hide() def setPoints(self, points): self.points["text"] = _("Points: %d")%points self.points.resetFrameSize() def setWater(self, water): self.playerWater["text"] = _("Remaining Water: %d")%water self.playerWater.resetFrameSize() def setStory(self, storytext): self.storyText["text"] = storytext self.storyText.resetFrameSize() def showSpeekText(self, text, newPos): self.speekLabel.setPos(newPos) self.speekLabel["text"] = text self.speekLabel.resetFrameSize() self.speekLabel.show() def hideSpeekText(self): self.speekLabel.hide()
class Vehicle: """A steerable point mass with various steering behaviors.""" # FIXME: One fix that is needed is that wanderSide and wanderUp should be # reset whenever a character switches back to the wander behaviour. This # might prevent wandering characters from 'hugging' obstacles and # containers when wandering is combined with obstacle avoidance and/or # containment. What happens is that the characters wanders into the # obstacle, avoidance takes over and steers the character away from it, # then when wandering gets control again it picks up where it left off -- # steering toward the obstacle. # # So make Vehicle a state-machine, with the state being the currently # active steering behaviour, so that there can be transition-in and # transition-out functions for steering behaviours? def __init__(self, pos=None, mass=1, maxforce=0.1, maxspeed=1, radius=1, avoidVehicles=True, avoidObstacles=True, container=None): """Initialise the vehicle.""" self.mass = mass # mass = 1 means that acceleration = force self.maxforce = maxforce self.maxspeed = maxspeed self.radius = radius self.avoidVehicles = avoidVehicles # Avoid colliding with other Vehicles self.avoidObstacles = avoidObstacles # Avoid colliding with obstacles if pos is None: pos = Point3(0, 0, 0) # The Vehicle controls a primary NodePath to which other NodePath's for # CollisionSolids are parented. Other nodes, such as animated Actors, # can be attached to this NodePath by user classes. self.prime = NodePath('Vehicle primary NodePath') self.prime.reparentTo(render) self.prime.setPos(pos) # If the Vehicle finds itself outside of its container it will turn # back toward the container. The vehicle also stays within the global # container at all times. The idea is that Vehicle.container can be # used to restrict one particular vehicle to a space smaller than the # global container. self.container = container self._pos = SteerVec(pos.getX(), pos.getY()) # 2D pos for steering # calculations self._velocity = SteerVec(0, 0) self._steeringforce = SteerVec(0, 0) self._steeringbehavior = [] # Some steering behaviors make use of self._target, which can be # another Vehicle or a point in 2-space (SteerVec), or it might be None # indicating that no target is currently in use. self._target = None # Initialise the Vehicle's CollisionRay which is used with a # CollisionHandlerFloor to keep the Vehicle on the ground. self.raynp = self.prime.attachNewNode(CollisionNode('colNode')) self.raynp.node().addSolid(CollisionRay(0, 0, 3, 0, 0, -1)) self.floorhandler = CollisionHandlerFloor() self.floorhandler.addCollider(self.raynp, self.prime) cTrav.addCollider(self.raynp, self.floorhandler) # Uncomment this line to show the CollisionRay: #self.raynp.show() # We only want our CollisionRay to collide with the collision # geometry of the terrain only, se we set a mask here. self.raynp.node().setFromCollideMask(floorMASK) self.raynp.node().setIntoCollideMask(offMASK) # Initialise CollisionTube for detecting oncoming obstacle collisions. x, y, z = self.prime.getX(), self.prime.getY(), self.prime.getZ( ) + 3 #FIXME: Don't hardcode how high the tube goes, add height parameter to __init__ for both tube and sphere vx, vy = self._velocity.getX(), self._velocity.getY() r = self.radius f = self.prime.getNetTransform().getMat().getRow3(1) s = 10 self.tube = CollisionTube(x, y, z, x + f.getX() * s, y + f.getY() * s, z, self.radius) self.tubenp = self.prime.attachNewNode(CollisionNode('colNode')) self.tubenp.node().addSolid(self.tube) # The tube should only collide with obstacles (and is an 'into' object) self.tubenp.node().setFromCollideMask(offMASK) self.tubenp.node().setIntoCollideMask(obstacleMASK) # Uncomment this line to show the CollisionTube #self.tubenp.show() # CollisionSphere for detecting when we've actuallyt collided with # something. self.sphere = CollisionSphere(x, y, z, self.radius) self.spherenp = self.prime.attachNewNode(CollisionNode('cnode')) self.spherenp.node().addSolid(self.sphere) # Only collide with the CollisionSphere's of other vehicles. self.spherenp.node().setFromCollideMask( obstacleMASK ) # So the spheres of vehicles will collide with eachother self.spherenp.node().setIntoCollideMask( obstacleMASK) # So obstacles will collide into spheres of vehicles cTrav.addCollider(self.spherenp, collisionHandler) # Uncomment this line to show the CollisionSphere #self.spherenp.show() # Add a task for this Vehicle to the global task manager. self._prevtime = 0 self.stepTask = taskMgr.add(self._step, "Vehicle step task") # Add the Vehicle to the global list of Vehicles vehicles.append(self) # Initialise the DirectLabel used when annotating the Vehicle # FIXME: Needs to be destroyed in self.destroy self.text = "no steering" self.label = DirectLabel(parent=self.prime, pos=(4, 4, 4), text=self.text, text_wordwrap=10, relief=None, text_scale=(1.5, 1.5), text_frame=(0, 0, 0, 1), text_bg=(1, 1, 1, 1)) self.label.component('text0').textNode.setCardDecal(1) self.label.setBillboardAxis() self.label.hide() self.label.setLightOff(1) # A second label for speaking ('Ouch!', 'Sorry!' etc.) self.callout = DirectLabel(parent=self.prime, pos=(4, 4, 4), text='', text_wordwrap=10, relief=None, text_scale=(1.5, 1.5), text_frame=(0, 0, 0, 1), text_bg=(1, 1, 1, 1)) self.callout.component('text0').textNode.setCardDecal(1) self.callout.setBillboardAxis() self.callout.hide() self.callout.setLightOff(1) def destroy(self): """Prepare this Vehicle to be garbage-collected by Python: Remove all of the Vehicle's nodes from the scene graph, remove its CollisionSolids from the global CollisionTraverser, clear its CollisionHandler, remove tasks After executing this method, any remaining references to the Vehicle object can be destroyed by the user module, and the Vehicle will be garbage-collected by Python. """ cTrav.removeCollider(self.raynp) cTrav.removeCollider(self.spherenp) self.floorhandler.clearColliders() self.floorhandler = None self.prime.removeNode() taskMgr.remove(self.stepTask) vehicles.remove(self) def getspeed(self): """Return the speed (not the velocity) of this vehicle (float).""" return self._velocity.length() def getX(self): """Convenience method for accessing self._pos.getX()""" return self._pos.getX() def getY(self): """Convenience method for accessing self._pos.getY()""" return self._pos.getY() def getForward(self): """Return this vehicle's forward direction, a unit vector (SteerVec). """ forward = SteerVec(self._velocity.getX(), self._velocity.getY()) forward.normalize() return forward def getRight(self): """Return this vehicle's right direction, a unit vector (SteerVec). """ right = self._velocity.rotate(90) right.normalize() return right def predictFuturePosition(self, predictionTime): """ Return the predicted position (SteerVec) of this vehicle predictionTime units in the future using a simple linear predictor. """ return self._pos + (self._velocity * predictionTime) # Public methods used to activate steering behaviors. Once a steering # behavior is activated it will be applied every simulation frame until # another steering behavior is activated. Only one steering behavior can # be active at once. def stop(self): """Activate 'no steering' behavior. No steering force will be applied. """ self._steeringbehavior = [] def seek(self, target): """Activate seek steering behavior. target should be a SteerVec. """ self._steeringbehavior = ['Seek'] self._target = target def flee(self, target): """Activate flee steering behavior. target should be a SteerVec. """ self._steeringbehavior = ['Flee'] self._target = target def pursue(self, target): """Activate pursue steering behavior. target should be another Vehicle. """ self._steeringbehavior = ['Pursue'] self._target = target def follow(self, target): """Activate follow steering behavior. target should be another Vehicle. """ self._steeringbehavior = ['Follow'] self._target = target def evade(self, target): """Activate evade steering behavior. target should be another Vehicle. """ self._steeringbehavior = ['Evade'] self._target = target def arrive(self, target): """Activate the arrive steering behavior. target should be a SteerVec. """ self._steeringbehavior = ['Arrive'] self._target = target def wander(self): """Activate wander steering behavior. """ # FIXME: when mixin behaviours are in use, wanderSide and wanderUp # should be reset every time a mixin is activated. self.wanderSide = 0 self.wanderUp = 0 self._steeringbehavior = ['Wander'] def followPath(self, path, loop=False): self._steeringbehavior = ['FollowPath'] self._path = path self._waypoint = path.getNearestWaypoint(self._pos) self._loop = loop # Private methods to compute the steering vectors for steering behaviors. # These methods will be called by self._step(). Each method may return None # indicating that no steering is required at this time for the behavior. def _steerForSeek(self, target=None): """Return the steering_direction (SteerVec) required to seek target. target should be a SteerVec.""" if target == None: target = self._target desired_velocity = -(self._pos - target) * self.maxspeed desired_velocity.normalize() steering_direction = desired_velocity - self._velocity return steering_direction def _steerForFlee(self, target=None): """Return the steering_direction (SteerVec) required to flee target. target should be a SteerVec.""" if target == None: target = self._target desired_velocity = (self._pos - target) * self.maxspeed desired_velocity.normalize() steering_direction = desired_velocity - self._velocity return steering_direction def _steerForPursue(self, target=None): """Return the steering_direction (SteerVec) required to pursue target. target should be another Vehicle.""" # FIXME: Should the prediction interval be a parameter somewhere? if target == None: target = self._target prediction = target.predictFuturePosition(10) return self._steerForSeek(prediction) def _steerForFollow(self, target=None): """Return the steering_direction (SteerVec) required to follow target. target should be another Vehicle. Follow is like the pursue behavior but the vehicle will follow behind its target instead of catching up to it. The arrive behavior is place of seek in pursuit""" if target == None: target = self._target direction = SteerVec(target._velocity.getX(), target._velocity.getY()) direction.normalize() point = target._pos + direction * -5 return self._steerForArrive(point) def _steerForEvade(self, target=None): """Return the steering_direction (SteerVec) required to evade target. target should be another Vehicle.""" # FIXME: Should the prediction interval be a parameter somewhere? if target == None: target = self._target prediction = target.predictFuturePosition(10) return self._steerForFlee(prediction) def _steerForArrive(self, target=None): """Return the steering_direction (SteerVec) required to arrive at target. target should be a SteerVec.""" if target == None: target = self._target else: # Make sure it's a SteerVec (if it's not we assume it's something # with a getX() and getY() and we translate it) if not isinstance(target, SteerVec): target = SteerVec(target.getX(), target.getY()) # FIXME: slowing_distance should be a parameter somewhere. slowing_distance = 20 target_offset = target - self._pos distance = target_offset.length() if distance == 0: return SteerVec(0, 0) ramped_speed = self.maxspeed * (distance / slowing_distance) clipped_speed = min(ramped_speed, self.maxspeed) desired_velocity = target_offset * (clipped_speed / distance) steering_direction = desired_velocity - self._velocity return steering_direction def _steerForWander(self): """Return a steering_direction for wandering.""" speed = 0.2 self.wanderSide = self._scalarRandomWalk(self.wanderSide, speed, -1, 1) self.wanderUp = self._scalarRandomWalk(self.wanderUp, speed, -1, 1) up = self._velocity up.normalize() # The vehicle's forward direction side = up.rotate(90) return ((side * self.wanderSide) + (up * self.wanderUp)).truncate(0.01) def _scalarRandomWalk(self, initial, walkspeed, minimum, maximum): """Helper function for Vehicle._steerForWander() below.""" next = initial + ((random.random() * 2) - 1) * walkspeed if next < minimum: return minimum if next > maximum: return maximum return next def _steerForAvoidObstacles(self): """ Return a steering force to avoid the nearest obstacle that is considered a collision threat, or None to indicate that no obstacle avoidance steering is required. """ # Check for collisions with obstacles. collision = False obstacleHandler.sortEntries() for i in range(obstacleHandler.getNumEntries()): entry = obstacleHandler.getEntry(i) if entry.getInto() == self.tube: collision = True pos = entry.getSurfacePoint(render) nrml = entry.getSurfaceNormal(render) if collision is False: return None # Compute steering to avoid the collision. nrml = SteerVec(nrml.getX(), nrml.getY()) forward = self._velocity forward.normalize() steeringdirection = nrml.perpendicularComponent(forward) steeringdirection.normalize() brakingdirection = -self._velocity brakingdirection.normalize() md = self._velocity.length() + self.radius mf = self.maxforce p = SteerVec(pos.getX(), pos.getY()) d = (self._pos - p).length() if d < 0: d = 0 steeringforce = mf - ((d / md) * mf) brakingforce = mf - ((sqrt(d) / md) * mf) return (brakingdirection * brakingforce) + (steeringdirection * steeringforce) def _steerForContainment(self): """ If this vehicle is outside either the global container or its local self.container return a steering force to turn the vehicle back towards the container. Else return None to indicate no containment steering is required. self.container is given priority over the global container. """ global container for container in (self.container, container): if container is None: continue if not container.isInside(self._pos): # We are outside of the container, steer back toward it seek = self._steerForSeek(container.pos) lateral = seek.perpendicularComponent(self.getForward()) return lateral return None def _steerForFollowPath(self): if (self._pos - self._path[self._waypoint]).length() < 3: self._waypoint += 1 if self._waypoint >= len(self._path): if self._loop: self._waypoint = 0 else: self._waypoint = len(self._path) - 1 if not self._loop and self._waypoint == len(self._path) - 1: return self._steerForArrive(self._path[self._waypoint]) else: return self._steerForSeek(self._path[self._waypoint]) def _steerForAvoidVehicles(self): """ Return a steering force to avoid the site of the soonest potential collision with another vehicle, or None if there is no impending collision. Unaligned collision avoidance behavior: avoid colliding with other nearby vehicles moving in unconstrained directions. Determine which (if any) other other vehicle we would collide with first, then steer to avoid the site of that potential collision. """ # First priority is to steer hard to avoid very close vehicles steering = self._steerForAvoidCloseNeighbors(0) if steering is not False: return steering # Otherwise look for collisions further away. steer = 0 threat = None # Time (in seconds) until the most immediate collision threat found # so far. Initial value is a threshold: don't look more than this # many frames into the future. minTime = 60 # Determine which (if any) neighbor vehicle poses the most immediate # threat of collision. for vehicle in vehicles: if vehicle is self: continue # Avoid when future positions are this close (or less) collisionDangerThreshold = self.radius * 2 # Predicted time until nearest approach time = self._predictNearestApproachTime(vehicle) # If `time` is in the future, sooner than any other threatened # collision... if time >= 0 and time < minTime: # If the two will be close enough to collide make a note of it thrtPosAtNrstApprch, distance = self._computeNearestApproachPositions( time, vehicle) if distance < collisionDangerThreshold: minTime = time threat = vehicle # If a potential collision was found, compute steering to avoid if threat is None: return None else: parallelness = self.getForward().dot(threat.getForward()) angle = 0.707 if parallelness < -angle: # Anti-parallel "head on" paths: steer away from future threat # position offset = thrtPosAtNrstApprch - self._pos sideDot = offset.dot(self.getRight()) if sideDot > 0: steer = -1 else: steer = 1 elif parallelness > angle: # Parallel paths: steer away from threat offset = threat._pos - self._pos sideDot = offset.dot(self.getRight()) if sideDot > 0: steer = -1 else: steer = 1 elif threat.getspeed() <= self.getspeed(): # Perpendicular paths: steer behind threat (only the slower of # the two does this) sideDot = self.getRight().dot(threat._velocity) if sideDot > 0: steer = -1 else: steer = 1 return self.getRight() * steer def _predictNearestApproachTime(self, vehicle): """Return the time until nearest approach between this vehicle and another vehicle.""" # Imagine we are at the origin with no velocity, compute the relative # velocity of the other vehicle myVelocity = self._velocity hisVelocity = vehicle._velocity relVelocity = hisVelocity - myVelocity relSpeed = relVelocity.length() # For parallel paths, the vehicles will always be at the same distance, # so return 0 (aka "now") since "there is no time like the present" if relSpeed == 0: return 0 # Now consider the path of the other vehicle in this relative # space, a line defined by the relative position and velocity. # The distance from the origin (our vehicle) to that line is # the nearest approach. # Take the unit tangent along the other vehicle's path relTangent = relVelocity / relSpeed # Find distance from its path to origin (compute offset from # other to us, find length of projection onto path) relPosition = self._pos - vehicle._pos projection = relTangent.dot(relPosition) return projection / relSpeed def _computeNearestApproachPositions(self, time, vehicle): """Return a tuple containing the position of 'vehicle' at its nearest approach to this vehicle and the distance between the two at that point, given the time until the nearest approach of the two.""" myTravel = (self.getForward() * self.getspeed()) * time hisTravel = vehicle.getForward() * vehicle.getspeed() * time myFinal = self._pos + myTravel hisFinal = vehicle._pos + hisTravel distance = (myFinal - hisFinal).length() return (hisFinal, distance) def _steerForAvoidCloseNeighbors(self, criticalDistance): """Avoidance of "close neighbors" -- used only by _steerForAvoidNeighbors. Does a hard steer away from any other vehicle who comes withing a critical distance.""" for vehicle in vehicles: if vehicle is self: continue # No need to avoid yourself sumOfRadii = self.radius + vehicle.radius minCenterToCenter = criticalDistance + sumOfRadii offset = vehicle._pos - self._pos currentDistance = offset.length() if currentDistance < minCenterToCenter: return (-offset).perpendicularComponent(self.getForward()) return False def _step(self, task): """ Update the vehicle's position using a simple point-mass physics model based on self._steeringforce, self.maxforce, self.mass, and self.maxspeed, and applying the steering behavior indicated by self._steeringbehavior. """ dt = task.time - self._prevtime steeringbehavior = self._steeringbehavior if self.avoidObstacles: steeringbehavior = ['AvoidObstacles'] + steeringbehavior if self.avoidVehicles: steeringbehavior = ['AvoidVehicles'] + steeringbehavior if (self.container is not None) or (container is not None): steeringbehavior = ['Containment'] + steeringbehavior # Set self._steeringforce to be the result of the first method in # steeringbehavior that does not return None. self._steeringforce = SteerVec(0, 0) self.label['text'] = 'no steering' for steeringmethod in steeringbehavior: method_name = '_steerFor' + steeringmethod method = getattr(self, method_name) steeringforce = method() if steeringforce is not None: self.label['text'] = steeringmethod self._steeringforce = steeringforce break global show if show: self.label.show() #self.tubenp.show() #self.spherenp.show() else: self.label.hide() #self.tubenp.hide() #self.spherenp.hide() # Compute new velocity according to point-mass physics. steering_force = self._steeringforce.truncate(self.maxforce) acceleration = steering_force / self.mass self._velocity = (self._velocity + acceleration).truncate( self.maxspeed) # Add a small random component to the velocity. The component is too # small to produce any visible result. It is added to avoid a bug in # the obstacle avoidance behavior: if a vehicle heads precisely # toward an obstacle then the surface normal at the point of # collision on the surface of the obstacle is parallel to the forward # direction of the vehicle. So the perpendicular component of the # surface normal to the vehicle's forward direction is zero, and hence # the steering force is zero, and the vehicle plows straight into the # obstacle. With a random element to the vehicle's velocity, this # precise situation will not exist for consecutive simulation frames. x = (random.random() - 0.5) * 0.01 y = (random.random() - 0.5) * 0.01 self._velocity.setX(self._velocity.getX() + self._velocity.getX() * x) self._velocity.setY(self._velocity.getY() + self._velocity.getY() * y) # Update vehicle's position. self._pos += self._velocity * (dt * 50) self._enforceNonPenetrationConstraint() # Fluidly update the NodePath's X and Y positions to match self._pos. # Leave the NodePath's Z-axis position untouched (that is taken care of # by CollisionHandlerFloor). self.prime.setFluidPos(self._pos.getX(), self._pos.getY(), self.prime.getZ()) # Update the Vehicles's CollisionTube, varying the length of the tube # according to the Vehicle's speed. ##zuck ###tube=self.tubenp.node().getSolid(0) tube = self.tubenp.node().modifySolid(0) tube.setPointB( Point3(tube.getPointA() + Point3(0, 15. * self._velocity.length(), 0))) self._prevtime = task.time return Task.cont def _enforceNonPenetrationConstraint(self): """Forcibly prevent this vehicle from penetrating obstacles. Based on advice from Craig Reynolds: The obstacle and vehicle are both assumed to be spheres. Measure the distance between their centers. If this is less than the sum of their radii the two spheres intersect. If so, simply "slide" (that is, SET the position of) the vehicle along the line connecting their centers the distance by which they overlap. See code here: http://sourceforge.net/forum/message.php?msg_id=3928822 """ # Handle collisions with obstacles. obstacleHandler.sortEntries() for i in range(obstacleHandler.getNumEntries()): entry = obstacleHandler.getEntry(i) if entry.getInto() == self.sphere: other = entry.getFrom() pos = other.getCenter() pos = SteerVec(pos.getX(), pos.getY()) s = self.radius + other.getRadius() overlap = self._pos - pos d = overlap.length() if d > 0: s = (s - d) / d overlap *= s self._pos += overlap return # Handle collisions with other vehicles. collisionHandler.sortEntries() for i in range(collisionHandler.getNumEntries()): entry = collisionHandler.getEntry(i) # FIXME: The collisionmasks in this module aren't quite right. # Want Vehicle.sphere to collide with other Vehicle.sphere's and # with obstacles.py/SphereObstacle's, and want Vehicle.tube to # collide with obstacles.py/SphereObstacle's, but we don't want # Vehicle.sphere to collide with the Vehicle.tube of another # vehicle! (or vice-versa) # For now just check for the unwanted tube collisions and ignore # them. if isinstance(entry.getInto(), CollisionTube): continue if entry.getFrom() == self.sphere: pos = entry.getIntoNodePath().getPos(render) pos = SteerVec(pos.getX(), pos.getY()) s = self.radius + entry.getInto().getRadius() overlap = self._pos - pos d = overlap.length() if d > 0: s = (s - d) / d overlap *= s self._pos += overlap if self.callout['text'] == '': self.callout['text'] = random.choice( ["Ouch!", "Sorry!", "Hey!"]) self.callout.show() return self.callout['text'] = '' self.callout.hide()
class PlayerHUD(): def __init__(self): # # Player status section # heartscale = (0.1, 1, 0.1) self.heart1 = OnscreenImage(image="HeartIcon.png", scale=heartscale, pos=(0.2, 0, -0.15)) self.heart1.setTransparency(True) self.heart1.reparentTo(base.a2dTopLeft) self.heart2 = OnscreenImage(image="HeartIcon.png", scale=heartscale, pos=(0.45, 0, -0.15)) self.heart2.setTransparency(True) self.heart2.reparentTo(base.a2dTopLeft) self.heart3 = OnscreenImage(image="HeartIcon.png", scale=heartscale, pos=(0.7, 0, -0.15)) self.heart3.setTransparency(True) self.heart3.reparentTo(base.a2dTopLeft) self.keys = DirectLabel(text="x0", frameColor=(0, 0, 0, 0), text_fg=(1, 1, 1, 1), text_scale=1.8, text_pos=(1, -0.25, 0), text_align=TextNode.ALeft, image="Keys.png", pos=(0.2, 0, -0.4)) self.keys.setScale(0.085) self.keys.setTransparency(True) self.keys.reparentTo(base.a2dTopLeft) self.actionKey = DirectLabel(frameColor=(0, 0, 0, 0), text_fg=(1, 1, 1, 1), scale=0.15, pos=(0, 0, 0.15), text=_("Action: E/Enter")) self.actionKey.setTransparency(True) self.actionKey.reparentTo(base.a2dBottomCenter) self.actionKey.hide() def show(self): self.keys.show() def hide(self): self.heart1.hide() self.heart2.hide() self.heart3.hide() self.keys.hide() self.hideActionKey() def setHealthStatus(self, value): """this function will set the health image in the top righthand corner according to the given value, where value is a integer between 0 and 100 """ if value >= 1: self.heart1.show() else: self.heart1.hide() if value >= 2: self.heart2.show() else: self.heart2.hide() if value >= 3: self.heart3.show() else: self.heart3.hide() def showActionKey(self): self.actionKey.show() def hideActionKey(self): self.actionKey.hide() def updateKeyCount(self, numKeys): self.keys["text"] = "x%d" % numKeys
class GUI: def __init__(self, rootParent=None): self.frmInventory = DirectFrame( frameColor=(0.2, 0.2, 0.2, 1.0), frameSize=(-0.3, 0.3, -0.5, 0.5), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(0.725, 0, 0.2), parent=rootParent, ) self.frmInventory.setTransparency(0) self.frmContent = DirectScrolledFrame( canvasSize=(-0.8, 0.8, -0.8, 0.8), frameColor=(0.2, 0.2, 0.2, 1.0), frameSize=(-0.8, 0.8, -0.8, 0.8), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(-0.475, 0, 0.1), scrollBarWidth=0.08, state='normal', horizontalScroll_borderWidth=(0.01, 0.01), horizontalScroll_frameSize=(-0.05, 0.05, -0.04, 0.04), horizontalScroll_hpr=LVecBase3f(0, 0, 0), horizontalScroll_pos=LPoint3f(0, 0, 0), horizontalScroll_decButton_borderWidth=(0.01, 0.01), horizontalScroll_decButton_frameSize=(-0.05, 0.05, -0.04, 0.04), horizontalScroll_decButton_hpr=LVecBase3f(0, 0, 0), horizontalScroll_decButton_pos=LPoint3f(0, 0, 0), horizontalScroll_incButton_borderWidth=(0.01, 0.01), horizontalScroll_incButton_frameSize=(-0.05, 0.05, -0.04, 0.04), horizontalScroll_incButton_hpr=LVecBase3f(0, 0, 0), horizontalScroll_incButton_pos=LPoint3f(0, 0, 0), horizontalScroll_thumb_borderWidth=(0.01, 0.01), horizontalScroll_thumb_hpr=LVecBase3f(0, 0, 0), horizontalScroll_thumb_pos=LPoint3f(0, 0, 0), verticalScroll_borderWidth=(0.01, 0.01), verticalScroll_frameSize=(-0.04, 0.04, -0.05, 0.05), verticalScroll_hpr=LVecBase3f(0, 0, 0), verticalScroll_pos=LPoint3f(0, 0, 0), verticalScroll_decButton_borderWidth=(0.01, 0.01), verticalScroll_decButton_frameSize=(-0.04, 0.04, -0.05, 0.05), verticalScroll_decButton_hpr=LVecBase3f(0, 0, 0), verticalScroll_decButton_pos=LPoint3f(0, 0, 0), verticalScroll_incButton_borderWidth=(0.01, 0.01), verticalScroll_incButton_frameSize=(-0.04, 0.04, -0.05, 0.05), verticalScroll_incButton_hpr=LVecBase3f(0, 0, 0), verticalScroll_incButton_pos=LPoint3f(0, 0, 0), verticalScroll_thumb_borderWidth=(0.01, 0.01), verticalScroll_thumb_hpr=LVecBase3f(0, 0, 0), verticalScroll_thumb_pos=LPoint3f(0, 0, 0), parent=rootParent, ) self.frmContent.setTransparency(1) self.btnQuit = DirectButton( frameSize=(-3.0, 3.0, -0.3, 0.9), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(0.725, 0, -0.85), scale=LVecBase3f(0.1, 0.1, 0.1), text='Quit', text_align=TextNode.A_center, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(0, 0, 0, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=rootParent, command=base.messenger.send, extraArgs=["quitGame"], pressEffect=1, ) self.btnQuit.setTransparency(0) self.btnAudioToggle = DirectButton( frameSize=(-3.0, 3.0, -0.3, 0.9), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(0.725, 0, -0.7), scale=LVecBase3f(0.1, 0.1, 0.1), text='Audio On', text_align=TextNode.A_center, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(0, 0, 0, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=rootParent, command=base.messenger.send, extraArgs=["toggleAudio"], pressEffect=1, ) self.btnAudioToggle.setTransparency(0) self.frmBorderOverlay = DirectFrame( frameColor=(1.0, 1.0, 1.0, 0.0), frameSize=(-0.8, 0.8, -0.8, 0.8), hpr=LVecBase3f(0, 0, 0), image='gameScreen/border.png', pos=LPoint3f(-0.475, 0, 0.1), image_scale=LVecBase3f(0.8, 1, 0.8), image_pos=LPoint3f(0, 0, 0), parent=rootParent, ) self.frmBorderOverlay.setTransparency(1) self.lblInventory = DirectLabel( frameColor=(0.8, 0.8, 0.8, 0.0), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(0.725, 0, 0.775), scale=LVecBase3f(0.1, 0.1, 0.1), text='Inventory', text_align=TextNode.A_center, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(0.9, 0.9, 0.9, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=rootParent, ) self.lblInventory.setTransparency(0) self.lblStory = DirectLabel( frameSize=(-0.125, 12.0, -0.313, 0.925), hpr=LVecBase3f(0, 0, 0), pad=(0.2, 0.2), pos=LPoint3f(-1.26, 0, -0.845), scale=LVecBase3f(0.1, 0.1, 0.1), text='', text_align=TextNode.A_left, text_scale=(0.4, 0.4), text_pos=(0.0, 0.4), text_fg=LVecBase4f(0, 0, 0, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=29.8, parent=rootParent, ) self.lblStory.setTransparency(0) self.btnContinue = DirectButton( frameSize=(-1.8, 1.8, -0.3, 0.9), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(0.145, 0, -0.845), scale=LVecBase3f(0.1, 0.1, 0.1), text='Cont.', text_align=TextNode.A_center, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(0, 0, 0, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=rootParent, command=base.messenger.send, extraArgs=["story_continue"], pressEffect=1, ) self.btnContinue.setTransparency(0) self.frmFadeOverlay = DirectFrame( frameColor=(0.0, 0.0, 0.0, 1.0), frameSize=(-0.8, 0.8, -0.8, 0.8), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(-0.475, 0, 0.1), parent=rootParent, ) self.frmFadeOverlay.setTransparency(1) def show(self): self.frmInventory.show() self.frmContent.show() self.btnQuit.show() self.btnAudioToggle.show() self.frmBorderOverlay.show() self.lblInventory.show() self.lblStory.show() self.btnContinue.show() self.frmFadeOverlay.show() def hide(self): self.frmInventory.hide() self.frmContent.hide() self.btnQuit.hide() self.btnAudioToggle.hide() self.frmBorderOverlay.hide() self.lblInventory.hide() self.lblStory.hide() self.btnContinue.hide() self.frmFadeOverlay.hide() def destroy(self): self.frmInventory.destroy() self.frmContent.destroy() self.btnQuit.destroy() self.btnAudioToggle.destroy() self.frmBorderOverlay.destroy() self.lblInventory.destroy() self.lblStory.destroy() self.btnContinue.destroy() self.frmFadeOverlay.destroy()
class MPBtn(GameObject): tooltip_align = TextNode.A_right tooltip_offset = (.01, 0, -.08) def __init__(self, parent, owner, menu_args, img_path, msg_btn_x, cb, usr_name, tooltip): GameObject.__init__(self) self.owner = owner lab_args = menu_args.label_args lab_args['scale'] = .046 #lab_args['text_fg'] = menu_args.text_normal self.btn = ImgBtn(parent=parent, scale=.024, pos=(msg_btn_x, 1, .01), frameColor=(1, 1, 1, 1), frameTexture=img_path, command=cb, extraArgs=[usr_name], **menu_args.imgbtn_args) self.btn.bind(ENTER, self.on_enter) self.btn.bind(EXIT, self.on_exit) self.tooltip_btn = DirectButton(parent=parent, scale=.024, pos=(msg_btn_x, 1, .01), frameColor=(1, 1, 1, 0), frameSize=(-1, 1, -1, 1), command=None, **menu_args.imgbtn_args) self.tooltip_btn.bind(ENTER, self.on_enter) self.tooltip_btn.bind(EXIT, self.on_exit) self.on_create() self.tooltip = DirectLabel(text=tooltip, pos=self.btn.get_pos() + self.tooltip_offset, parent=parent, text_wordwrap=10, text_bg=(.2, .2, .2, .8), text_align=self.tooltip_align, **lab_args) self.tooltip.set_bin('gui-popup', 10) self.tooltip.hide() def on_create(self): self.btn.hide() self.tooltip_btn.hide() def is_hidden(self): return self.btn.is_hidden() def show(self): if self.btn['state'] == DISABLED: self.tooltip_btn.show() else: self.tooltip_btn.hide() return self.btn.show() def hide(self): self.tooltip_btn.hide() return self.btn.hide() def enable(self): self.tooltip_btn.hide() return self.btn.enable() def disable(self): self.tooltip_btn.show() return self.btn.disable() def on_enter(self, pos): self.owner.on_enter(pos) self.tooltip.show() def on_exit(self, pos): self.owner.on_exit(pos) self.tooltip.hide()
class Vehicle: """A steerable point mass with various steering behaviors.""" # FIXME: One fix that is needed is that wanderSide and wanderUp should be # reset whenever a character switches back to the wander behaviour. This # might prevent wandering characters from 'hugging' obstacles and # containers when wandering is combined with obstacle avoidance and/or # containment. What happens is that the characters wanders into the # obstacle, avoidance takes over and steers the character away from it, # then when wandering gets control again it picks up where it left off -- # steering toward the obstacle. # # So make Vehicle a state-machine, with the state being the currently # active steering behaviour, so that there can be transition-in and # transition-out functions for steering behaviours? def __init__(self,pos=None,mass=1,maxforce=0.1,maxspeed=1,radius=1, avoidVehicles=True,avoidObstacles=True,container=None): """Initialise the vehicle.""" self.mass = mass # mass = 1 means that acceleration = force self.maxforce = maxforce self.maxspeed = maxspeed self.radius = radius self.avoidVehicles = avoidVehicles # Avoid colliding with other Vehicles self.avoidObstacles = avoidObstacles # Avoid colliding with obstacles if pos is None: pos = Point3(0,0,0) # The Vehicle controls a primary NodePath to which other NodePath's for # CollisionSolids are parented. Other nodes, such as animated Actors, # can be attached to this NodePath by user classes. self.prime = NodePath('Vehicle primary NodePath') self.prime.reparentTo(render) self.prime.setPos(pos) # If the Vehicle finds itself outside of its container it will turn # back toward the container. The vehicle also stays within the global # container at all times. The idea is that Vehicle.container can be # used to restrict one particular vehicle to a space smaller than the # global container. self.container = container self._pos = SteerVec(pos.getX(),pos.getY()) # 2D pos for steering # calculations self._velocity = SteerVec(0,0) self._steeringforce = SteerVec(0,0) self._steeringbehavior = [] # Some steering behaviors make use of self._target, which can be # another Vehicle or a point in 2-space (SteerVec), or it might be None # indicating that no target is currently in use. self._target = None # Initialise the Vehicle's CollisionRay which is used with a # CollisionHandlerFloor to keep the Vehicle on the ground. self.raynp = self.prime.attachNewNode(CollisionNode('colNode')) self.raynp.node().addSolid(CollisionRay(0,0,3,0,0,-1)) self.floorhandler = CollisionHandlerFloor() self.floorhandler.addCollider(self.raynp,self.prime) cTrav.addCollider(self.raynp,self.floorhandler) # Uncomment this line to show the CollisionRay: #self.raynp.show() # We only want our CollisionRay to collide with the collision # geometry of the terrain only, se we set a mask here. self.raynp.node().setFromCollideMask(floorMASK) self.raynp.node().setIntoCollideMask(offMASK) # Initialise CollisionTube for detecting oncoming obstacle collisions. x,y,z = self.prime.getX(),self.prime.getY(),self.prime.getZ()+3 #FIXME: Don't hardcode how high the tube goes, add height parameter to __init__ for both tube and sphere vx,vy = self._velocity.getX(),self._velocity.getY() r = self.radius f = self.prime.getNetTransform().getMat().getRow3(1) s = 10 self.tube = CollisionTube(x,y,z,x+f.getX()*s,y+f.getY()*s,z,self.radius) self.tubenp = self.prime.attachNewNode(CollisionNode('colNode')) self.tubenp.node().addSolid(self.tube) # The tube should only collide with obstacles (and is an 'into' object) self.tubenp.node().setFromCollideMask(offMASK) self.tubenp.node().setIntoCollideMask(obstacleMASK) # Uncomment this line to show the CollisionTube #self.tubenp.show() # CollisionSphere for detecting when we've actuallyt collided with # something. self.sphere = CollisionSphere(x,y,z,self.radius) self.spherenp = self.prime.attachNewNode(CollisionNode('cnode')) self.spherenp.node().addSolid(self.sphere) # Only collide with the CollisionSphere's of other vehicles. self.spherenp.node().setFromCollideMask(obstacleMASK) # So the spheres of vehicles will collide with eachother self.spherenp.node().setIntoCollideMask(obstacleMASK) # So obstacles will collide into spheres of vehicles cTrav.addCollider(self.spherenp,collisionHandler) # Uncomment this line to show the CollisionSphere #self.spherenp.show() # Add a task for this Vehicle to the global task manager. self._prevtime = 0 self.stepTask=taskMgr.add(self._step,"Vehicle step task") # Add the Vehicle to the global list of Vehicles vehicles.append(self) # Initialise the DirectLabel used when annotating the Vehicle # FIXME: Needs to be destroyed in self.destroy self.text = "no steering" self.label = DirectLabel(parent=self.prime,pos=(4,4,4),text=self.text, text_wordwrap=10,relief=None, text_scale=(1.5,1.5),text_frame=(0,0,0,1), text_bg=(1,1,1,1)) self.label.component('text0').textNode.setCardDecal(1) self.label.setBillboardAxis() self.label.hide() self.label.setLightOff(1) # A second label for speaking ('Ouch!', 'Sorry!' etc.) self.callout = DirectLabel(parent=self.prime,pos=(4,4,4),text='', text_wordwrap=10,relief=None, text_scale=(1.5,1.5),text_frame=(0,0,0,1), text_bg=(1,1,1,1)) self.callout.component('text0').textNode.setCardDecal(1) self.callout.setBillboardAxis() self.callout.hide() self.callout.setLightOff(1) def destroy(self): """Prepare this Vehicle to be garbage-collected by Python: Remove all of the Vehicle's nodes from the scene graph, remove its CollisionSolids from the global CollisionTraverser, clear its CollisionHandler, remove tasks After executing this method, any remaining references to the Vehicle object can be destroyed by the user module, and the Vehicle will be garbage-collected by Python. """ cTrav.removeCollider(self.raynp) cTrav.removeCollider(self.spherenp) self.floorhandler.clearColliders() self.floorhandler = None self.prime.removeNode() taskMgr.remove(self.stepTask) vehicles.remove(self) def getspeed(self): """Return the speed (not the velocity) of this vehicle (float).""" return self._velocity.length() def getX(self): """Convenience method for accessing self._pos.getX()""" return self._pos.getX() def getY(self): """Convenience method for accessing self._pos.getY()""" return self._pos.getY() def getForward(self): """Return this vehicle's forward direction, a unit vector (SteerVec). """ forward = SteerVec(self._velocity.getX(),self._velocity.getY()) forward.normalize() return forward def getRight(self): """Return this vehicle's right direction, a unit vector (SteerVec). """ right = self._velocity.rotate(90) right.normalize() return right def predictFuturePosition(self, predictionTime): """ Return the predicted position (SteerVec) of this vehicle predictionTime units in the future using a simple linear predictor. """ return self._pos + (self._velocity * predictionTime) # Public methods used to activate steering behaviors. Once a steering # behavior is activated it will be applied every simulation frame until # another steering behavior is activated. Only one steering behavior can # be active at once. def stop(self): """Activate 'no steering' behavior. No steering force will be applied. """ self._steeringbehavior = [] def seek(self, target): """Activate seek steering behavior. target should be a SteerVec. """ self._steeringbehavior = ['Seek'] self._target = target def flee(self, target): """Activate flee steering behavior. target should be a SteerVec. """ self._steeringbehavior = ['Flee'] self._target = target def pursue(self, target): """Activate pursue steering behavior. target should be another Vehicle. """ self._steeringbehavior = ['Pursue'] self._target = target def follow(self, target): """Activate follow steering behavior. target should be another Vehicle. """ self._steeringbehavior = ['Follow'] self._target = target def evade(self, target): """Activate evade steering behavior. target should be another Vehicle. """ self._steeringbehavior = ['Evade'] self._target = target def arrive(self, target): """Activate the arrive steering behavior. target should be a SteerVec. """ self._steeringbehavior = ['Arrive'] self._target = target def wander(self): """Activate wander steering behavior. """ # FIXME: when mixin behaviours are in use, wanderSide and wanderUp # should be reset every time a mixin is activated. self.wanderSide=0 self.wanderUp=0 self._steeringbehavior = ['Wander'] def followPath(self,path,loop=False): self._steeringbehavior = ['FollowPath'] self._path = path self._waypoint = path.getNearestWaypoint(self._pos) self._loop = loop # Private methods to compute the steering vectors for steering behaviors. # These methods will be called by self._step(). Each method may return None # indicating that no steering is required at this time for the behavior. def _steerForSeek(self, target=None): """Return the steering_direction (SteerVec) required to seek target. target should be a SteerVec.""" if target == None: target = self._target desired_velocity = -(self._pos - target) * self.maxspeed desired_velocity.normalize() steering_direction = desired_velocity - self._velocity return steering_direction def _steerForFlee(self, target=None): """Return the steering_direction (SteerVec) required to flee target. target should be a SteerVec.""" if target == None: target = self._target desired_velocity = (self._pos - target) * self.maxspeed desired_velocity.normalize() steering_direction = desired_velocity - self._velocity return steering_direction def _steerForPursue(self, target=None): """Return the steering_direction (SteerVec) required to pursue target. target should be another Vehicle.""" # FIXME: Should the prediction interval be a parameter somewhere? if target == None: target = self._target prediction = target.predictFuturePosition(10) return self._steerForSeek(prediction) def _steerForFollow(self, target=None): """Return the steering_direction (SteerVec) required to follow target. target should be another Vehicle. Follow is like the pursue behavior but the vehicle will follow behind its target instead of catching up to it. The arrive behavior is place of seek in pursuit""" if target == None: target = self._target direction = SteerVec(target._velocity.getX(),target._velocity.getY()) direction.normalize() point = target._pos + direction*-5 return self._steerForArrive(point) def _steerForEvade(self, target=None): """Return the steering_direction (SteerVec) required to evade target. target should be another Vehicle.""" # FIXME: Should the prediction interval be a parameter somewhere? if target == None: target = self._target prediction = target.predictFuturePosition(10) return self._steerForFlee(prediction) def _steerForArrive(self, target=None): """Return the steering_direction (SteerVec) required to arrive at target. target should be a SteerVec.""" if target == None: target = self._target else: # Make sure it's a SteerVec (if it's not we assume it's something # with a getX() and getY() and we translate it) if not isinstance(target,SteerVec): target = SteerVec(target.getX(),target.getY()) # FIXME: slowing_distance should be a parameter somewhere. slowing_distance = 20 target_offset = target - self._pos distance = target_offset.length() if distance == 0: return SteerVec(0,0) ramped_speed = self.maxspeed * (distance / slowing_distance) clipped_speed = min(ramped_speed,self.maxspeed) desired_velocity = target_offset * (clipped_speed / distance) steering_direction = desired_velocity - self._velocity return steering_direction def _steerForWander(self): """Return a steering_direction for wandering.""" speed = 0.2 self.wanderSide = self._scalarRandomWalk(self.wanderSide,speed,-1,1) self.wanderUp = self._scalarRandomWalk(self.wanderUp,speed,-1,1) up = self._velocity up.normalize() # The vehicle's forward direction side = up.rotate(90) return ((side * self.wanderSide) + (up * self.wanderUp)).truncate(0.01) def _scalarRandomWalk(self,initial,walkspeed,minimum,maximum): """Helper function for Vehicle._steerForWander() below.""" next = initial + ((random.random()*2)-1)*walkspeed if next < minimum: return minimum if next > maximum: return maximum return next def _steerForAvoidObstacles(self): """ Return a steering force to avoid the nearest obstacle that is considered a collision threat, or None to indicate that no obstacle avoidance steering is required. """ # Check for collisions with obstacles. collision = False obstacleHandler.sortEntries() for i in range(obstacleHandler.getNumEntries()): entry = obstacleHandler.getEntry(i) if entry.getInto() == self.tube: collision = True pos = entry.getSurfacePoint(render) nrml = entry.getSurfaceNormal(render) if collision is False: return None # Compute steering to avoid the collision. nrml = SteerVec(nrml.getX(),nrml.getY()) forward = self._velocity forward.normalize() steeringdirection = nrml.perpendicularComponent(forward) steeringdirection.normalize() brakingdirection = -self._velocity brakingdirection.normalize() md = self._velocity.length() + self.radius mf = self.maxforce p = SteerVec(pos.getX(),pos.getY()) d = (self._pos - p).length() if d < 0: d = 0 steeringforce = mf - ((d/md)*mf) brakingforce = mf - ((sqrt(d)/md)*mf) return (brakingdirection*brakingforce)+(steeringdirection*steeringforce) def _steerForContainment(self): """ If this vehicle is outside either the global container or its local self.container return a steering force to turn the vehicle back towards the container. Else return None to indicate no containment steering is required. self.container is given priority over the global container. """ global container for container in (self.container,container): if container is None: continue if not container.isInside(self._pos): # We are outside of the container, steer back toward it seek = self._steerForSeek(container.pos) lateral = seek.perpendicularComponent(self.getForward()) return lateral return None def _steerForFollowPath(self): if (self._pos-self._path[self._waypoint]).length()<3: self._waypoint += 1 if self._waypoint >= len(self._path): if self._loop: self._waypoint = 0 else: self._waypoint = len(self._path)-1 if not self._loop and self._waypoint == len(self._path)-1: return self._steerForArrive(self._path[self._waypoint]) else: return self._steerForSeek(self._path[self._waypoint]) def _steerForAvoidVehicles(self): """ Return a steering force to avoid the site of the soonest potential collision with another vehicle, or None if there is no impending collision. Unaligned collision avoidance behavior: avoid colliding with other nearby vehicles moving in unconstrained directions. Determine which (if any) other other vehicle we would collide with first, then steer to avoid the site of that potential collision. """ # First priority is to steer hard to avoid very close vehicles steering = self._steerForAvoidCloseNeighbors(0) if steering is not False: return steering # Otherwise look for collisions further away. steer = 0 threat = None # Time (in seconds) until the most immediate collision threat found # so far. Initial value is a threshold: don't look more than this # many frames into the future. minTime = 60 # Determine which (if any) neighbor vehicle poses the most immediate # threat of collision. for vehicle in vehicles: if vehicle is self: continue # Avoid when future positions are this close (or less) collisionDangerThreshold = self.radius * 2 # Predicted time until nearest approach time = self._predictNearestApproachTime(vehicle) # If `time` is in the future, sooner than any other threatened # collision... if time >= 0 and time < minTime: # If the two will be close enough to collide make a note of it thrtPosAtNrstApprch,distance = self._computeNearestApproachPositions(time,vehicle) if distance < collisionDangerThreshold: minTime = time threat = vehicle # If a potential collision was found, compute steering to avoid if threat is None: return None else: parallelness = self.getForward().dot(threat.getForward()) angle = 0.707 if parallelness < -angle: # Anti-parallel "head on" paths: steer away from future threat # position offset = thrtPosAtNrstApprch - self._pos sideDot = offset.dot(self.getRight()) if sideDot > 0: steer = -1 else: steer = 1 elif parallelness > angle: # Parallel paths: steer away from threat offset = threat._pos - self._pos sideDot = offset.dot(self.getRight()) if sideDot > 0: steer = -1 else: steer = 1 elif threat.getspeed() <= self.getspeed(): # Perpendicular paths: steer behind threat (only the slower of # the two does this) sideDot = self.getRight().dot(threat._velocity) if sideDot > 0: steer = -1 else: steer = 1 return self.getRight() * steer def _predictNearestApproachTime(self,vehicle): """Return the time until nearest approach between this vehicle and another vehicle.""" # Imagine we are at the origin with no velocity, compute the relative # velocity of the other vehicle myVelocity = self._velocity hisVelocity = vehicle._velocity relVelocity = hisVelocity - myVelocity relSpeed = relVelocity.length() # For parallel paths, the vehicles will always be at the same distance, # so return 0 (aka "now") since "there is no time like the present" if relSpeed == 0: return 0 # Now consider the path of the other vehicle in this relative # space, a line defined by the relative position and velocity. # The distance from the origin (our vehicle) to that line is # the nearest approach. # Take the unit tangent along the other vehicle's path relTangent = relVelocity / relSpeed # Find distance from its path to origin (compute offset from # other to us, find length of projection onto path) relPosition = self._pos - vehicle._pos projection = relTangent.dot(relPosition) return projection / relSpeed def _computeNearestApproachPositions(self, time, vehicle): """Return a tuple containing the position of 'vehicle' at its nearest approach to this vehicle and the distance between the two at that point, given the time until the nearest approach of the two.""" myTravel = (self.getForward() * self.getspeed()) * time hisTravel = vehicle.getForward() * vehicle.getspeed() * time myFinal = self._pos + myTravel hisFinal = vehicle._pos + hisTravel distance = (myFinal - hisFinal).length() return (hisFinal,distance) def _steerForAvoidCloseNeighbors(self, criticalDistance): """Avoidance of "close neighbors" -- used only by _steerForAvoidNeighbors. Does a hard steer away from any other vehicle who comes withing a critical distance.""" for vehicle in vehicles: if vehicle is self: continue # No need to avoid yourself sumOfRadii = self.radius + vehicle.radius minCenterToCenter = criticalDistance + sumOfRadii offset = vehicle._pos - self._pos currentDistance = offset.length() if currentDistance < minCenterToCenter: return (-offset).perpendicularComponent(self.getForward()) return False def _step(self,task): """ Update the vehicle's position using a simple point-mass physics model based on self._steeringforce, self.maxforce, self.mass, and self.maxspeed, and applying the steering behavior indicated by self._steeringbehavior. """ dt = task.time - self._prevtime steeringbehavior = self._steeringbehavior if self.avoidObstacles: steeringbehavior = ['AvoidObstacles'] + steeringbehavior if self.avoidVehicles: steeringbehavior = ['AvoidVehicles'] + steeringbehavior if (self.container is not None) or (container is not None): steeringbehavior = ['Containment'] + steeringbehavior # Set self._steeringforce to be the result of the first method in # steeringbehavior that does not return None. self._steeringforce = SteerVec(0,0) self.label['text'] = 'no steering' for steeringmethod in steeringbehavior: method_name = '_steerFor' + steeringmethod method = getattr(self, method_name) steeringforce = method() if steeringforce is not None: self.label['text'] = steeringmethod self._steeringforce = steeringforce break global show if show: self.label.show() #self.tubenp.show() #self.spherenp.show() else: self.label.hide() #self.tubenp.hide() #self.spherenp.hide() # Compute new velocity according to point-mass physics. steering_force = self._steeringforce.truncate(self.maxforce) acceleration = steering_force/self.mass self._velocity = (self._velocity+acceleration).truncate(self.maxspeed) # Add a small random component to the velocity. The component is too # small to produce any visible result. It is added to avoid a bug in # the obstacle avoidance behavior: if a vehicle heads precisely # toward an obstacle then the surface normal at the point of # collision on the surface of the obstacle is parallel to the forward # direction of the vehicle. So the perpendicular component of the # surface normal to the vehicle's forward direction is zero, and hence # the steering force is zero, and the vehicle plows straight into the # obstacle. With a random element to the vehicle's velocity, this # precise situation will not exist for consecutive simulation frames. x = (random.random()-0.5)*0.01 y = (random.random()-0.5)*0.01 self._velocity.setX(self._velocity.getX()+self._velocity.getX()*x) self._velocity.setY(self._velocity.getY()+self._velocity.getY()*y) # Update vehicle's position. self._pos += self._velocity*(dt*50) self._enforceNonPenetrationConstraint() # Fluidly update the NodePath's X and Y positions to match self._pos. # Leave the NodePath's Z-axis position untouched (that is taken care of # by CollisionHandlerFloor). self.prime.setFluidPos(self._pos.getX(),self._pos.getY(), self.prime.getZ()) # Update the Vehicles's CollisionTube, varying the length of the tube # according to the Vehicle's speed. ##zuck ###tube=self.tubenp.node().getSolid(0) tube=self.tubenp.node().modifySolid(0) tube.setPointB(Point3( tube.getPointA()+Point3(0,15.*self._velocity.length(),0))) self._prevtime = task.time return Task.cont def _enforceNonPenetrationConstraint(self): """Forcibly prevent this vehicle from penetrating obstacles. Based on advice from Craig Reynolds: The obstacle and vehicle are both assumed to be spheres. Measure the distance between their centers. If this is less than the sum of their radii the two spheres intersect. If so, simply "slide" (that is, SET the position of) the vehicle along the line connecting their centers the distance by which they overlap. See code here: http://sourceforge.net/forum/message.php?msg_id=3928822 """ # Handle collisions with obstacles. obstacleHandler.sortEntries() for i in range(obstacleHandler.getNumEntries()): entry = obstacleHandler.getEntry(i) if entry.getInto() == self.sphere: other = entry.getFrom() pos = other.getCenter() pos = SteerVec(pos.getX(),pos.getY()) s = self.radius + other.getRadius() overlap = self._pos-pos d = overlap.length() if d>0: s = (s-d)/d overlap *= s self._pos += overlap return # Handle collisions with other vehicles. collisionHandler.sortEntries() for i in range(collisionHandler.getNumEntries()): entry = collisionHandler.getEntry(i) # FIXME: The collisionmasks in this module aren't quite right. # Want Vehicle.sphere to collide with other Vehicle.sphere's and # with obstacles.py/SphereObstacle's, and want Vehicle.tube to # collide with obstacles.py/SphereObstacle's, but we don't want # Vehicle.sphere to collide with the Vehicle.tube of another # vehicle! (or vice-versa) # For now just check for the unwanted tube collisions and ignore # them. if isinstance(entry.getInto(),CollisionTube): continue if entry.getFrom() == self.sphere: pos = entry.getIntoNodePath().getPos(render) pos = SteerVec(pos.getX(),pos.getY()) s = self.radius + entry.getInto().getRadius() overlap = self._pos-pos d = overlap.length() if d>0: s = (s-d)/d overlap *= s self._pos += overlap if self.callout['text'] == '': self.callout['text'] = random.choice(["Ouch!","Sorry!","Hey!"]) self.callout.show() return self.callout['text']='' self.callout.hide()
class UsersFrm(GameObject): def __init__(self, menu_args, yorg_srv): GameObject.__init__(self) self.eng.log('create users form') self.ver_check = VersionChecker() self.yorg_srv = yorg_srv self.room_name = None self.labels = [] self.invited_users = [] self.menu_args = menu_args lab_args = menu_args.label_args lab_args['scale'] = .046 self.users_lab = DirectLabel(text=_('Current online users'), pos=(-.85, 1, -.02), hpr=(0, 0, -90), parent=base.a2dTopRight, text_align=TextNode.A_right, **lab_args) self.frm = DirectScrolledFrame( frameSize=(-.02, .8, .45, 2.43), canvasSize=(-.02, .76, -.08, 3.8), scrollBarWidth=.036, verticalScroll_relief=FLAT, verticalScroll_frameColor=(.2, .2, .2, .4), verticalScroll_thumb_relief=FLAT, verticalScroll_thumb_frameColor=(.8, .8, .8, .6), verticalScroll_incButton_relief=FLAT, verticalScroll_incButton_frameColor=(.8, .8, .8, .6), verticalScroll_decButton_relief=FLAT, verticalScroll_decButton_frameColor=(.8, .8, .8, .6), horizontalScroll_relief=FLAT, frameColor=(.2, .2, .2, .5), pos=(-.82, 1, -2.44), parent=base.a2dTopRight) self.conn_lab = DirectLabel(text='', pos=(.38, 1, 1.5), parent=self.frm, text_wordwrap=10, **lab_args) self.set_connection_label() self.in_match_room = None self.invited = False def show(self): self.frm.show() self.users_lab.show() def hide(self): self.frm.hide() self.users_lab.hide() def set_connection_label(self): lab_args = self.menu_args.label_args lab_args['scale'] = .046 txt = '' if not self.ver_check.is_uptodate(): txt = _("Your game isn't up-to-date, please update") elif not self.eng.xmpp.client: txt = _("You aren't logged in") elif not self.eng.xmpp.is_server_up: txt = _("Yorg's server isn't running") self.conn_lab['text'] = txt def set_size(self, full=True): if full: self.frm.setPos(-.82, 1, -2.44) self.frm['frameSize'] = (-.02, .8, .45, 2.43) else: self.frm.setPos(-.82, 1, -1.97) self.frm['frameSize'] = (-.02, .8, .45, 1.96) @staticmethod def trunc(name, lgt): if len(name) > lgt: return name[:lgt] + '...' return name def on_users(self): self.set_connection_label() bare_users = [ self.trunc(user.name, 20) for user in self.eng.xmpp.users_nodup ] for lab in self.labels[:]: _lab = lab.lab.lab['text'].replace('\1smaller\1', '').replace('\2', '') if _lab not in bare_users: if _lab not in self.eng.xmpp.client.client_roster.keys(): lab.destroy() self.labels.remove(lab) nusers = len(self.eng.xmpp.users_nodup) invite_btn = len(self.invited_users) < 8 invite_btn = invite_btn and not self.in_match_room and not self.invited top = .08 * nusers + .08 self.frm['canvasSize'] = (-.02, .76, 0, top) label_users = [lab.lab.lab['text'] for lab in self.labels] clean = lambda n: n.replace('\1smaller\1', '').replace('\2', '') label_users = map(clean, label_users) for i, user in enumerate(self.eng.xmpp.users_nodup): usr_inv = invite_btn and user.is_in_yorg if self.trunc(user.name, 20) not in label_users: if self.eng.xmpp.client.boundjid.bare != user.name: lab = UserFrmList(self.trunc(user.name, 20), user, user.is_supporter, user.is_online, self.eng.xmpp.is_friend(user.name), user.is_in_yorg, user.is_playing, (0, 1, top - .08 - .08 * i), self.frm.getCanvas(), self.menu_args) else: lab = UserFrmListMe(self.trunc(user.name, 20), user, user.is_supporter, (0, 1, top - .08 - .08 * i), self.frm.getCanvas(), self.menu_args) self.labels += [lab] lab.attach(self.on_invite) lab.attach(self.on_friend) lab.attach(self.on_unfriend) lab.attach(self.on_add_chat) for i, user in enumerate(self.eng.xmpp.users_nodup): clean = lambda n: n.replace('\1smaller\1', '').replace('\2', '') lab = [ lab for lab in self.labels if clean(lab.lab.lab['text']) == self.trunc(user.name, 20) ][0] enb_val = usr_inv and user.name not in self.invited_users and user.is_in_yorg and not user.is_playing and self.eng.upnp if hasattr(lab, 'invite_btn'): inv_btn = lab.invite_btn if enb_val: inv_btn.tooltip['text'] = _('invite the user to a match') elif len(self.invited_users) == 8: inv_btn.tooltip['text'] = _( "you can't invite more players") elif self.in_match_room: inv_btn.tooltip['text'] = _("you're already in a match") elif not user.is_in_yorg: inv_btn.tooltip['text'] = _("the user isn't playing yorg") elif user.name in self.invited_users: inv_btn.tooltip['text'] = _( "you've already invited this user") elif user.is_playing: inv_btn.tooltip['text'] = _( "the user is already playing a match") elif not self.eng.upnp: inv_btn.tooltip['text'] = _("can't set UPnP") lab.enable_invite_btn(enb_val) lab.frm.set_z(top - .08 - .08 * i) lab.lab.set_supporter(user.is_supporter) lab.lab.set_online(user.is_online) def on_invite(self, usr): self.notify('on_invite', usr) if not (self.eng.server.public_addr and self.eng.server.local_addr): return self.invited_users += [usr.name] self.on_users() if not self.room_name: jid = self.eng.xmpp.client.boundjid time_code = strftime('%y%m%d%H%M%S') srv = self.eng.xmpp.client.conf_srv self.room_name = 'yorg' + jid.user + time_code + '@' + srv self.eng.xmpp.client.plugin['xep_0045'].joinMUC( self.room_name, self.eng.xmpp.client.boundjid.bare, pfrom=self.eng.xmpp.client.boundjid.full) cfg = self.eng.xmpp.client.plugin['xep_0045'].getRoomConfig( self.room_name) values = cfg.get_values() values['muc#roomconfig_publicroom'] = False cfg.set_values(values) self.eng.xmpp.client.plugin['xep_0045'].configureRoom( self.room_name, cfg) self.eng.log('created room ' + self.room_name) for usr_name in [self.yorg_srv] + \ [_usr.name_full for _usr in self.eng.xmpp.users if _usr.is_in_yorg]: self.eng.xmpp.client.send_message( mfrom=self.eng.xmpp.client.boundjid.full, mto=usr_name, mtype='ya2_yorg', msubject='is_playing', mbody='1') self.eng.xmpp.client.send_message( mfrom=self.eng.xmpp.client.boundjid.full, mto=usr.name_full, mtype='ya2_yorg', msubject='invite', mbody=self.room_name + '\n' + self.eng.server.public_addr + '\n' + self.eng.server.local_addr) self.eng.log('invited ' + str(usr.name_full)) self.notify('on_add_groupchat', self.room_name, usr.name) def on_declined(self, msg): self.eng.log('declined from ' + str(JID(msg['from']).bare)) usr = str(JID(msg['from']).bare) self.invited_users.remove(usr) self.on_users() def on_add_chat(self, msg): self.notify('on_add_chat', msg) def on_logout(self): map(lambda lab: lab.destroy(), self.labels) self.labels = [] def on_friend(self, usr_name): self.eng.log('send friend to ' + usr_name) self.eng.xmpp.client.send_presence_subscription( usr_name, ptype='subscribe', pfrom=self.eng.xmpp.client.boundjid.full) def on_unfriend(self, usr): self.eng.log('roster ' + str(self.eng.xmpp.client.client_roster)) self.eng.xmpp.client.del_roster_item(usr) self.eng.log('roster ' + str(self.eng.xmpp.client.client_roster)) def destroy(self): self.eng.log('destroyed usersfrm') self.frm = self.frm.destroy() GameObject.destroy(self)
class GUI: def __init__(self, USERNAME, rootParent=None): self.pg149 = DirectLabel( frameSize=(-1.149999976158142, 1.25, -0.11250001192092896, 0.7250000238418579), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(0, 0, 0.525), scale=LVecBase3f(0.1, 0.1, 0.1), text='Top', text_align=TextNode.A_center, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(0, 0, 0, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=rootParent, ) self.pg149.setTransparency(0) self.pg1336 = DirectScrolledList( forceHeight=0.1, frameSize=(-0.5, 0.5, -0.01, 0.75), hpr=LVecBase3f(0, 0, 0), numItemsVisible=5, pos=LPoint3f(0.025, 0, -0.25), state='normal', text='scrolled list', decButton_borderWidth=(0.005, 0.005), decButton_hpr=LVecBase3f(0, 0, 0), decButton_pos=LPoint3f(-0.45, 0, 0.03), decButton_state='disabled', decButton_text='Prev', decButton_text_align=TextNode.A_left, decButton_text_scale=(0.05, 0.05), decButton_text_pos=(0, 0), decButton_text_fg=LVecBase4f(0, 0, 0, 1), decButton_text_bg=LVecBase4f(0, 0, 0, 0), decButton_text_wordwrap=None, incButton_borderWidth=(0.005, 0.005), incButton_hpr=LVecBase3f(0, 0, 0), incButton_pos=LPoint3f(0.45, 0, 0.03), incButton_state='disabled', incButton_text='Next', incButton_text_align=TextNode.A_right, incButton_text_scale=(0.05, 0.05), incButton_text_pos=(0, 0), incButton_text_fg=LVecBase4f(0, 0, 0, 1), incButton_text_bg=LVecBase4f(0, 0, 0, 0), incButton_text_wordwrap=None, itemFrame_frameColor=(1, 1, 1, 1), itemFrame_frameSize=(-0.47, 0.47, -0.5, 0.1), itemFrame_hpr=LVecBase3f(0, 0, 0), itemFrame_pos=LPoint3f(0, 0, 0.6), text_align=TextNode.A_center, text_scale=(0.1, 0.1), text_pos=(0, 0.015), text_fg=LVecBase4f(0, 0, 0, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=rootParent, ) self.pg1336.setTransparency(0) self.pg1693 = DirectScrolledListItem( frameSize=(-3.831250286102295, 3.9062500953674317, -0.21250001192092896, 0.85), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(0, 0, 0), scale=LVecBase3f(0.1, 0.1, 0.1), state='disabled', text='Admin', text_align=TextNode.A_center, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(0, 0, 0, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=self.pg1336, command=base.messenger.send, extraArgs=['select_list_item_changed'], ) self.pg1693.setTransparency(0) self.pg1715 = DirectScrolledListItem( frameSize=(-3.831250286102295, 3.9062500953674317, -0.21250001192092896, 0.85), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(0, 0, -0.1), scale=LVecBase3f(0.1, 0.1, 0.1), text='NFSMW', text_align=TextNode.A_center, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(0, 0, 0, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=self.pg1336, command=base.messenger.send, extraArgs=['select_list_item_changed'], ) self.pg1715.setTransparency(0) self.pg1740 = DirectScrolledListItem( frameSize=(-3.831250286102295, 3.9062500953674317, -0.21250001192092896, 0.85), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(0, 0, -0.2), scale=LVecBase3f(0.1, 0.1, 0.1), text='|X_X|', text_align=TextNode.A_center, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(0, 0, 0, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=self.pg1336, command=base.messenger.send, extraArgs=['select_list_item_changed'], ) self.pg1740.setTransparency(0) self.pg1768 = DirectScrolledListItem( frameSize=(-3.831250286102295, 3.9062500953674317, -0.21250001192092896, 0.85), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(0, 0, -0.3), scale=LVecBase3f(0.1, 0.1, 0.1), text=USERNAME, text_align=TextNode.A_center, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(0, 0, 0, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=self.pg1336, command=base.messenger.send, extraArgs=['select_list_item_changed'], ) self.pg1768.setTransparency(0) self.pg1799 = DirectScrolledListItem( frameSize=(-3.831250286102295, 3.9062500953674317, -0.21250001192092896, 0.85), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(0, 0, -0.4), scale=LVecBase3f(0.1, 0.1, 0.1), text='.___.', text_align=TextNode.A_center, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(0, 0, 0, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=self.pg1336, command=base.messenger.send, extraArgs=['select_list_item_changed'], ) self.pg1799.setTransparency(0) self.pg1336.addItem(self.pg1693) self.pg1336.addItem(self.pg1715) self.pg1336.addItem(self.pg1740) self.pg1336.addItem(self.pg1768) self.pg1336.addItem(self.pg1799) def show(self): self.pg149.show() self.pg1336.show() def hide(self): self.pg149.hide() self.pg1336.hide() def destroy(self): self.pg149.destroy() self.pg1336.destroy()
class PlayerHUD(): def __init__(self): # # Player status section # heartscale = (0.1, 1, 0.1) self.heart1 = OnscreenImage( image = "HeartIcon.png", scale = heartscale, pos = (0.2, 0, -0.15)) self.heart1.setTransparency(True) self.heart1.reparentTo(base.a2dTopLeft) self.heart2 = OnscreenImage( image = "HeartIcon.png", scale = heartscale, pos = (0.45, 0, -0.15)) self.heart2.setTransparency(True) self.heart2.reparentTo(base.a2dTopLeft) self.heart3 = OnscreenImage( image = "HeartIcon.png", scale = heartscale, pos = (0.7, 0, -0.15)) self.heart3.setTransparency(True) self.heart3.reparentTo(base.a2dTopLeft) self.keys = DirectLabel( text = "x0", frameColor = (0, 0, 0, 0), text_fg = (1, 1, 1, 1), text_scale = 1.8, text_pos = (1, -0.25, 0), text_align = TextNode.ALeft, image = "Keys.png", pos = (0.2, 0, -0.4)) self.keys.setScale(0.085) self.keys.setTransparency(True) self.keys.reparentTo(base.a2dTopLeft) self.actionKey = DirectLabel( frameColor = (0, 0, 0, 0), text_fg = (1, 1, 1, 1), scale = 0.15, pos = (0, 0, 0.15), text = _("Action: E/Enter")) self.actionKey.setTransparency(True) self.actionKey.reparentTo(base.a2dBottomCenter) self.actionKey.hide() def show(self): self.keys.show() def hide(self): self.heart1.hide() self.heart2.hide() self.heart3.hide() self.keys.hide() self.hideActionKey() def setHealthStatus(self, value): """this function will set the health image in the top righthand corner according to the given value, where value is a integer between 0 and 100 """ if value >= 1: self.heart1.show() else: self.heart1.hide() if value >= 2: self.heart2.show() else: self.heart2.hide() if value >= 3: self.heart3.show() else: self.heart3.hide() def showActionKey(self): self.actionKey.show() def hideActionKey(self): self.actionKey.hide() def updateKeyCount(self, numKeys): self.keys["text"] = "x%d" % numKeys
class GUI_3: def __init__(self, rootParent=None): self.pg149 = DirectLabel( frameSize=(-3.15, 3.25, -0.113, 0.725), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(0, 0, 0.525), scale=LVecBase3f(0.1, 0.1, 0.1), text='Moderators', text_align=TextNode.A_center, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(0, 0, 0, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=rootParent, ) self.pg149.setTransparency(0) self.pg422 = DirectScrolledList( forceHeight=0.1, scale=LVecBase3f(10, 10, 10), frameSize=(-0.5, 0.5, -0.01, 0.75), hpr=LVecBase3f(0, 0, 0), numItemsVisible=5, pos=LPoint3f(0, 0, -7.9), state='normal', text='', decButton_borderWidth=(0.005, 0.005), decButton_hpr=LVecBase3f(0, 0, 0), decButton_pos=LPoint3f(-0.45, 0, 0.03), decButton_state='disabled', decButton_text='Prev', decButton_text_align=TextNode.A_left, decButton_text_scale=(0.05, 0.05), decButton_text_pos=(0, 0), decButton_text_fg=LVecBase4f(0, 0, 0, 1), decButton_text_bg=LVecBase4f(0, 0, 0, 0), decButton_text_wordwrap=None, incButton_borderWidth=(0.005, 0.005), incButton_hpr=LVecBase3f(0, 0, 0), incButton_pos=LPoint3f(0.45, 0, 0.03), incButton_state='disabled', incButton_text='Next', incButton_text_align=TextNode.A_right, incButton_text_scale=(0.05, 0.05), incButton_text_pos=(0, 0), incButton_text_fg=LVecBase4f(0, 0, 0, 1), incButton_text_bg=LVecBase4f(0, 0, 0, 0), incButton_text_wordwrap=None, itemFrame_frameColor=(1, 1, 1, 1), itemFrame_frameSize=(-0.47, 0.47, -0.5, 0.1), itemFrame_hpr=LVecBase3f(0, 0, 0), itemFrame_pos=LPoint3f(0, 0, 0.6), text_align=TextNode.A_center, text_scale=(0.1, 0.1), text_pos=(0, 0.015), text_fg=LVecBase4f(0, 0, 0, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=self.pg149, ) self.pg422.setTransparency(0) self.pg1117 = DirectScrolledListItem( frameSize=(-3.831250286102295, 3.9062500953674317, -0.21250001192092896, 0.85), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(0, 0, 0), scale=LVecBase3f(0.1, 0.1, 0.1), state='disabled', text='Marcic_Admin', text_align=TextNode.A_center, text_scale=(1, 1), text_pos=(0, 0), text_fg=LVecBase4f(0, 0, 0, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=self.pg422, command=base.messenger.send, extraArgs=['select_list_item_changed'], ) self.pg1118 = DirectScrolledListItem( frameSize=(-3.831250286102295, 3.9062500953674317, -0.21250001192092896, 0.85), hpr=LVecBase3f(0, 0, 0), pos=LPoint3f(0, 0, 0), scale=LVecBase3f(0.1, 0.1, 0.1), state='disabled', text='panda3dmastercoder', text_align=TextNode.A_center, text_scale=(0.8, 1), text_pos=(0, 0), text_fg=LVecBase4f(0, 0, 0, 1), text_bg=LVecBase4f(0, 0, 0, 0), text_wordwrap=None, parent=self.pg422, command=base.messenger.send, extraArgs=['select_list_item_changed'], ) self.pg1117.setTransparency(0) self.pg422.addItem(self.pg1117) self.pg422.addItem(self.pg1118) def show(self): self.pg149.show() def hide(self): self.pg149.hide() def destroy(self): self.pg149.destroy()