Pages

luni, 21 august 2017

PyGame : The pymunk python module.

First about pymunk python module:
Pymunk is an easy-to-use pythonic 2d physics library that can be used whenever you need 2d rigid body physics from Python. Perfect when you need 2d physics in your game, demo or other application!
I install it with pip and python 2.7 and I test it with one example from the official website.
The source code is this:

import sys, random
import os

description = """
---- Newton's Cradle ----
A screensaver version of Newton's Cradle with an interactive mode
/s - Run in fullscreen screensaver mode
/p #### - Display a preview of the screensaver using a window handler
/i - Interactive mode
"""

if len(sys.argv) < 2:
    print(description)
    sys.exit()

is_interactive = False
display_flags = 0
if sys.argv[1] == "/p":  # preview mode
    os.environ['SDL_VIDEODRIVER'] = 'windib'
    os.environ['SDL_WINDOWID'] = sys.argv[2]
    display_size = (100, 100)
    is_interactive = False

### We must set OS env before the pygame imports..
import pygame
from pygame.locals import *
from pygame.color import *

if sys.argv[1] == "/s":  # fullscreen screensaver mode
    display_size = (0, 0)
    is_interactive = False
    display_flags = display_flags | FULLSCREEN  # FULLSCREEN) # | DOUBLEBUF | HWSURFACE     )
elif sys.argv[1] == "/i":  # interactive
    display_size = (600, 600)
    is_interactive = True

import pymunk as pm
from pymunk import Vec2d


def drawcircle(image, colour, origin, radius, width=0):
    if width == 0:
        pygame.draw.circle(image, colour, origin, int(radius))
    else:
        if radius > 65534 / 5:
            radius = 65534 / 5
        circle = pygame.Surface([radius * 2 + width, radius * 2 + width]).convert_alpha()
        circle.fill([0, 0, 0, 0])
        pygame.draw.circle(circle, colour, [circle.get_width() / 2, circle.get_height() / 2], radius + (width / 2))
        if int(radius - (width / 2)) > 0:
            pygame.draw.circle(circle, [0, 0, 0, 0], [circle.get_width() / 2, circle.get_height() / 2],
                               abs(int(radius - (width / 2))))
        image.blit(circle, [origin[0] - (circle.get_width() / 2), origin[1] - (circle.get_height() / 2)])

def reset_bodies(space):
    for body in space.bodies:
        body.position = Vec2d(body.start_position)
        body.force = 0, 0
        body.torque = 0
        body.velocity = 0, 0
        body.angular_velocity = 0
    color = random.choice(list(THECOLORS.values()))
    for shape in space.shapes:
        shape.color = color

