- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我实际上是在用头撞墙(就像,是的,在 body 上,在我当前的位置,我正在损坏我的颅骨)。基本上,我有一个 Python/Pygame 游戏,带有一些典型的游戏“房间”或“屏幕”。 EG标题画面、高分画面、以及实际的游戏室。当我在房间之间切换时,发生了一些不好的事情:旧房间(及其各种项目)没有从内存或我的事件监听器中删除。不仅如此,每次我回到某个房间时,我的事件监听器数量都会增加,并且消耗的 RAM 也会增加!(因此,如果我在标题屏幕和例如“游戏室”,事件监听器的数量和内存使用量不断增加。
主要问题是所有事件监听器开始累积并真正耗尽 CPU。我是 Python 新手,不知道我是否在这里做了一些明显错误的事情,或者是什么。
如果你能帮助我,我会非常爱你!
下面是相关源码。完整源代码位于http://www.necessarygames.com/my_games/betraveled/betraveled_src0328.zip(需要Python 2.6 + Pygame 1.9)
MAIN.PY
class RoomController(object):
"""Controls which room is currently active (eg Title Screen)"""
def __init__(self, screen, ev_manager):
self.room = None
self.screen = screen
self.ev_manager = ev_manager
self.ev_manager.register_listener(self)
self.room = self.set_room(config.room)
def set_room(self, room_const):
#Unregister old room from ev_manager
if self.room:
self.room.ev_manager.unregister_listener(self.room)
self.room = None
#Set new room based on const
if room_const == config.TITLE_SCREEN:
return rooms.TitleScreen(self.screen, self.ev_manager)
elif room_const == config.GAME_MODE_ROOM:
return rooms.GameModeRoom(self.screen, self.ev_manager)
elif room_const == config.GAME_ROOM:
return rooms.GameRoom(self.screen, self.ev_manager)
elif room_const == config.HIGH_SCORES_ROOM:
return rooms.HighScoresRoom(self.screen, self.ev_manager)
def notify(self, event):
if isinstance(event, ChangeRoomRequest):
if event.game_mode:
config.game_mode = event.game_mode
self.room = self.set_room(event.new_room)
#Run game
def main():
pygame.init()
screen = pygame.display.set_mode(config.screen_size)
ev_manager = EventManager()
spinner = CPUSpinnerController(ev_manager)
room_controller = RoomController(screen, ev_manager)
pygame_event_controller = PyGameEventController(ev_manager)
spinner.run()
EVENT_MANAGER.PY
class EventManager:
#This object is responsible for coordinating most communication
#between the Model, View, and Controller.
def __init__(self):
from weakref import WeakKeyDictionary
self.last_listeners = {}
self.listeners = WeakKeyDictionary()
self.eventQueue= []
self.gui_app = None
#----------------------------------------------------------------------
def register_listener(self, listener):
self.listeners[listener] = 1
#----------------------------------------------------------------------
def unregister_listener(self, listener):
if listener in self.listeners:
del self.listeners[listener]
#----------------------------------------------------------------------
def clear(self):
del self.listeners[:]
#----------------------------------------------------------------------
def post(self, event):
# if isinstance(event, MouseButtonLeftEvent):
# debug(event.name)
#NOTE: copying the list like this before iterating over it, EVERY tick, is highly inefficient,
#but currently has to be done because of how new listeners are added to the queue while it is running
#(eg when popping cards from a deck). Should be changed. See: http://dr0id.homepage.bluewin.ch/pygame_tutorial08.html
#and search for "Watch the iteration"
print 'Number of listeners: ' + str(len(self.listeners))
for listener in list(self.listeners):
#NOTE: If the weakref has died, it will be
#automatically removed, so we don't have
#to worry about it.
listener.notify(event)
def notify(self, event):
pass
#------------------------------------------------------------------------------
class PyGameEventController:
"""..."""
def __init__(self, ev_manager):
self.ev_manager = ev_manager
self.ev_manager.register_listener(self)
self.input_freeze = False
#----------------------------------------------------------------------
def notify(self, incoming_event):
if isinstance(incoming_event, UserInputFreeze):
self.input_freeze = True
elif isinstance(incoming_event, UserInputUnFreeze):
self.input_freeze = False
elif isinstance(incoming_event, TickEvent) or isinstance(incoming_event, BoardCreationTick):
#Share some time with other processes, so we don't hog the cpu
pygame.time.wait(5)
#Handle Pygame Events
for event in pygame.event.get():
#If this event manager has an associated PGU GUI app, notify it of the event
if self.ev_manager.gui_app:
self.ev_manager.gui_app.event(event)
#Standard event handling for everything else
ev = None
if event.type == QUIT:
ev = QuitEvent()
elif event.type == pygame.MOUSEBUTTONDOWN and not self.input_freeze:
if event.button == 1: #Button 1
pos = pygame.mouse.get_pos()
ev = MouseButtonLeftEvent(pos)
elif event.type == pygame.MOUSEBUTTONDOWN and not self.input_freeze:
if event.button == 2: #Button 2
pos = pygame.mouse.get_pos()
ev = MouseButtonRightEvent(pos)
elif event.type == pygame.MOUSEBUTTONUP and not self.input_freeze:
if event.button == 2: #Button 2 Release
pos = pygame.mouse.get_pos()
ev = MouseButtonRightReleaseEvent(pos)
elif event.type == pygame.MOUSEMOTION:
pos = pygame.mouse.get_pos()
ev = MouseMoveEvent(pos)
#Post event to event manager
if ev:
self.ev_manager.post(ev)
# elif isinstance(event, BoardCreationTick):
# #Share some time with other processes, so we don't hog the cpu
# pygame.time.wait(5)
#
# #If this event manager has an associated PGU GUI app, notify it of the event
# if self.ev_manager.gui_app:
# self.ev_manager.gui_app.event(event)
#------------------------------------------------------------------------------
class CPUSpinnerController:
def __init__(self, ev_manager):
self.ev_manager = ev_manager
self.ev_manager.register_listener(self)
self.clock = pygame.time.Clock()
self.cumu_time = 0
self.keep_going = True
#----------------------------------------------------------------------
def run(self):
if not self.keep_going:
raise Exception('dead spinner')
while self.keep_going:
time_passed = self.clock.tick()
fps = self.clock.get_fps()
self.cumu_time += time_passed
self.ev_manager.post(TickEvent(time_passed, fps))
if self.cumu_time >= 1000:
self.cumu_time = 0
self.ev_manager.post(SecondEvent(fps=fps))
pygame.quit()
#----------------------------------------------------------------------
def notify(self, event):
if isinstance(event, QuitEvent):
#this will stop the while loop from running
self.keep_going = False
使用事件管理器的示例类
class Timer(object):
def __init__(self, ev_manager, time_left):
self.ev_manager = ev_manager
self.ev_manager.register_listener(self)
self.time_left = time_left
self.paused = False
def __repr__(self):
return str(self.time_left)
def pause(self):
self.paused = True
def unpause(self):
self.paused = False
def notify(self, event):
#Pause Event
if isinstance(event, Pause):
self.pause()
#Unpause Event
elif isinstance(event, Unpause):
self.unpause()
#Second Event
elif isinstance(event, SecondEvent):
if not self.paused:
self.time_left -= 1
最佳答案
当你做这样的事情时:
return rooms.TitleScreen(self.screen, self.ev_manager)
我假设您正在创建一个新的 TitleScreen 对象。
如果这是您想要做的,那么您可能希望在切换房间时删除旧的房间对象。
def notify(self, event):
if isinstance(event, ChangeRoomRequest):
if event.game_mode:
config.game_mode = event.game_mode
del self.room // delete the old room object
self.room = self.set_room(event.new_room)
如果您希望房间持续存在,您的 set_room 函数将必须检查房间是否已创建。然后您可以创建一个新房间或智能地加载旧房间。但您还必须以某种方式跟踪这些房间。
编辑:
那么好吧。问题不在于房间,而在于听众。您在 init 上注册的每个监听器可能都应该在 del 上取消注册。我在您的 src 中搜索了“unregister_listener”,只发现它取消注册了房间监听器。
因此,当您创建 100 个按钮,然后再创建 100 个按钮而不取消注册任何监听器时,您将拥有 100 个孤立监听器。这不好。我会重载 __ del __ () 函数来删除这些监听器,就像 __ init __ () 函数添加它们一样。
这有意义吗?
关于python - python 游戏中的房间/屏幕/菜单 Controller 问题 : old rooms are not removed from memory,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2540437/
使用 Foundation 6.3.1,我希望在桌面上显示 Canvas 外菜单,在移动设备上显示 Accordion 菜单。例如 This is the desktop view with a co
function HideandUNhideObj(ThisObj) { var nav = document.getElementById(ThisObj).style if (nav.displ
我正在处理一个页面,该页面有一个显示“更新”的链接。当用户单击此链接时,我希望表单使用幻灯片效果并显示在链接下方。提交表单后,它会更新数据库,并且菜单会显示。 我知道这可以用 JavaScript 来
这是我的运行时创建菜单的关键部分: GtkWidget *menu, *menu_item; menu = gtk_menu_new(); menu_item = gtk_image_menu_ite
您好,我想实现一个像这样的 donut 菜单 http://dribbble.com/shots/610433-Wheel-Nav我知道有一种在 css3 中制作 donut 的简单方法。 .doug
我的应用程序中有一个菜单,当菜单打开时我会触发触觉反馈(来自 onTagGesture Action )。 然而 有时当我点击菜单打开触发器时,菜单实际上不会打开,但我仍然收到触觉反馈。我只在菜单实际
也许这是一个简单的解决方案,但我坚持了下来。 这里有我的代码 http://jsbin.com/ejomuv纯CSS菜单 我想要做的是在悬停时在下拉按钮底部设置 0px 边框半径,但仅在下拉菜单上设置
下拉列表、菜单和组合框都是非常常见的用户界面元素。用户习惯于在 native 应用程序和 Web 应用程序中看到这些元素,但它们存在一些问题。 您必须瞄准鼠标。当您将鼠标移开时,有些菜单会折叠,而有些
我有 codeigniter 背景。现在,我正在学习 Laravel。所以,我处于这种情况(示例),我正在尝试创建一个具有多个用户的 web 应用程序。用户类型 A ,他们可以访问菜单 a、菜单 b
我正在学习 JQuery 的基础知识,我的老师显示的 menu() 看起来根本不像我的。 这是我创建的菜单的 LAF: 代码: Hello Hi Welcome World
- SELECT - 上面的显示:none不起作用。我也尝试过“隐藏”,但没有成功。 如何隐藏此选择菜单? 最佳答案 换行与 或并将 id 添加到标签。 - SELECT
我使用 Jquery 创建菜单,如下所示: homeinfo2info3 Jquery 代码如下: $(document).ready(function(){ $(".prof_info1").unb
我是 C 新手,我需要为项目构建一个带有循环的菜单。我有两个问题。 1) 我想在 else 中添加一个字符,如果在主菜单中按“2”后询问某事,问题将是“你要去参加事件吗?”用户可以输入聊天“Y”或“N
大家好,过去几个小时我一直在为类(class)编写这个程序,但似乎无法解决最后两个问题。它基本上是一个略微修改的 CashRegister 类,通过菜单提供基本功能。我遇到的问题是: 1) 用户第一次
List studentInfo = new LinkedList(); int choice; boolean flag = true; Student student =
我正在使用 bootsrap 4 alpha 6 和 midnight.js 来更改导航菜单切换器的颜色。我想在它旁边插入一个文本(菜单)。捕获中的示例。对于文本切换器,我使用 fontawesome
我正在尝试使用 CSS 菜单解决菜单在 IE 6 中无法正确显示的问题 alt text http://content.screencast.com/users/Dokmanc/folders/Jin
我无法让这段代码工作 - 我想要的是当我将鼠标悬停在圆圈上时,菜单会出现,然后如果我将鼠标从圆圈或菜单上移开,它就会消失。我尝试做的任何事情都是非常错误的,例如 onmouseover 在圆圈上然后在
我有一个典型的 CSS 顶部导航,当您滑过不同的父菜单项时,它会显示一个子菜单。如何更改代码以保持显示事件子菜单。因此,如果您在该父菜单项或其子项之一的页面上,它将保持显示该子菜单,除非您将鼠标悬停在
我很亲近。我怎样才能在我的 上有 MENU 1。 fiddle显示为默认菜单选项,然后在 MENU 2 悬停时更改? 提前致谢。继续编码! :) 最佳答案 要根据您的响应完全远离 jquery 进行编
我是一名优秀的程序员,十分优秀!