Quantcast
Channel: AudioGames.net Forum — Articles Room
Viewing all articles
Browse latest Browse all 309

Python Code Examples

$
0
0

Over the years I've posted a number of Python examples in a variety of threads, as such it was suggested it might be more convenient to pool them all into one place for ease of reference rather than digging through all the reams of threads on the forum. So, this thread will contain many of those examples, along with potentially future examples for anyone to reference in the future.

A basic example for key input with Pygame, with the list of keycodes here:

import pygame
from pygame import mixer
import sys

def Example():
#initialize pygame
    pygame.init()
#initialize sound mixer
    mixer.init()
#create display
    window = pygame.display.set_mode([640,480])
#load sound
    sound = mixer.Sound('tone5.wav')

#main update loop
    while True:
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
            #if space is pressed, play sound
                if event.key == pygame.K_SPACE:
                    sound.play()
            #if escape is pressed, quit
                if event.key == pygame.K_ESCAPE:
                    pygame.quit()
                    sys.exit(0)

    #update window
        pygame.display.update()

Example()

You can also collect text strings by adding a capture for event.unicode:

for event in pygame.event.get():
    if event.type == pygame.KEYDOWN:
        text += event.unicode
        print(text)

An example for modular menu based system with simple state handling:

import pygame
import sys

class main(object):
    def __init__(self):
    #initialize pygame
        pygame.init()
    #create display
        self.window = pygame.display.set_mode([640,480])
    #current menu state
        self.state = 'title'
    #list of menu/game classes
        self.menus = {'title':titlescreen(), 'game':game()}

    #primary update loop
        while True:
        #check for key press events
            for event in pygame.event.get():
                if event.type == pygame.KEYDOWN:
                    key = event
                else:
                    key = None

        #update and pass key presses and menu state to active menu
            self.state = self.menus[self.state].update(key,self.state)

        #update window
            pygame.display.update()


#titlescreen menu class
class titlescreen(object):
    def __init__(self):
    #menu option
        self.option = 0

    def update(self,event,state):
    #if a key has been pressed
        if event != None:
        #move up in the menu
            if event.key == pygame.K_UP:
                if self.option > 0:
                    print(self.option)
                    self.option -= 1

        #move down in the menu
            elif event.key == pygame.K_DOWN:
                if self.option < 1:
                    print(self.option)
                    self.option += 1

        #select a menu option
            elif event.key == pygame.K_RETURN:
            #if option is 0 return game state and play tone
                if self.option == 0:
                    print('game menu')
                    return 'game'
            #quit game
                elif self.option == 1:
                    print('quit')
                    pygame.quit()
                    sys.exit(0)

    #return current state if no changes
        return state


#main game class
class game(object):
    def __init__(self):
        pass

#DEMO: return to titlescreen
    def update(self,key,state):
        return 'title'


a = main()

A menu example with sounds:

import pygame
from pygame import mixer
import sys

class main(object):
    def __init__(self):
    #initialize pygame
        pygame.init()
    #initialize sound mixer
        mixer.init()
    #create display
        self.window = pygame.display.set_mode([640,480])
    #current menu state
        self.state = 'title'
    #list of menu/game classes
        self.menus = {'title':titlescreen(), 'game':game()}

    #primary update loop
        while True:
        #check for key press events
            for event in pygame.event.get():
                if event.type == pygame.KEYDOWN:
                    key = event
                else:
                    key = None

        #update and pass key presses and menu state to active menu
            self.state = self.menus[self.state].update(key,self.state)

        #update window
            pygame.display.update()


#titlescreen menu class
class titlescreen(object):
    def __init__(self):
    #load sound
        self.click = mixer.Sound('sound.wav')
    #load sound
        self.enter = mixer.Sound('enter.wav')
    #load music
        self.music = mixer.Sound('music.wav')
    #menu option
        self.option = 0

    #select channel's for better playback control
        self.channel0 = pygame.mixer.Channel(0)
        self.channel1 = pygame.mixer.Channel(1)
    #play background music
        self.channel0.queue(self.music)

    def update(self,event,state):
    #if titlescreen is active and not playing, play
        if self.channel0.get_busy == False:
            self.channel0.play(self.music)
    #queue the music to keep it playing
        if self.channel0.get_queue() == None:
            self.channel0.queue(self.music)

    #if a key has been pressed
        if event != None:
        #move up in the menu and play tone
            if event.key == pygame.K_UP:
                if self.option > 0:
                    self.option -= 1
                    self.channel1.play(self.click)

        #move down in the menu and play tone
            elif event.key == pygame.K_DOWN:
                if self.option < 1:
                    self.option += 1
                    self.channel1.play(self.click)

        #select a menu option
            elif event.key == pygame.K_RETURN:
            #if option is 0 return game state and play tone
                if self.option == 0:
                    self.channel1.play(self.enter)
                    return 'game'
            #quit game
                elif self.option == 1:
                    self.channel1.play(self.enter)
                    pygame.quit()
                    sys.exit(0)

    #return current state if no changes
        return state