def main():
    pygame.init()
    screen = pygame.display.set_mode(display_size, display_flags)
    width, height = screen.get_size()

    def to_pygame(p):
        """Small hack to convert pymunk to pygame coordinates"""
        return int(p.x), int(-p.y + height)

    def from_pygame(p):
        return to_pygame(p)

    clock = pygame.time.Clock()
    running = True
    font = pygame.font.Font(None, 16)

    ### Physics stuff
    space = pm.Space()
    space.gravity = (0.0, -1900.0)
    space.damping = 0.999  # to prevent it from blowing up.
    mouse_body = pm.Body(body_type=pm.Body.KINEMATIC)

    bodies = []
    for x in range(-100, 150, 50):
        x += width / 2
        offset_y = height / 2
        mass = 10
        radius = 25
        moment = pm.moment_for_circle(mass, 0, radius, (0, 0))
        body = pm.Body(mass, moment)
        body.position = (x, -125 + offset_y)
        body.start_position = Vec2d(body.position)
        shape = pm.Circle(body, radius)
        shape.elasticity = 0.9999999
        space.add(body, shape)
        bodies.append(body)
        pj = pm.PinJoint(space.static_body, body, (x, 125 + offset_y), (0, 0))
        space.add(pj)

    reset_bodies(space)
    selected = None

    if not is_interactive:
        pygame.time.set_timer(USEREVENT + 1, 70000)  # apply force
        pygame.time.set_timer(USEREVENT + 2, 120000)  # reset
        pygame.event.post(pygame.event.Event(USEREVENT + 1))
        pygame.mouse.set_visible(False)

    while running:
        for event in pygame.event.get():
            if event.type == QUIT:
                running = False
            elif event.type == KEYDOWN and event.key == K_p:
                pygame.image.save(screen, "newtons_cradle.png")

            if event.type == pygame.USEREVENT + 1:
                r = random.randint(1, 4)
                for body in bodies[0:r]:
                    body.apply_impulse_at_local_point((-6000, 0))
            if event.type == pygame.USEREVENT + 2:
                reset_bodies(space)

            elif event.type == KEYDOWN and event.key == K_r and is_interactive:
                reset_bodies(space)
            elif event.type == KEYDOWN and event.key == K_f and is_interactive:
                r = random.randint(1, 4)
                for body in bodies[0:r]:
                    body.apply_impulse_at_local_point((-6000, 0))

            elif event.type == MOUSEBUTTONDOWN and is_interactive:
                if selected != None:
                    space.remove(selected)
                p = from_pygame(Vec2d(event.pos))
                hit = space.point_query_nearest(p, 0, pm.ShapeFilter())
                if hit != None:
                    shape = hit.shape
                    rest_length = mouse_body.position.get_distance(shape.body.position)
                    ds = pm.DampedSpring(mouse_body, shape.body, (0, 0), (0, 0), rest_length, 1000, 10)
                    space.add(ds)
                    selected = ds

            elif event.type == MOUSEBUTTONUP and is_interactive:
                if selected != None:
                    space.remove(selected)
                    selected = None

            elif event.type == KEYDOWN:
                running = False
            elif event.type == MOUSEBUTTONDOWN:
                running = False

        mpos = pygame.mouse.get_pos()
        p = from_pygame(Vec2d(mpos))
        mouse_body.position = p

        ### Clear screen
        screen.fill(THECOLORS["black"])

        ### Draw stuff
        for c in space.constraints:
            pv1 = c.a.position + c.anchor_a
            pv2 = c.b.position + c.anchor_b
            p1 = to_pygame(pv1)
            p2 = to_pygame(pv2)
            pygame.draw.aalines(screen, THECOLORS["lightgray"], False, [p1, p2])

        for ball in space.shapes:
            p = to_pygame(ball.body.position)
            drawcircle(screen, ball.color, p, int(ball.radius), 0)
            # pygame.draw.circle(screen, ball.color, p, int(ball.radius), 0)

        ### Update physics
        fps = 50
        iterations = 25
        dt = 1.0 / float(fps) / float(iterations)
        for x in range(iterations):  # 10 iterations to get a more stable simulation
            space.step(dt)

        ### Flip screen
        if is_interactive:
            screen.blit(font.render("fps: " + str(clock.get_fps()), 1, THECOLORS["white"]), (0, 0))
            screen.blit(font.render("Press left mouse button and drag to interact", 1, THECOLORS["darkgrey"]),
                        (5, height - 35))
            screen.blit(font.render("Press R to reset, any other key to quit", 1, THECOLORS["darkgrey"]),
                        (5, height - 20))

        pygame.display.flip()
        clock.tick(fps)

