Как увеличить частоту кадров (кадров в секунду) в Python + Pygame?

Я работаю над маленькой карточной игрой в мир путешествий, которую я представляю себе как нечто среднее между Bejeweled и 10-дневной настольной игрой по географии. Пока что кодирование идет хорошо, но частота кадров довольно плохая... в настоящее время я получаю низкий 20 на моем Core 2 Duo. Это проблема, так как я создаю игру для конкурса разработчиков Intel March, которая прямо нацелена на нетбуки, упаковывающие маломощные процессоры Atom.

Вот скрин из игры:

alt text
(источник: requiredgames.com)

Я очень плохо знаком с Python и Pygame (это первое, для чего я их использовал), и мне, к сожалению, не хватает формального обучения CS... то есть я думаю, что, вероятно, происходит ОЧЕНЬ много плохих практик. в моем коде, и много, что может быть оптимизировано. Если бы некоторые из вас, более старых разработчиков Python, не возражали бы взглянуть на мой код и посмотреть, не можете ли вы найти какие-либо очевидные области для оптимизации, я был бы чрезвычайно благодарен.

Вы можете скачать полный исходный код здесь (Python 2.6 + Pygame 1.9): http://www.neededgames.com/my_games/betraveled/betraveled_src0328.zip

Скомпилированный exe здесь: www.neededgames.com/my_games/betraveled/betraveled_src0328.zip

Одна вещь, которая меня беспокоит, - это мой менеджер событий, который, я чувствую, может иметь некоторую производительность, а другая вещь - мой рендеринг... Я почти все время просто перетаскиваю все на экран (см. Процедуры рендеринга). в моем game_components.py ниже); Недавно я обнаружил, что вам следует обновлять только те области экрана, которые изменились, но я все еще сомневаюсь, как именно это достигнуто... может ли это быть огромной проблемой производительности?

Любые мысли очень ценятся! Как обычно, я рад сообщить вам о вашем времени и энергии через PayPal.

Иордания



РЕДАКТИРОВАТЬ: Благодаря совету ниже, я запустил cprofile на моем коде. Было бы здорово, если бы кто-нибудь захотел взглянуть на этот вывод и сообщить мне, что есть, а чего нет.



Вот вывод p.strip_dirs(). Sort_stats ("накопительный"). Print_stats():

pydev debugger: starting

Sun Mar 28 04:46:16 2010    cprofile

         8383715 function calls (8264821 primitive calls) in 157.732 CPU seconds

   Ordered by: cumulative time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000  157.732  157.732 <string>:1(<module>)
        1    0.000    0.000  157.732  157.732 main.py:47(main)
        1    0.074    0.074  157.280  157.280 event_manager.py:101(run)
4911/2414   11.837    0.002  156.984    0.065 event_manager.py:32(post)
4786/4681    0.238    0.000   94.852    0.020 rooms.py:251(notify)
     2187    0.523    0.000   51.136    0.023 rooms.py:329(render)
4911/2959    0.220    0.000   35.732    0.012 event_manager.py:54(notify)
     2271   33.996    0.015   33.996    0.015 {pygame.display.update}
     2271    0.060    0.000   23.664    0.010 app.py:178(paint)
37347/2271    1.580    0.000   23.587    0.010 container.py:83(paint)
70236/2271    3.609    0.000   23.448    0.010 theme.py:275(func)
  1078950   16.926    0.000   16.926    0.000 {method 'blit' of 'pygame.Surface' objects}
     2187    2.131    0.001   16.875    0.008 game_components.py:666(render)
19635/17756    0.187    0.000   13.852    0.001 game_components.py:641(notify)
   733820    7.710    0.000   13.643    0.000 game_components.py:1151(notify)
     2271   12.254    0.005   12.254    0.005 {pygame.time.wait}
    64112    3.174    0.000   11.252    0.000 game_components.py:1186(render)
        9    0.002    0.000   10.151    1.128 game_components.py:286(deal_new_board)
     1934    0.095    0.000    8.489    0.004 app.py:144(event)
