Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pygame application runs slower on Mac than on PC

A friend and I are making a game in Python (2.7) with the Pygame module. I have mostly done the art for the game so far and he has mostly done the coding but eventually I plan to help code with him once most of the art is done. I am on a Mac (latest version of OS X) and my friend is using a PC.

He has been building and running the game from his PC and as of right now it has been working as planned in his PC (perfect 60fps). However, whenever I pull the code from GitHub (I definitely have the most updated version of our code) and I try to run the game, the game runs like half as fast.

We have tried doubling the fps to 120 in the code and it then runs twice as fast on the PC but when I pull that code on my Mac it still seemed like I was capped around 30fps.

We haven't really found any convincing answers to this problem anywhere else, however we are both pretty new to Pygame and Python so we may be missing something very obvious.

import pygame as pg
import os

os.environ['SDL_VIDEO_CENTERED'] = '1'

class Wombat:
    def __init__(self, screen_rect, image, starting_loc):
        self.screen_rect = screen_rect
        self.image = image
        self.width = 192
        self.height = 96
        self.starting_loc = starting_loc
        self.rect = self.image.get_rect(bottomleft=starting_loc)
        self.speed = 5
        self.grav = .5

        self.jumping = False
        self.y_vel = 0

    def update(self):
        self.rect.clamp_ip(self.screen_rect)
        self.jump_update()

    def render(self, screen):
        screen.blit(self.image, self.rect)

    def move(self, x, y):
        self.rect.x += x * self.speed
        self.rect.y += y * self.speed

    def jump_update(self):
        if self.jumping:
            self.y_vel += self.grav
            self.rect.y += self.y_vel
            if self.is_touching_ground():
                self.jumping = False

    def is_touching_ground(self):
        return self.rect.y >= self.screen_rect.height - self.height - 50

    def jump(self):
        if not self.jumping:
            self.y_vel = -12
            self.jumping = True


class Control:
    def __init__(self):
        self.screensize = (1000,500)
        self.screen = pg.display.set_mode(self.screensize, pg.DOUBLEBUF)
        self.screen_rect = self.screen.get_rect()
        try:
            self.bg = pg.image.load("res\\bg.png")
            self.wb11 = pg.image.load("res\BlueWombat\BlueStay.png")
            self.wb1 = pg.image.load("res\BlueWombat\BlueWalk.gif").convert_alpha()
            self.wb2 = pg.image.load("res\GreenWombat\GreenStay.png")
            self.wb21 = pg.image.load("res\GreenWombat\GreenWalk.gif")
        except:
            self.bg = pg.image.load("res/bg.png")
            self.wb1 = pg.image.load("res/BlueWombat/BlueStay.png")
            self.wb11 = pg.image.load("res/BlueWombat/BlueWalk.gif")
            self.wb2 = pg.image.load("res/GreenWombat/GreenStay.png")
            self.wb21 = pg.image.load("res/GreenWombat/GreenWalk.gif")
        self.wb2 = pg.transform.flip(self.wb2, True, False)
        self.clock = pg.time.Clock()
        self.fps = 60
        self.quit = False
        self.keys = pg.key.get_pressed()

        self.wombat_one = Wombat(self.screen_rect, self.wb1, (0,450))
        self.wombat_two = Wombat(self.screen_rect, self.wb2, (1000-192,450))

    def run(self):
        while not self.quit:
            now = pg.time.get_ticks()
            self.held_keys(self.keys)
            self.event_loop()
            self.update()
            self.render()
            pg.display.update()

            self.clock.tick(self.fps)

    def event_loop(self):
        for event in pg.event.get():
            if event.type == pg.QUIT:
                self.quit = True
            elif event.type in (pg.KEYDOWN, pg.KEYUP):
                self.keys = pg.key.get_pressed()
                if event.type == pg.KEYDOWN:
                    if event.key == pg.K_w:
                        self.wombat_one.jump()
                    if event.key == pg.K_UP:
                        self.wombat_two.jump()

    def held_keys(self, keys):
        if keys[pg.K_a]:
            self.wombat_one.move(-1, 0)
        if keys[pg.K_d]:
            self.wombat_one.move(1, 0)
        if keys[pg.K_LEFT]:
            self.wombat_two.move(-1, 0)
        if keys[pg.K_RIGHT]:
            self.wombat_two.move(1, 0)

    def render(self):
        self.screen.blit(self.bg, (0,0))
        self.wombat_one.render(self.screen)
        self.wombat_two.render(self.screen)

    def update(self):
        self.wombat_one.update()
        self.wombat_two.update()


app = Control()
app.run()
like image 229
Alex McMullen Avatar asked Jul 28 '15 19:07

Alex McMullen


2 Answers

Hey umm I had the same problem but now my pygame code runs at 60 fps which is good. I am using Idle with Python 3.6.3 and the appropriate pygame for it. Here is how I fixed it:

  1. Run your pygame program
  2. In the dock you will see a snake with controllers in his mouth. Right click him.
  3. Go to Options and click "Show in Finder"
  4. Finder will open and you will see a the python application.(Mine was in the shape of rocket with the idle symbol on it.)
  5. Right click the python application and click "Get Info".
  6. Check the box "Open in Low Resolution" and it should now run at around 60fps.
like image 111
Peter_S Avatar answered Nov 20 '22 16:11

Peter_S


I suggest you read the documentation for pygame.time.Clock and, in particular, this:

Note that this function uses SDL_Delay function which is not accurate on every platform, but does not use much cpu. Use tick_busy_loop if you want an accurate timer, and don’t mind chewing cpu.

The problem is likely due to issues with SDL_Delay() when you're calling self.clock.tick(self.fps) in the run function.

like image 2
Jack Aidley Avatar answered Nov 20 '22 16:11

Jack Aidley