if __name__ == '__main__':
    sys.exit(main()

I test with this command:

C:\Python27>python.exe newtons_cradle.py /i

The result work well, see the next image: 

sâmbătă, 29 iulie 2017

PyGame : The experimental gfxdraw.

This is a tutorial about gfxdraw how to use.
Note: this is an EXPERIMENTAL feature for PyGame ( meaning this API may change, or disappear in later pygame releases).
First about this gfxdraw we can use this:
  • pygame module for drawing shapes
  • pygame.gfxdraw.pixel — place a pixel
  • pygame.gfxdraw.hline — draw a horizontal line
  • pygame.gfxdraw.vline — draw a vertical line
  • pygame.gfxdraw.rectangle — draw a rectangle
  • pygame.gfxdraw.box — draw a box
  • pygame.gfxdraw.line — draw a line
  • pygame.gfxdraw.circle — draw a circle
  • pygame.gfxdraw.arc — draw an arc
  • pygame.gfxdraw.aacircle — draw an anti-aliased circle
  • pygame.gfxdraw.filled_circle — draw a filled circle
  • pygame.gfxdraw.ellipse — draw an ellipse
  • pygame.gfxdraw.aaellipse — draw an anti-aliased ellipse
  • pygame.gfxdraw.filled_ellipse — draw a filled ellipse
  • pygame.gfxdraw.pie — draw a pie
  • pygame.gfxdraw.trigon — draw a triangle
  • pygame.gfxdraw.aatrigon — draw an anti-aliased triangle
  • pygame.gfxdraw.filled_trigon — draw a filled trigon
  • pygame.gfxdraw.polygon — draw a polygon
  • pygame.gfxdraw.aapolygon — draw an anti-aliased polygon
  • pygame.gfxdraw.filled_polygon — draw a filled polygon
  • pygame.gfxdraw.textured_polygon — draw a textured polygon
  • pygame.gfxdraw.bezier — draw a Bézier curve
Nou about the example I will use into this tutorial. Is a very simple class with an anti-aliased ellipse.
This class used pygame.gfxdraw.aaellipse , see the doc:
pygame.gfxdraw.aaellipse()
    draw an anti-aliased ellipse
      aaellipse(surface, x, y, rx, ry, color) -> None
      Draws anti aliased edges of an ellipse onto a surface.
#!/usr/bin/python

import random
import math

import pygame
from pygame.locals import *
from pygame import *
from pygame import gfxdraw

#create a math function
def linear_interp(a, b, x):
 return a*(1-x) + b*x

#a class python to show on display
class Screen():
 def __init__(self):
  pygame.init()

  self.display_flags = DOUBLEBUF
  rect = self.width, self.height = 640, 480

  if pygame.display.mode_ok(rect, self.display_flags):
   self.screen = pygame.display.set_mode(rect, self.display_flags)

 def shell_print(self,text):
  print text

 def aaellipse(self,surface, x, y, rx, ry, color):
  pygame.gfxdraw.ellipse(surface, x, y, rx, ry, color)

show = Screen()

run = 1
clock = pygame.time.Clock()

show.shell_print("test")
show.aaellipse(show.screen, x=300, y=200, rx=100, ry=60, color=(8, 8, 160))

while run:
 events = pygame.event.get()

 for event in events:
  if event.type == QUIT:
   run = 0

 pygame.display.flip()

 clock.tick(60)
To understand the class methods I used two: shell_print and aaellipse.
The shell_print is used just to print a input text to python shell.
The aaellipse take all inputs for the default pygame.gfxdraw.ellipse.
The result is a simple blue ellipse at 300 and 200 points and sized with 100 and 60.
Another aspect to note is use of the surface into show.aaellipse : show.screen.
This means that the drawing screen is used and not another defined surface.
Of course we can change Screen class to help us - decorators, other defining surfaces, initializations...

vineri, 26 mai 2017

PyGame : First interface - part 7.

Today I will start with another feature: add text from the keyboard.
The interface needs to be filled with text and a good way is to read the keyboard.
My example using this feature and print the text into one row and let you erase chars when you typing.
First, you need to know I used python version 2.7.13 and the last pygame version 1.9.2.0a from here.
I used also the PyCharm version Community Edition 2017.1.3.
Let see the source code for this example:
import pygame
from pygame.locals import *

def name():
    pygame.init()
    screen = pygame.display.set_mode((480, 360))
    name = ""
    font = pygame.font.Font(None, 50)
    while True:
        for evt in pygame.event.get():
            if evt.type == KEYDOWN:
                if evt.unicode.isalpha():
                    name += evt.unicode
                elif evt.key == K_BACKSPACE:
                    name = name[:-1]
                elif evt.key == K_SPACE:
                    name = name+str(" ")
            elif evt.type == QUIT:
                return
        screen.fill((0, 0, 0))
        block = font.render(name, True, (255, 255, 255))
        rect = block.get_rect()
        rect.center = screen.get_rect().center
        screen.blit(block, rect)
        pygame.display.flip()

if __name__ == "__main__":
    name()
The result of this python script can see into image below:

joi, 25 mai 2017

PyGame : Fix error install pygame module on python 3.4.

Today I started to install pygame with python 3.4.1.
I got a lot of errors first with pip tool, see all errors.
C:\Python34\Scripts>pip install pygame
Downloading/unpacking pygame
  Running setup.py (path:C:\Users\mythcat\AppData\Local\Temp\pip_build_mythcat\
pygame\setup.py) egg_info for package pygame


    WARNING, No "Setup" File Exists, Running "config.py"
    Using WINDOWS configuration...

    Path for SDL not found.
    Too bad that is a requirement! Hand-fix the "Setup"
    Path for FONT not found.
    Path for IMAGE not found.
    Path for MIXER not found.
    Path for PNG not found.
    Path for JPEG not found.
    Path for PORTMIDI not found.
    Path for COPYLIB_tiff not found.
    Path for COPYLIB_z not found.
    Path for COPYLIB_vorbis not found.
    Path for COPYLIB_ogg not found.

    If you get compiler errors during install, doublecheck
    the compiler flags in the "Setup" file.


    Continuing With "setup.py"
    Error with the "Setup" file,
    perhaps make a clean copy from "Setup.in".
    Traceback (most recent call last):
      File "", line 17, in 
      File "C:\Users\mythcat\AppData\Local\Temp\pip_build_mythcat\pygame\setup.py", line 165, in 
        extensions = read_setup_file('Setup')
      File "C:\Python34\lib\distutils\extension.py", line 164, in read_setup_file
        line = expand_makefile_vars(line, vars)
      File "C:\Python34\lib\distutils\sysconfig.py", line 423, in expand_makefile_vars
        s = s[0:beg] + vars.get(m.group(1)) + s[end:]
    TypeError: Can't convert 'NoneType' object to str implicitly
    Complete output from command python setup.py egg_info:

WARNING, No "Setup" File Exists, Running "config.py"

Using WINDOWS configuration...

Path for SDL not found.

Too bad that is a requirement! Hand-fix the "Setup"

Path for FONT not found.

Path for IMAGE not found.

Path for MIXER not found.

Path for PNG not found.

Path for JPEG not found.

Path for PORTMIDI not found.

Path for COPYLIB_tiff not found.

Path for COPYLIB_z not found.

Path for COPYLIB_vorbis not found.

Path for COPYLIB_ogg not found.

If you get compiler errors during install, doublecheck

the compiler flags in the "Setup" file.

Continuing With "setup.py"

Error with the "Setup" file,

perhaps make a clean copy from "Setup.in".

Traceback (most recent call last):

  File "", line 17, in 

  File "C:\Users\mythcat\AppData\Local\Temp\pip_build_mythcat\pygame\setup.py", line 165, in 

    extensions = read_setup_file('Setup')

  File "C:\Python34\lib\distutils\extension.py", line 164, in read_setup_file

    line = expand_makefile_vars(line, vars)

  File "C:\Python34\lib\distutils\sysconfig.py", line 423, in expand_makefile_vars

    s = s[0:beg] + vars.get(m.group(1)) + s[end:]

TypeError: Can't convert 'NoneType' object to str implicitly

----------------------------------------
Cleaning up...
Command python setup.py egg_info failed with error code 1 in C:\Users\mythcat\AppData\Local\Temp\pip_build_mythcat\pygame
Storing debug log for failure in C:\Users\mythcat\pip\pip.log

C:\Python34\Scripts>pip install pygame-1.9.3-cp34-cp34m-win_amd64.whl
pygame-1.9.3-cp34-cp34m-win_amd64.whl is not a supported wheel on this platform.
Storing debug log for failure in C:\Users\mythcat\pip\pip.log

C:\Python34\Scripts>pip3 install pygame-1.9.3-cp34-cp34m-win_amd64.whl
pygame-1.9.3-cp34-cp34m-win_amd64.whl is not a supported wheel on this platform.
Storing debug log for failure in C:\Users\mythcat\pip\pip.log
The solution come with the executable pygame-1.9.2a0-hg_8d9e6a1f2635%2B.win-amd64-py3.4.msi from here and now working very well.

duminică, 12 martie 2017

PyGame : How play ogg file.

Let's see how to play file.ogg file with pygame python module.
import pygame
import time
pygame.init()
pygame.mixer.music.load('file.ogg')
pygame.mixer.music.play()
time.sleep(1.5)