4359/2146    0.178    0.000    8.375    0.004 container.py:112(event)
2335/2146    0.056    0.000    8.251    0.004 widget.py:346(_event)
2335/2146    0.048    0.000    8.193    0.004 theme.py:320(func)
4883/4691    0.018    0.000    8.049    0.002 widget.py:313(send)
      229    0.139    0.001    8.017    0.035 game_components.py:632(refresh_darkness)
     7258    0.499    0.000    7.844    0.001 game_components.py:963(test_close_to_trip)
     2271    7.378    0.003    7.378    0.003 {pygame.display.set_caption}
    19347    3.313    0.000    6.687    0.000 game_components.py:928(get_next_to)
     2187    1.529    0.001    6.629    0.003 game_components.py:130(render)
  2011729    5.938    0.000    5.938    0.000 {isinstance}
        3    0.000    0.000    5.906    1.969 my_gui.py:274(clicked)
   219456    3.060    0.000    5.680    0.000 surface.py:5(subsurface)
     1290    0.506    0.000    5.416    0.004 game_components.py:683(__init__)
     8748    2.891    0.000    5.340    0.001 theme.py:400(render)
    70236    2.232    0.000    4.945    0.000 theme.py:186(box)
     1357    0.097    0.000    4.391    0.003 game_components.py:742(set_image)
        9    0.054    0.006    3.450    0.383 game_components.py:209(deal_connection_matrix)
     8748    0.325    0.000    3.318    0.000 theme.py:479(paint)
     1051    0.015    0.000    3.262    0.003 game_components.py:1232(__init__)
   386467    3.148    0.000    3.148    0.000 {method 'fill' of 'pygame.Surface' objects}
   245332    2.470    0.000    3.117    0.000 game_components.py:495(get_card)
    55761    3.068    0.000    3.068    0.000 {pygame.draw.aaline}
     2271    2.968    0.001    2.968    0.001 {pygame.event.get}
        9    0.007    0.001    2.946    0.327 game_components.py:416(clone)
     2187    0.089    0.000    2.717    0.001 misc.py:28(paint)
   803701    2.483    0.000    2.497    0.000 weakref.py:302(iterkeys)
     2739    2.441    0.001    2.441    0.001 {pygame.imageext.load_extended}
     1470    1.108    0.001    2.432    0.002 game_components.py:450(set_pos)
       29    0.029    0.001    2.270    0.078 game_components.py:433(clear)
        2    0.000    0.000    2.158    1.079 main.py:22(set_room)
