September 25, 2019

Pyglet hello world program

According to different internet websites, a potential alternative for the pygame library is the pyglet framework. It's a bit harder to use, the number of tutorials is lower but the performance is much better. In pygame, the general problem is, that even a slow framerate results into an application which consumes many CPU ressources. Pyglet allows similar to a C program direct access to the OpenGL interface which improves the performance. Additionally, there is a feature available called batch, which is useful for particle simulation in which hundreds of verticies are drawn at the same time.

It's unsure, if pyglet can replace the famous pygame library. Because it's very new, and the information are spread over different stackoverflow entries. For testing out the capabilities, a small hello world program make sense, which draws a line, a sprite and asks for keyboard input. From the performance side, it's much better than pygame. The window consums nearly zero CPU ressources, it's on the same level like a game written in fast C++ with the SFML library. A short look into the sourcecode shows, that pyglet is a bit tricky to use. The first thing which is important is to inherit a window, and secondly, the manipulation of the colors is complicated too. The hope is, that in larger programs, it will become easier to use, because the drawing primitives can be capsuled in subfunctions. What we can say for sure, is that the program written in Python is much easier to write, than the same App written in C++, Java or C.



#!/usr/bin/env python3
import pyglet
from pyglet.window import key

class GameWindow(pyglet.window.Window):
  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.pos=(200,200)
    self.angle=0
    self.movement=20
    imagetrain = pyglet.resource.image('locomotive.png')
    self.spritetrain = pyglet.sprite.Sprite(imagetrain)
    self.label = pyglet.text.Label('Hello, world',x=100,y=100,color=(100,100,255,255))
  def on_mouse_press(self, x, y, button, modifiers):
    pass
  def on_mouse_release(self, x, y, button, modifiers):
    pass
  def on_mouse_motion(self, x, y, dx, dy):
    pass
    #print("move mouse")
  def on_key_press(self, symbol, modifiers):
    #print("key was pressed",symbol)
    if symbol == key.A: self.angle-=10
    elif symbol == key.B: self.angle+=10
    elif symbol == key.ENTER: pass
    elif symbol == key.LEFT: 
      self.pos=(self.pos[0]-self.movement,self.pos[1])
    elif symbol == key.RIGHT: 
      self.pos=(self.pos[0]+self.movement,self.pos[1])
    elif symbol == key.UP: 
      self.pos=(self.pos[0],self.pos[1]+self.movement)
    elif symbol == key.DOWN: 
      self.pos=(self.pos[0],self.pos[1]-self.movement)
    self.spritetrain.update(x=self.pos[0],y=self.pos[1],rotation=self.angle)
  def update(self, dt):
    pass
    
  def on_draw(self):
    self.clear()  
    pyglet.gl.glClearColor(1,1,1,1)
    pyglet.graphics.draw(2,pyglet.gl.GL_LINES,
      ('v2i', (10, 15, 130, 135)),
      ('c3B', (100,100,255)*2), # one color per vertex
    )
    self.spritetrain.draw()
    self.label.draw() 

if __name__ == "__main__":
  window = GameWindow(600, 400, "pyglet",resizable=False)
  pyglet.clock.schedule_interval(window.update, 1/30.0)
  pyglet.app.run() 


Update

In a second version of the program, a dedicated class for the physics state was created. This simplified the programming a bit. The remaining commands for drawing the lines and the sprites will become easier, because once the code is written, it will draw all the elements to the screen.

Secondly, it was measured the exact cpu consumption. For 100 frames per second, the GUI app needs 15% of the totai CPU.

ps -p 31339 -o %cpu,%mem,cmd
%CPU %MEM CMD
15.1  1.3 python3 1.py

If the framerate is increased to 200 fps, the cpu consumption is 18%. It's important to know, that the only objects on the screen, are one sprite, one line and a small “hello world” text. It seems, that Python programs in general are running slow? No, that is not the case. Because a program written in high speed C++ with the SFML library has the same performance problems. It seems, that the requirements of updating the screen 200 times per second is too much for computers in general. No matter in which programming language the code was written.