#main game class
class game(object):
    def __init__(self):
        pass

#DEMO: return to titlescreen
    def update(self,key,state):
        return 'title'


a = main()

A network programming example using python Twisted. Note that PIckle should likely be replaced with JSON, "S" starts the server, "C" connects to it, "Q" quits, and "D" disconnects clients from the server:

from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.internet.protocol import Protocol
from twisted.internet.protocol import Factory
from twisted.internet.protocol import ClientFactory
from twisted.internet import reactor
from twisted.internet import task

import pickle
import zlib
import random

pyglet.options['debug_gl'] = False

#primary window/game class
class Prototype(pyglet.window.Window):
    def __init__(self):
        super(Prototype, self).__init__(640, 480, resizable=False, fullscreen=False, caption="Test")
        self.clear()

    #server side connected user variable, when someone connects the Echo Class will add itself into it.
    #then just call self.user.sendData to transmit to the connected user or check self.user.inbox to get data.
        self.user = []

        self.server = None
        self.client = None

    #since the Reactor is in control, to properly run the main game loop you have to manually call the clock.
    #this variable is to keep track of the last time the clock was ticked.
        self.old_dt = clock.tick()
        self.fps_display = pyglet.clock.ClockDisplay()


#shutdown program gracefully
    def shutdown(self, result):
        reactor.stop()

#system error shutdown
    def bailout(self, reason):
        reason.printTraceback()
        reactor.stop()

#main game loop
    def update(self):
        while not self.has_exit:
        #manually dispatch window events (since twisted reactor is in control)
            self.dispatch_events()

        #Make sure events are timed properly while coiterating with network layer. That and tick clock events like the fps counter and game pacing.
            dt = clock.tick()
            self.old_dt = self.old_dt + dt

        #if enough time has passed, update game state
            if self.old_dt >= 0.025:
                self.old_dt = 0

                self.clear()

                for a in self.user:
                    if len(a.inbox) > 0:
                        print(a.inbox)
                        a.inbox = []

                self.fps_display.draw()


        #draw here and manually flip frame buffers
            self.flip()

        #return control to twisted Reactor
            yield 1

                    
    def on_key_release(self,symbol, modifiers):
    #start server
        if symbol == key.S:
            self.server = TCP4ServerEndpoint(reactor, 8007)
            self.server.listen(QOTDFactory())
            print("server initializing")
    #connect to server
        if symbol == key.C:
            self.client = reactor.connectTCP('localhost', 8007, EchoClientFactory())
            print("connecting")
    #disconnect client from server side
        if symbol == key.D:
            for a in range(0,len(self.user),1):
                self.user[a].disconnect()

        if symbol == key.Q:
            if self.client != None:
            #disconnect from the client side
                print('stopping client')
                self.client.disconnect()
            self.close()

        if symbol == key.SPACE:
            for a in self.user:
                a.sendData("space pressed")



#this handles two way communication with connected clients
class Echo(Protocol):
#data reciever class
    def connectionMade(self):
    #add this class to the main program
        window.user.append(self)
    #stored incoming data
        self.inbox = []

    def dataReceived(self, data):
        data = zlib.decompress(data)
        data = pickle.loads(data)
        self.inbox.insert(0,data)

    def sendData(self,data):
        data = pickle.dumps(data)
        data = zlib.compress(data)
        self.transport.write(data)

    def disconnect(self):
        self.transport.loseConnection()



#this monitors the port and automatically calls Echo() when someone connects, passing their address to it.
class QOTDFactory(Factory):
    def buildProtocol(self, addr):
        print(addr, "connected.")
        return Echo()



#This class establishes a connection to a server.
class EchoClientFactory(ClientFactory):
    def startedConnecting(self, connector):
        print('Started to connect.')

    def buildProtocol(self, addr):
        print('Connected.')
        return Echo()

    def clientConnectionLost(self, connector, reason):
        print('Lost connection. Reason:', reason)

    def clientConnectionFailed(self, connector, reason):
        print('Connection failed. Reason:', reason)