4911/4862    0.027    0.000    2.141    0.000 main.py:37(notify)
        1    0.000    0.000    2.099    2.099 my_gui.py:164(clicked)
        1    0.001    0.001    2.099    2.099 rooms.py:117(__init__)
     1120    0.039    0.000    1.978    0.002 game_components.py:484(place_card)
       27    0.013    0.000    1.963    0.073 game_components.py:339(merge_board_stack)
      311    0.018    0.000    1.939    0.006 game_components.py:443(remove)
      125    0.007    0.000    1.848    0.015 rooms.py:18(notify)
      224    0.003    0.000    1.806    0.008 game_components.py:721(clone)
   219456    1.638    0.000    1.638    0.000 {method 'subsurface' of 'pygame.Surface' objects}
      183    0.004    0.000    1.313    0.007 game_components.py:1240(__init__)
     4374    0.106    0.000    1.224    0.000 button.py:97(paint)
    46765    0.967    0.000    1.137    0.000 game_components.py:784(set_pos)
      229    0.109    0.000    1.111    0.005 game_components.py:594(refresh_trip)
     4076    1.076    0.000    1.076    0.000 {method 'convert_alpha' of 'pygame.Surface' objects}
        9    0.015    0.002    1.018    0.113 game_components.py:542(displace_cards)
    17496    0.360    0.000    0.953    0.000 basic.py:102(paint)
    66299    0.948    0.000    0.948    0.000 {pygame.draw.rect}
     1357    0.024    0.000    0.945    0.001 game_components.py:736(set_text)
     1357    0.052    0.000    0.917    0.001 game_components.py:841(render_text_rec)
     5815    0.455    0.000    0.881    0.000 game_components.py:1108(get_connections)
     6610    0.869    0.000    0.869    0.000 {method 'replace' of 'pygame.PixelArray' objects}
       56    0.001    0.000    0.861    0.015 game_components.py:1252(__init__)
       10    0.001    0.000    0.857    0.086 game_components.py:377(__init__)
      540    0.484    0.001    0.828    0.002 game_components.py:613(refresh_connections)
   189431    0.730    0.000    0.730    0.000 game_components.py:500(test_index_on_board)
   161329    0.632    0.000    0.727    0.000 matrix.py:33(__iter__)
   309968    0.710    0.000    0.710    0.000 {method 'get_width' of 'pygame.Surface' objects}
   308567    0.675    0.000    0.675    0.000 {method 'get_height' of 'pygame.Surface' objects}
   109626    0.646    0.000    0.670    0.000 style.py:18(__getattr__)
   241697    0.646    0.000    0.646    0.000 matrix.py:24(getitem)
    21084    0.601    0.000    0.601    0.000 {method 'render' of 'pygame.font.Font' objects}
      327    0.006    0.000    0.580    0.002 game_components.py:490(place_card_first_time)
       26    0.001    0.000    0.561    0.022 game_components.py:1259(__init__)
      166    0.002    0.000    0.536    0.003 game_components.py:608(get_longest_trip)
 1491/166    0.075    0.000    0.534    0.003 game_components.py:989(get_longest_trip)
     5702    0.533    0.000    0.533    0.000 {method 'size' of 'pygame.font.Font' objects}
        1    0.000    0.000    0.478    0.478 game_components.py:141(__init__)
        1    0.001    0.001    0.478    0.478 game_components.py:165(rebuild)
       67    0.005    0.000    0.457    0.007 game_components.py:713(change_size)
        1    0.001    0.001    0.420    0.420 game_components.py:347(change_card_size)
 1210/166    0.044    0.000    0.412    0.002 game_components.py:982(add_to_trip)
     7654    0.275    0.000    0.405    0.000 game_components.py:938(get_bounding_box)
    14969    0.101    0.000    0.385    0.000 game_components.py:1305(render)
   149709    0.341    0.000    0.341    0.000 {method 'append' of 'list' objects}
    87958    0.341    0.000    0.341    0.000 {hasattr}
     1362    0.068    0.000    0.336    0.000 textrect.py:12(render_textrect)
       30    0.001    0.000    0.301    0.010 game_components.py:1282(__init__)
    47795    0.257    0.000    0.257    0.000 game_components.py:1024(test_connection)
    14849    0.098    0.000    0.251    0.000 my_gui.py:209(notify)
    17498    0.158    0.000    0.242    0.000 basic.py:22(is_color)
    87480    0.224    0.000    0.224    0.000 {method 'set_clip' of 'pygame.Surface' objects}
        9    0.003    0.000    0.209    0.023 game_components.py:279(deal_to_blank_squares)
        1    0.114    0.114    0.208    0.208 {pygame.display.set_mode}
    56617    0.206    0.000    0.206    0.000 game_components.py:837(get_center)
       84    0.005    0.000    0.206    0.002 rooms.py:110(render)

Вот вывод p.strip_dirs(). Sort_stats ('time'). Print_stats():

Sun Mar 28 04:46:16 2010    cprofile

         8383715 function calls (8264821 primitive calls) in 157.732 CPU seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     2271   33.996    0.015   33.996    0.015 {pygame.display.update}
  1078950   16.926    0.000   16.926    0.000 {method 'blit' of 'pygame.Surface' objects}
     2271   12.254    0.005   12.254    0.005 {pygame.time.wait}
4911/2414   11.837    0.002  156.984    0.065 event_manager.py:32(post)
   733820    7.710    0.000   13.643    0.000 game_components.py:1151(notify)
     2271    7.378    0.003    7.378    0.003 {pygame.display.set_caption}
  2011729    5.938    0.000    5.938    0.000 {isinstance}
70236/2271    3.609    0.000   23.448    0.010 theme.py:275(func)
    19347    3.313    0.000    6.687    0.000 game_components.py:928(get_next_to)
    64112    3.174    0.000   11.252    0.000 game_components.py:1186(render)
   386467    3.148    0.000    3.148    0.000 {method 'fill' of 'pygame.Surface' objects}
    55761    3.068    0.000    3.068    0.000 {pygame.draw.aaline}
   219456    3.060    0.000    5.680    0.000 surface.py:5(subsurface)
     2271    2.968    0.001    2.968    0.001 {pygame.event.get}
     8748    2.891    0.000    5.340    0.001 theme.py:400(render)
   803701    2.483    0.000    2.497    0.000 weakref.py:302(iterkeys)
   245332    2.470    0.000    3.117    0.000 game_components.py:495(get_card)
     2739    2.441    0.001    2.441    0.001 {pygame.imageext.load_extended}
    70236    2.232    0.000    4.945    0.000 theme.py:186(box)
     2187    2.131    0.001   16.875    0.008 game_components.py:666(render)
   219456    1.638    0.000    1.638    0.000 {method 'subsurface' of 'pygame.Surface' objects}
37347/2271    1.580    0.000   23.587    0.010 container.py:83(paint)
     2187    1.529    0.001    6.629    0.003 game_components.py:130(render)
     1470    1.108    0.001    2.432    0.002 game_components.py:450(set_pos)
     4076    1.076    0.000    1.076    0.000 {method 'convert_alpha' of 'pygame.Surface' objects}
    46765    0.967    0.000    1.137    0.000 game_components.py:784(set_pos)
    66299    0.948    0.000    0.948    0.000 {pygame.draw.rect}
     6610    0.869    0.000    0.869    0.000 {method 'replace' of 'pygame.PixelArray' objects}
   189431    0.730    0.000    0.730    0.000 game_components.py:500(test_index_on_board)
   309968    0.710    0.000    0.710    0.000 {method 'get_width' of 'pygame.Surface' objects}
   308567    0.675    0.000    0.675    0.000 {method 'get_height' of 'pygame.Surface' objects}
   109626    0.646    0.000    0.670    0.000 style.py:18(__getattr__)
   241697    0.646    0.000    0.646    0.000 matrix.py:24(getitem)
   161329    0.632    0.000    0.727    0.000 matrix.py:33(__iter__)
    21084    0.601    0.000    0.601    0.000 {method 'render' of 'pygame.font.Font' objects}
     5702    0.533    0.000    0.533    0.000 {method 'size' of 'pygame.font.Font' objects}
     2187    0.523    0.000   51.136    0.023 rooms.py:329(render)
     1290    0.506    0.000    5.416    0.004 game_components.py:683(__init__)
     7258    0.499    0.000    7.844    0.001 game_components.py:963(test_close_to_trip)
      540    0.484    0.001    0.828    0.002 game_components.py:613(refresh_connections)
     5815    0.455    0.000    0.881    0.000 game_components.py:1108(get_connections)
    17496    0.360    0.000    0.953    0.000 basic.py:102(paint)
   149709    0.341    0.000    0.341    0.000 {method 'append' of 'list' objects}
    87958    0.341    0.000    0.341    0.000 {hasattr}
     8748    0.325    0.000    3.318    0.000 theme.py:479(paint)
     7654    0.275    0.000    0.405    0.000 game_components.py:938(get_bounding_box)
    47795    0.257    0.000    0.257    0.000 game_components.py:1024(test_connection)
4786/4681    0.238    0.000   94.852    0.020 rooms.py:251(notify)
    87480    0.224    0.000    0.224    0.000 {method 'set_clip' of 'pygame.Surface' objects}
4911/2959    0.220    0.000   35.732    0.012 event_manager.py:54(notify)
    56617    0.206    0.000    0.206    0.000 game_components.py:837(get_center)
        1    0.200    0.200    0.200    0.200 {pygame.base.quit}
19635/17756    0.187    0.000   13.852    0.001 game_components.py:641(notify)
        1    0.184    0.184    0.184    0.184 {pygame.base.init}