if __name__ == '__main__':
#initialize main window
    window = Prototype()
#port to listen to
    task.coiterate(window.update()).addCallback(window.shutdown).addErrback(window.bailout)
#start reactor loop
    reactor.run()

Random map generator code:

import pyglet
from pyglet.window import key
from pyglet.gl import *
import numpy
import random
import sys

class Prototype(pyglet.window.Window):
    def __init__(self):
        super(Prototype, self).__init__(640, 480, resizable=False, fullscreen=False, caption="Test")
        self.clear()

        self.map = Map_Gen(128,128)
        self.map.generate()

        pyglet.clock.schedule_interval(self.update, .01)



    def update(self,dt):
    #draw screen
        self.draw()



    def draw(self):
        self.clear()
        self.map.minimap['map'].blit(32,0)
        


    def on_key_press(self,symbol,modifiers):
        if symbol == key.ESCAPE:
            self.close()





#Map Generator
#/---------------------------------------------------------------------------/
class Map_Gen(object):
    def __init__(self,mx=64,my=64,density=0.5,r_density=0.5,node=10):
    #Map Dimensions
        self.mx = mx
        self.my = my
    #density of terrain: 0.0 to 1.0
        self.density = density
    #number of terrain nodes
        self.node = node
    #random map seed
        self.seed = None

    #minimap main texture
        self.minimap = {'map_image':pyglet.image.create(1,1),'map':pyglet.image.create(1,1)}


    #contains the ground layer data that makes up the map
        self.map = [] #28
    #contains the object layer information IE: vehicles, resources, objects, components, (buildings?),etc.
        self.resource = []

    #The tileset is an indexed list of tile types based on their shape and purpose relative to terrain placement.
    #In this case, the total is 16 tiles with the order being:

        #0: Land
        #1: Water

        #2: Water with lower right corner Land
        #3: Water with bottom half Land
        #4: Water with lower left Land
        #5: Water with right side Land
        #6: Water with left side Land
        #7: Water with upper right Land
        #8: Water with upper half Land
        #9: Water with upper left Land

        #10: Land with Bottom Right Water
        #11: Land with bottom left water
        #12: Land with upper right Water
        #13: Land with upper left water

        #14: Land with Upper Right and Lower Left water
        #15: Land with upper left and lower right water

        self.tileset = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]

    #Tile properties determines whether the tiles are passable or solid, the length equals number
    #of different types of tile, 16 in all: #0 passable, 1 impassable, 2 overhead
    #tiles that have water are impassable.
        self.properties = [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]


    #The update table is a quick reference 2D array to change adjacent tiles during a change based on
    #what tiles are adjacent to the new ground tile. So if the tile above the new ground tile is solid water, it would be
    #changed to water with the bottom being land, or self.table[8_direction][current_land_type] = new_land_type.
    #update table
        self.table = [[0,2,2,3,3,5,12,5,11,14,0,11,12,13,14,13],#upper left
                      [0,3,3,3,3,13,12,13,0,12,0,0,12,13,12,13],#top
                      [0,4,3,3,4,13,6,15,10,6,10,0,12,13,12,15],#upper right
                      [0,6,12,12,6,0,6,10,10,6,10,0,12,0,12,10],#right
                      [0,9,14,12,6,11,6,8,8,9,10,11,12,0,14,10],#lower right
                      [0,8,11,0,10,11,10,8,8,8,10,11,8,8,11,10],#bottom
                      [0,7,5,13,15,5,10,7,8,8,10,11,0,13,11,15],#lower left
                      [0,5,5,13,13,5,0,5,11,11,0,11,0,13,11,13]]#left


    #Toggle map wrap around on/off 
        self.wrap_toggle = False

    #toggle terrain update
        self.update = False

    #total solid water count
        self.w_count = self.mx * self.my
    #total shoreline count
        self.s_count = 0
    #total solid ground count
        self.g_count = 0

    #wander variables
        self.x = 0
        self.y = 0
        self.counter = 0