4359/2146    0.178    0.000    8.375    0.004 container.py:112(event)
    17498    0.158    0.000    0.242    0.000 basic.py:22(is_color)
     1358    0.151    0.000    0.151    0.000 {pygame.transform.smoothscale}
      229    0.139    0.001    8.017    0.035 game_components.py:632(refresh_darkness)
        1    0.114    0.114    0.208    0.208 {pygame.display.set_mode}
    37862    0.112    0.000    0.112    0.000 {method 'set_alpha' of 'pygame.Surface' objects}
     6561    0.111    0.000    0.195    0.000 button.py:236(paint)
      229    0.109    0.000    1.111    0.005 game_components.py:594(refresh_trip)
     4374    0.106    0.000    1.224    0.000 button.py:97(paint)
    14969    0.101    0.000    0.385    0.000 game_components.py:1305(render)
    14849    0.098    0.000    0.251    0.000 my_gui.py:209(notify)
     1357    0.097    0.000    4.391    0.003 game_components.py:742(set_image)
    24072    0.096    0.000    0.096    0.000 game_components.py:913(test_pos_on_card)
     4926    0.095    0.000    0.132    0.000 game_components.py:1292(__init__)
    33286    0.095    0.000    0.095    0.000 {range}
     1934    0.095    0.000    8.489    0.004 app.py:144(event)
     2187    0.089    0.000    2.717    0.001 misc.py:28(paint)
     2135    0.087    0.000    0.091    0.000 matrix.py:21(setitem)
     4374    0.076    0.000    0.131    0.000 button.py:182(paint)
 1491/166    0.075    0.000    0.534    0.003 game_components.py:989(get_longest_trip)
        1    0.074    0.074  157.280  157.280 event_manager.py:101(run)
      301    0.069    0.000    0.107    0.000 game_components.py:508(clear_selection)
     1362    0.068    0.000    0.336    0.000 textrect.py:12(render_textrect)
     2227    0.066    0.000    0.150    0.000 game_components.py:809(move)
     5740    0.062    0.000    0.165    0.000 misc.py:34(__setattr__)
     2271    0.060    0.000   23.664    0.010 app.py:178(paint)
2335/2146    0.056    0.000    8.251    0.004 widget.py:346(_event)
     4786    0.055    0.000    0.099    0.000 game_components.py:97(notify)
        9    0.054    0.006    3.450    0.383 game_components.py:209(deal_connection_matrix)
     1357    0.052    0.000    0.917    0.001 game_components.py:841(render_text_rec)
        5    0.052    0.010    0.052    0.010 {method 'convert' of 'pygame.Surface' objects}
2335/2146    0.048    0.000    8.193    0.004 theme.py:320(func)
 1210/166    0.044    0.000    0.412    0.002 game_components.py:982(add_to_trip)
     1120    0.039    0.000    1.978    0.002 game_components.py:484(place_card)
 2871/465    0.037    0.000    0.070    0.000 container.py:77(reupdate)
    11862    0.037    0.000    0.037    0.000 {method 'collidepoint' of 'pygame.Rect' objects}
13602/13558    0.035    0.000    0.035    0.000 {len}
     4493    0.035    0.000    0.047    0.000 button.py:71(__setattr__)





Вот несколько битов источника:

Main.py

#Remote imports
import pygame
from pygame.locals import *

#Local imports
import config
import rooms
from event_manager import *
from events import *

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)

    def render(self, surface):
        self.room.render(surface)

#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()


# this runs the main function if this script is called to run.
#  If it is imported as a module, we don't run the main function.
if __name__ == "__main__": 
    main()

event_manager.py

#Remote imports
import pygame
from pygame.locals import *

#Local imports
import config
from events import *

def debug( msg ):
    print "Debug Message: " + str(msg)

class EventManager:

    #This object is responsible for coordinating most communication
    #between the Model, View, and Controller.
    def __init__(self):
        from weakref import WeakKeyDictionary
        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 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"
        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)

#------------------------------------------------------------------------------
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):

            #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.MOUSEMOTION:
                        pos = pygame.mouse.get_pos()
                        ev = MouseMoveEvent(pos)

                #Post event to event manager
                if ev:
                    self.ev_manager.post(ev)                          

#------------------------------------------------------------------------------            
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())

        pygame.quit()


    #----------------------------------------------------------------------
    def notify(self, event):
        if isinstance(event, QuitEvent):
            #this will stop the while loop from running
            self.keep_going = False            

rooms.py

#Remote imports
import pygame

#Local imports
import config
import continents
from game_components import *
from my_gui import *
from pgu import high