#Generate map data and map image
#/-----------------------------------------------------------------------------/
    def generate(self,seed=None):
    #generate seed
        if seed == None:
            self.seed = random.randint(-999999999999,999999999999) #move to window?
        print("SEED: ", self.seed)
        random.seed(self.seed)

    #generate water
        print("Initializing Environment")
        self.map = numpy.zeros((self.my,self.mx),dtype='uint8')
        self.map[:] = 1

    #generate land masses
        print("Generating Land Masses")
        dx = random.randrange(0,len(self.map[0])-1,1)#incorporate random positions to help map saturation.
        dy = random.randrange(0,len(self.map)-1,1) 
        direction = 0
        count = 0
    #randomize direction and change terrain accordingly
        while self.g_count < (self.mx*self.my)*self.density:
            direction = random.randrange(0,4,1)

        #right
            if direction == 0 and (dx + 1) < len(self.map[dy])-1:
                dx += 1
        #left
            elif direction == 1 and (dx - 1) > 0:
                dx -= 1
        #up
            elif direction == 2 and (dy + 1) < len(self.map)-1:
                dy += 1
        #down
            elif direction == 3 and (dy - 1) > 0:
                dy -= 1            

        #count number of water/shore/land tiles
        #if water
            if self.map[dy][dx] == 1:
                self.w_count = self.w_count - 1
                self.g_count = self.g_count + 1
        #if shore
            elif self.map[dy][dx] != 0 and self.map[dy][dx] != 1:
                self.s_count = self.s_count - 1
                self.g_count = self.g_count + 1

        #set tile to land and update surrounding tiles with flux
            self.map[dy][dx] = 0
            self.flux(dx,dy)

        #calculate number of nodes and change position based on density threshold NOTE: use self.g_count instead of count?
            count = count + 1
            if count >= ((self.mx * self.my)*self.density)/(self.density*self.node):
                dx = random.randrange(0,len(self.map[0])-1,1)
                dy = random.randrange(0,len(self.map)-1,1)
                count = 0


    #generate minimap
        print("Generating Map")
        self.minimap['map_image'].width = len(self.map[0])
        self.minimap['map_image'].height = len(self.map)

        tmp = numpy.zeros((self.my,self.mx,3),dtype='uint8')
        tmp = numpy.dstack((self.map,tmp))

    #land/water/shore colors
        color = [[139,69,19,255], [0,0,255,255], [100,50,10,255]]
        for a in range(0,15,1):
            if a < 2:
                tmp = numpy.where(tmp[::,::,:1]!=a,tmp,color[a])
            else:
                tmp = numpy.where(tmp[::,::,:1]!=a,tmp,color[2])

        tmp = tmp.astype('uint8')
        
        self.minimap['map_image'].set_data('RGBA',self.minimap['map_image'].width*4,tmp.tobytes())
        self.minimap['map'] = self.minimap['map_image'].get_texture()

    #disable anti-aliasing/bilinear-filtering
        glTexParameteri(self.minimap['map'].target, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
        glTexParameteri(self.minimap['map'].target, GL_TEXTURE_MIN_FILTER, GL_NEAREST)

    #save image
        self.minimap['map'].save('tmp.png')

#update adjacent tiles
#----------------------------------------------------------------------------------|
    def flux(self,x,y):
    #upper left wrap check
        if y+1 > len(self.map)-1 and x-1 < 0:
            mx = self.mx
            my = self.my
        elif y+1 <= len(self.map)-1 and x-1 < 0:
            mx = self.mx
            my = 0
        elif y+1 > len(self.map)-1 and x-1 >= 0:
            mx = 0
            my = self.my
        else:
            mx = 0
            my = 0

        if self.map[(y+1)-my][(x-1)+mx] == 1:
            self.w_count -= 1
            self.s_count += 1
        elif self.map[(y+1)-my][(x-1)+mx] == 10:
            self.s_count -= 1
            self.g_count += 1

    #upper left
        self.map[(y+1)-my][(x-1)+mx] = self.table[0][self.map[(y+1)-my][(x-1)+mx]]



    #up wrap check
        if y+1 > len(self.map)-1:
            my = self.my
        else:
            my = 0

    #up
        if self.map[(y+1)-my][x] == 1:
            self.w_count -= 1
            self.s_count += 1
        elif self.map[(y+1)-my][x] == 8:
            self.s_count -= 1
            self.g_count += 1
        elif self.map[(y+1)-my][x] == 10:
            self.s_count -= 1
            self.g_count += 1
        elif self.map[(y+1)-my][x] == 11:
            self.s_count -= 1
            self.g_count += 1

        self.map[(y+1)-my][x] = self.table[1][self.map[(y+1)-my][x]]



    #upper right wrap check
        if y+1 > len(self.map)-1 and x+1 > len(self.map[0])-1:
            mx = self.mx
            my = self.my
        elif y+1 > len(self.map)-1 and x+1 <= len(self.map[0])-1:
            mx = 0
            my = self.my
        elif y+1 <= len(self.map)-1 and x+1 > len(self.map[0])-1:
            mx = self.mx
            my = 0
        else:
            mx = 0
            my = 0

        if self.map[(y+1)-my][(x+1)-mx] == 1:
            self.w_count -= 1
            self.s_count += 1
        elif self.map[(y+1)-my][(x+1)-mx] == 11:
            self.s_count -= 1
            self.g_count += 1

    #upper right
        self.map[(y+1)-my][(x+1)-mx] = self.table[2][self.map[(y+1)-my][(x+1)-mx]]



    #right wrap check
        if x+1 > len(self.map[0])-1:
            mx = self.mx
        else:
            mx = 0

        if self.map[y][(x+1)-mx] == 1:
            self.w_count -= 1
            self.s_count += 1
        elif self.map[y][(x+1)-mx] == 5:
            self.s_count -= 1
            self.g_count += 1
        elif self.map[y][(x+1)-mx] == 11:
            self.s_count -= 1
            self.g_count += 1
        elif self.map[y][(x+1)-mx] == 13:
            self.s_count -= 1
            self.g_count += 1

    #right
        self.map[y][(x+1)-mx] = self.table[3][self.map[y][(x+1)-mx]]



    #lower right wrap check
        if y-1 < 0 and x+1 > len(self.map[0])-1:
            mx = self.mx
            my = self.my
        elif y-1 >= 0 and x+1 > len(self.map[0])-1:
            mx = self.mx
            my = 0
        elif y-1 < 0 and x+1 <= len(self.map[0])-1:
            mx = 0
            my = self.my
        else:
            mx = 0
            my = 0

        if self.map[(y-1)+my][(x+1)-mx] == 1:
            self.w_count -= 1
            self.s_count += 1
        elif self.map[(y-1)+my][(x+1)-mx] == 13:
            self.s_count -= 1
            self.g_count += 1
        elif self.map[(y-1)+my][(x+1)-mx] == 4:
            self.s_count -= 1
            self.g_count += 1

    #lower right
        self.map[(y-1)+my][(x+1)-mx] = self.table[4][self.map[(y-1)+my][(x+1)-mx]]



    #bottom wrap check
        if y-1 < 0:
            my = self.my
        else:
            my = 0

        if self.map[(y-1)+my][x] == 1:
            self.w_count -= 1
            self.s_count += 1
        elif self.map[(y-1)+my][x] == 3:
            self.s_count -= 1
            self.g_count += 1
        elif self.map[(y-1)+my][x] == 12:
            self.s_count -= 1
            self.g_count += 1
        elif self.map[(y-1)+my][x] == 13:
            self.s_count -= 1
            self.g_count += 1

    #bottom
        self.map[(y-1)+my][x] = self.table[5][self.map[(y-1)+my][x]]



    #lower left wrap check
        if y-1 < 0 and x-1 < 0:
            mx = self.mx
            my = self.my
        elif y-1 >= 0 and x-1 < 0:
            mx = self.mx
            my = 0
        elif y-1 < 0 and x-1 >= 0:
            mx = 0
            my = self.my
        else:
            mx = 0
            my = 0

        if self.map[(y-1)+my][(x-1)+mx] == 1:
            self.w_count -= 1
            self.s_count += 1
        elif self.map[(y-1)+my][(x-1)+mx] == 12:
            self.s_count -= 1
            self.g_count += 1

    #lower left
        self.map[(y-1)+my][(x-1)+mx] = self.table[6][self.map[(y-1)+my][(x-1)+mx]]



    #left wrap check
        if x-1 < 0:
            mx = self.mx
        else:
            mx = 0

        if self.map[y][(x-1)+mx] == 1:
            self.w_count -= 1
            self.s_count += 1
        elif self.map[y][(x-1)+mx] == 6:
            self.s_count -= 1
            self.g_count += 1
        elif self.map[y][(x-1)+mx] == 10:
            self.s_count -= 1
            self.g_count += 1
        elif self.map[y][(x-1)+mx] == 12:
            self.s_count -= 1
            self.g_count += 1

    #left
        self.map[y][(x-1)+mx] = self.table[7][self.map[y][(x-1)+mx]]




if __name__ == '__main__':
    window = Prototype()
    pyglet.app.run()

Viewing all articles
Browse latest Browse all 309

Trending Articles