class Room(object):

    def __init__(self, screen, ev_manager):
        self.screen = screen
        self.ev_manager = ev_manager
        self.ev_manager.register_listener(self)

    def notify(self, event):
        if isinstance(event, TickEvent): 
            pygame.display.set_caption('FPS: ' + str(int(event.fps)))         
            self.render(self.screen) 
            pygame.display.update()


    def get_highs_table(self):
        fname = 'high_scores.txt'
        highs_table = None
        config.all_highs = high.Highs(fname)
        if config.game_mode == config.TIME_CHALLENGE:
            if config.difficulty == config.EASY:
                highs_table = config.all_highs['time_challenge_easy']
            if config.difficulty == config.MED_DIF:
                highs_table = config.all_highs['time_challenge_med']
            if config.difficulty == config.HARD:
                highs_table = config.all_highs['time_challenge_hard']
            if config.difficulty == config.SUPER:
                highs_table = config.all_highs['time_challenge_super']                  
        elif config.game_mode == config.PLAN_AHEAD:
            pass     
        return highs_table

class TitleScreen(Room):

    def __init__(self, screen, ev_manager):
        Room.__init__(self, screen, ev_manager)

        self.background = pygame.image.load('assets/images/interface/background.jpg').convert()      
        #Initialize
        #---------------------------------------
        self.gui_form = gui.Form()
        self.gui_app = gui.App(config.gui_theme)
        self.ev_manager.gui_app = self.gui_app
        c = gui.Container(align=0,valign=0)        

        #Quit Button
        #---------------------------------------
        b = StartGameButton(ev_manager=self.ev_manager)
        c.add(b, 0, 0)    
        self.gui_app.init(c)


    def render(self, surface):
        surface.blit(self.background, (0, 0))
        #GUI
        self.gui_app.paint(surface)            

class GameModeRoom(Room):

    def __init__(self, screen, ev_manager):
        Room.__init__(self, screen, ev_manager)

        self.background = pygame.image.load('assets/images/interface/background.jpg').convert()      
        self.create_gui()

    #Create pgu gui elements
    def create_gui(self):
        #Setup
        #---------------------------------------
        self.gui_form = gui.Form()
        self.gui_app = gui.App(config.gui_theme)
        self.ev_manager.gui_app = self.gui_app
        c = gui.Container(align=0,valign=-1)        

        #Mode Relaxed Button
        #---------------------------------------
        b = GameModeRelaxedButton(ev_manager=self.ev_manager)
        self.b = b
        print b.rect

Ответ 1

Пусть события приходят к вам с event.wait

Вам действительно нужно обрабатывать каждый тик? Если нет, используйте pygame.event.wait для того, чтобы цикл вашего события обрабатывался только при входе события, и pygame.time.set_timer, если вам нужны периодические события, такие как SecondEvent.

Это означает, что вы не будете рисовать много кадров в течение секунд, когда события не появятся, но это нормально. Использование event.wait уменьшит использование ЦП и позволит вам быть отзывчивым и, вероятно, удалит необходимость в time.wait, который у вас там есть.

Не перерисовывайте всю доску с нуля каждый галочку

У вас нет Room.render каждый раз, чтобы разыгрывать фон, а значит, он должен пройти и повторно нарисовать всю доску и все карты. Сделайте это один раз. Затем у вас нет карт, которые повторно отображают себя, если они не изменят темноту или они не двигаются.

Когда карты движутся, вы должны восстановить фоновый фон, просто отравляя только фрагмент фонового рисунка, а не всего.

Передать список прямоугольников на display.update

Как только вы обновляете определенные области, вы можете передать эти области в display.update, чтобы не обновлять весь экран. Например, см. Код Solarwolf и как он отмечает грязные прямоугольники.

Ответ 2

В результатах вашего профиля:

Недавно я узнал, что вы должны только обновлять области экрана, которые изменились, но я все еще туманно, как это было сделано... может ли это быть огромной проблемой производительности?

Да. display.update и Surface.blit находятся в верхней части результатов вашего профиля. Вы сделали более миллиона бликов, примерно в 5000 тиков, что составляет до 200 бликов за каждый тик.

Кроме того, шестой результат вашего профиля display.set_caption, который, я думаю, является отображением самого FPS-счетчика? В 7 секунд 157 это не ваша основная точка доступа, но все же интересно знать.

Ответ 3

Я бы сказал, что простого ожидания 5-10 мс достаточно, чтобы серьезно снизить потребление ЦП, которое постоянно перерисовывает экран.