Initial Commit für 1869 RemakeV2

main
Alex 2 years ago
parent 3b22d18389
commit 2419dda640

@ -0,0 +1,21 @@
#####
#Paths / Assets
#####
import pyglet
draw_batch = pyglet.graphics.Batch()
#-> batch to identify who needs what to do
#-> draw_batch = should be drawn
pyglet.resource.path = ['graphics']
pyglet.resource.reindex()
max_design_intro_image = pyglet.resource.image("Max Design Introscreen.png")
artwork_intro_image = pyglet.resource.image("Introscreen_Artwork.png")
programmers_intro_image = pyglet.resource.image("Introscreen_Programmers.png")
music_intro_image = pyglet.resource.image("Introscreen_Musik.png")
title_intro_image = pyglet.resource.image("TitleScreen.png")
blackScreen = pyglet.resource.image("Blackscreen.png")
configScreen = pyglet.resource.image("ConfigScreen.png")

@ -0,0 +1,41 @@
#####
#Labels
#####
globalLabels = {
'CONFIG':{
'1' : "EIN ALTES SPIEL LADEN \"J\" SONST LEERTASTE.",
'2' : "WIE VIELE SPIELER 1-4",
'3' : "DEN NAMEN DES {} SPIELERS EINGEBEN.",
'4' : "\"M\" - MÄNNLICH ODER \"W\" - WEIBLICH ?",
'5' : "WIE SOLL DIE FIRMA DES {} SPIELERS HEISSEN ?",
'6' : (
"IN WELCHEM HAFEN WOLLEN SIE STARTEN?",
"\"1\" {} {}",
"\"2\" {} {}",
"\"3\" {} {}",
"\"4\" {} {}",
"\"5\" {} {}",
),
'7': (
"SPIELERNAME {}",
"GESCHLECHT {}",
"FIRMENNAME {}",
"STARTHAFEN {}",
"",
"SIND DIESE EINSTELLUNGEN RICHTIG? \"J\" ODER \"N\"",
),
'8':(
"WIE LANGE WOLLEN SIE SPIELEN?",
"A - 5 JAHRE",
"B - 10 JAHRE",
"C - 15 JAHRE",
"D - 20 JAHRE",
"E - 26 JAHRE",
"",
"F - 5 JAHRE \"EINSTEIGER SPIEL\"",
),
},
}

@ -0,0 +1,412 @@
# /////
# Remake of 1869 in python
# ////
import pyglet
import Assets
import Labels
import Utils
import logging # TODO to be implemented
from pyglet.window import key
from pyglet.window import mouse
from pyglet.gl import *
from scenes import IntroScreen
from scenes import ConfigScreen
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
pyglet.gl.glClearColor(0.1, 0.1, 0.1, 1)
"""
naming conventions:
d_varname = dict
s_varname = set
l_varname = list
t_varname = tuple
b_varname = batch
og_varname = orderedGroup for z relation of graphics
"""
class main(pyglet.window.Window):
def __init__(self, width=640, height=480, fps=False, *args, **kwargs):
super(main, self).__init__(width, height,
caption='1869 Remake', *args, **kwargs)
self.x = 0
self.y = 0
self.WindowMinWidth = width
self.WindowMinHeight = height
self.currentWindowWidth = width
self.currentWindowHeight = height
# self.push_handlers(pyglet.window.event.WindowEventLogger())
# -> gibt aus welche events an das window geschickt wurden -> gut zum finden von events die manipuliert werden sollen
self.og_background = pyglet.graphics.OrderedGroup(0)
self.og_semi_background = pyglet.graphics.OrderedGroup(1)
self.og_semi_foreground = pyglet.graphics.OrderedGroup(2)
self.og_foreground = pyglet.graphics.OrderedGroup(3)
self.b_sprites = pyglet.graphics.Batch()
self.b_labels = pyglet.graphics.Batch()
self.b_widgets = pyglet.graphics.Batch()
self.mouse_x = 0
self.mouse_y = 0
self.alive = 1
self.activeScene = None
self.activeSceneName = None
self.sceneTransferPhase = 1
self.d_stopWatch = dict()
self.d_active_SpriteAnimations = dict()
self.d_active_LabelAnimations = dict()
self.d_active_WidgetAnimations = dict()
self.targetScene = 'INTRO'
self.d_active_sprites = dict()
self.d_active_labels = dict()
self.d_active_widgets = dict()
# TODO check if this widget system for text input can be used to imitate text lieferant from c# code
self.text_cursor = self.get_system_mouse_cursor('text')
self.focus = None
#####
# system funcs
#####
def on_resize(self, width, height):
width = max(width,self.WindowMinWidth)
height = max(height, self.WindowMinHeight)
super(main, self).on_resize(width, height)
currentScaleFactor_x = width/self.currentWindowWidth
currentScaleFactor_y = height/self.currentWindowHeight
self.currentWindowWidth = width
self.currentWindowHeight = height
if self.d_active_sprites is not None:
for keys, sprite in self.d_active_sprites.items():
sprite.scale_x = max(width, sprite.image.width)/min(width, sprite.width)
sprite.scale_y = max(sprite.image.height, height)/min(sprite.image.height, height)
if self.d_active_labels is not None:
for keys, label in self.d_active_labels.items():
label.content_width = label.content_width*(max(label.content_width, width)/ min(label.content_width, width))
label.content_height = label.content_height*(max(label.content_height, height)/ min(label.content_height, height))
label.x = label.x* currentScaleFactor_x
label.y = label.y* currentScaleFactor_y
label.font_size = label.font_size*currentScaleFactor_x
if self.d_active_widgets is not None:
for keys, widget in self.d_active_widgets.items():
#widget.width = width - 110
pass
def on_draw(self):
self.render()
def render(self):
self.clear()
self.b_sprites.draw()
self.b_labels.draw()
self.b_widgets.draw()
self.flip()
def on_close(self):
self.alive = 0
#####
# input Handler Funcs
#####
def on_mouse_motion(self, x, y, dx, dy):
# forward mouse information to active scene
self.activeScene.on_mouse_motion(self, x, y, dx, dy)
self.mouse_x = x
self.mouse_y = y
if self.d_active_widgets is not None:
for key,widget in self.d_active_widgets.items():
if widget.hit_test(x, y):
self.set_mouse_cursor(self.text_cursor)
break
else:
self.set_mouse_cursor(None)
def on_mouse_press(self, x, y, button, modifiers):
# forward mouse information to active scene
self.activeScene.on_mouse_press(self, x, y, button, modifiers)
if button == 1: # Left click
pass
for key,widget in self.d_active_widgets.items():
if widget.hit_test(x, y):
self.set_focus(widget)
break
else:
self.set_focus(None)
if self.focus:
self.focus.caret.on_mouse_press(x, y, button, modifiers)
def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
if self.focus:
self.focus.caret.on_mouse_drag(x, y, dx, dy, buttons, modifiers)
def on_key_press(self, symbol, modifiers):
# forward keypress information to active scene
self.activeScene.on_key_press(self, symbol, modifiers)
if symbol == key.ESCAPE:
self.alive = 0
if symbol == key.TAB:
if modifiers & key.MOD_SHIFT:
dir = -1
else:
dir = 1
if self.focus in self.d_active_widgets:
i = self.d_active_widgets.index(self.focus)
else:
i = 0
dir = 0
self.set_focus(self.d_active_widgets[(i + dir) % len(self.d_active_widgets)])
def on_text(self, text):
if self.focus:
self.focus.caret.on_text(text)
def on_text_motion(self, motion):
if self.focus:
self.focus.caret.on_text_motion(motion)
def on_text_motion_select(self, motion):
if self.focus:
self.focus.caret.on_text_motion_select(motion)
def set_focus(self, focus):
if self.focus:
self.focus.caret.visible = False
self.focus.caret.mark = self.focus.caret.position = 0
print('defocused')
self.focus = focus
if self.focus:
print('focused')
self.focus.caret.visible = True
self.focus.caret.mark = 0
self.focus.caret.position = len(self.focus.document.text)
#####
# stopwatch functions
####
def checkStopwatch(self, obj, targetSeconds):
"""
tracks time based operations for given objects
-> targetSeconds: returns true if current Timer is below /reached targetSeconds
"""
if obj in self.d_stopWatch:
if self.d_stopWatch[obj] <= targetSeconds:
return True
else:
return False
else:
return False
def setStopwatch(self, obj, seconds):
if obj not in self.d_stopWatch:
self.d_stopWatch[obj] = seconds
return True
else:
# not allowed to set a timer on an object twice
return False
def stopwatch_tick(self):
for obj in self.d_stopWatch:
self.d_stopWatch[obj] -= 1
def clearStopwatchTask(self, obj):
if obj in self.d_stopWatch:
self.d_stopWatch.pop(obj)
return True
else:
return False
def clearStopwatch(self):
self.d_stopWatch.clear()
#####
# resource loaders
#####
def load_sprites(self):
"""
load all sprites used in the specific scene
"""
if isinstance(self.activeScene, IntroScreen.IntroScene):
return {
'max_design_intro_sprite': pyglet.sprite.Sprite(Assets.max_design_intro_image, batch=self.b_sprites, group=self.og_background),
'artwork_intro_sprite': pyglet.sprite.Sprite(Assets.artwork_intro_image, batch=self.b_sprites, group=self.og_background),
'programmers_intro_sprite': pyglet.sprite.Sprite(Assets.programmers_intro_image, batch=self.b_sprites, group=self.og_background),
'music_intro_sprite': pyglet.sprite.Sprite(Assets.music_intro_image, batch=self.b_sprites, group=self.og_background),
'title_intro_sprite': pyglet.sprite.Sprite(Assets.title_intro_image, batch=self.b_sprites, group=self.og_background),
'blackscreen': pyglet.sprite.Sprite(Assets.blackScreen, batch=self.b_sprites, group=self.og_foreground),
}
if isinstance(self.activeScene, ConfigScreen.ConfigScene):
return {
'configSprite': pyglet.sprite.Sprite(Assets.configScreen, batch=self.b_sprites, group=self.og_background),
'blackscreen': pyglet.sprite.Sprite(Assets.blackScreen, batch=self.b_sprites, group=self.og_foreground),
}
def load_labels(self):
"""
load all labels used in the specific scene
"""
if isinstance(self.activeScene, IntroScreen.IntroScene):
return {
'press_enter': pyglet.text.Label(text="Press Enter", font_name=None, font_size=10, color=(255, 255, 255, 0), x=(self.width*7/10), y=(self.height*2/7), anchor_x='center', batch=self.b_labels, group=self.og_semi_foreground),
}
if isinstance(self.activeScene, ConfigScreen.ConfigScene):
return {}#CONFIG has no preset Labels -> they are created by the scene on demand
def load_widgets(self):
"""
load all widgets used in the specific scene
"""
if isinstance(self.activeScene, ConfigScreen.ConfigScene):
return {
'mainInput': Utils.TextWidget("-TEST TEXT-", x=(self.width/2 )-50, y=self.height/2, width=100 ,batch=self.b_widgets),
'textController':Utils.ControledTextBox(x=(self.width/2 )-50, y=(self.height/2) - 50, width=100 , height = 150, batch=self.b_widgets),
}
def load_sounds(self):
"""
load all sound resources -> probably optimize for scenes
"""
return {
}
#####
# maintanence funcs
#####
def clear_externalLabel(self, target=None):
pass
def register_externalLabel(self, keyName, text, x, y, width, batch):
if keyName in self.d_active_labels:
return False
else:
self.d_active_labels[keyName]
def clear_animationLists(self, target=None):
if target in [None, 'sprites']:
self.d_active_SpriteAnimations.clear()
if target in [None, 'labels']:
self.d_active_LabelAnimations.clear()
if target in [None, 'widgets']:
self.d_active_WidgetAnimations.clear()
def register_animation(self, anim, wantedAnimation):
"""
registers anims to be animated by custom animations
"""
if isinstance(anim, pyglet.sprite.Sprite):
if anim in self.d_active_SpriteAnimations:
return False
else:
self.d_active_SpriteAnimations[anim] = wantedAnimation
elif isinstance(anim, pyglet.text.Label):
if anim in self.d_active_LabelAnimations:
return False
else:
self.d_active_LabelAnimations[anim] = wantedAnimation
else:
if anim in self.d_active_WidgetAnimations:
return False
else:
self.d_active_WidgetAnimations[anim] = wantedAnimation
def run_AnimationManager(self):
"""
animates all registered animations that are currently active
"""
l_deactivateAnims = list()
for sprite, animationType in self.d_active_SpriteAnimations.items():
# forward sprite animation infos to active scene
self.activeScene.maintain_SpriteAnimations(l_deactivateAnims, sprite, animationType)
for label, animationType in self.d_active_LabelAnimations.items():
# forward label animation infos to active scene
self.activeScene.maintain_LabelAnimations(l_deactivateAnims, label, animationType)
for widget, animationType in self.d_active_WidgetAnimations.items():
# forward label animation infos to active scene
self.activeScene.maintain_WidgetAnimations(l_deactivateAnims, widget, animationType)
# when all anims are played out active anims must be cleared for finished ones
for anim in l_deactivateAnims:
if isinstance(anim, pyglet.sprite.Sprite):
self.d_active_SpriteAnimations.pop(anim, None)
if isinstance(anim, pyglet.text.Label):
self.d_active_LabelAnimations.pop(anim, None)
if isinstance(anim, Utils.TextWidget):
self.d_active_WidgetAnimations.pop(anim, None)
def activate_scene(self, scene):
self.activeScene = scene
self.activeSceneName = self.activeScene.sceneName
def transferToScene(self, originScene, targetScene):
"""
transfers from a scene to a scene
phase false = no transition
phase 1 = origin is deactivated
phase 2 = target is loaded
"""
if self.sceneTransferPhase is False:
self.sceneTransferPhase = 1
if self.sceneTransferPhase is 1:
if self.activeScene is None :
self.sceneTransferPhase = 2
elif self.activeScene.isAlive is False:
self.activeScene.killSprites(self,self.d_active_sprites)
self.activeScene.killLabels(self,self.d_active_labels)
self.activeScene.killWidgets(self,self.d_active_widgets)
self.sceneTransferPhase = 2
if self.sceneTransferPhase is 2:
if self.targetScene is "INTRO":
self.activate_scene(IntroScreen.IntroScene())
if self.targetScene is "CONFIG":
self.activate_scene(ConfigScreen.ConfigScene())
self.d_active_sprites = self.load_sprites()
self.d_active_labels = self.load_labels()
self.d_active_widgets = self.load_widgets()
self.activeScene.prepareSprites(self, self.d_active_sprites)
self.activeScene.prepareLabels(self, self.d_active_labels)
self.activeScene.prepareWidgets(self,self.d_active_widgets)
self.targetScene = False
self.sceneTransferPhase = False
def checkSceneTransfers(self):
"""
check if any scene transferes have to be made
"""
#scenetransfer is broken -> repair + more control (e.g. introscene)
if self.activeScene is None:
self.transferToScene(self.activeScene,self.targetScene)
elif self.activeScene.isInTransfer is True or self.sceneTransferPhase is 1:
self.transferToScene(self.activeScene,self.targetScene)
#####
# main loop
#####
def run(self):
while self.alive == 1:
self.run_AnimationManager()
self.checkSceneTransfers()
if self.activeScene is not None:
self.targetScene = self.activeScene.run(self)
self.render()
event = self.dispatch_events()
# Programm starting point
if __name__ == '__main__':
game = main(resizable=True)
game.run()

@ -0,0 +1,9 @@
ToDo:
IntroScreen:
- done
ConfigScreen:
- Textfeld informationen verarbeiten
- animationsmaschinerie mit IntroScreen vergleichen und anpassen(bei bedarf)
- doScene + close funktionen mit intro abgleichen
utils:
- textcontroller -> mouse daten übergabe zuende implementieren

@ -0,0 +1,234 @@
###
#util functions
###
import pyglet
def center_image(image):
"""Sets an image's anchor point to its center"""
image.anchor_x = image.width // 2
image.anchor_y = image.height // 2
def fadeIn_sprite(sprite , currentOpacity ,speed):
if sprite.opacity < 255:
if sprite.opacity + speed > 255:
sprite.opacity = 255
else:
sprite.opacity = currentOpacity + speed
else:
return False # returns False if max reached
def fadeOut_sprite(sprite, currentOpacity ,speed):
if sprite.opacity > 0:
if sprite.opacity - speed < 0:
sprite.opacity = 0
else:
sprite.opacity = currentOpacity - speed
else:
return False # returns False if 0 reached
def fadeIn_label(label, currentColor,speed):
red = currentColor[0]
green = currentColor[1]
blue = currentColor[2]
alpha = currentColor[3]
inProgess = True
if alpha + speed > 255:
alpha = 255
inProgess = False
else:
alpha += speed
toggledColor = (red,green,blue,alpha)
label.color = toggledColor
return inProgess
def toggle_label(label, currentColor):
red = currentColor[0]
green = currentColor[1]
blue = currentColor[2]
alpha = currentColor[3]
if alpha > 0:
alpha = 0
else:
alpha = 255
toggledColor = (red,green,blue,alpha)
label.color = toggledColor
return True
def fading_toggle_label(label, currentColor,remaining_alpha):
if remaining_alpha is 0:
return True
red = currentColor[0]
green = currentColor[1]
blue = currentColor[2]
alpha = currentColor[3]
if alpha > 0:
alpha = 0
else:
alpha = remaining_alpha
toggledColor = (red,green,blue,alpha)
label.color = toggledColor
return True
def fadeIn_widget(widget, Alpha,speed):
inProgess = True
if Alpha + speed > 255:
widget.set_opacity(255)
inProgess = False
else:
widget.set_opacity(Alpha + speed)
return inProgess
def fadeOut_widget(widget, Alpha,speed):
inProgess = True
if Alpha > 0:
if Alpha - speed < 0:
widget.set_opacity(0)
inProgess = False
else:
widget.set_opacity(Alpha - speed)
return inProgress
class Rectangle(object):
'''Draws a rectangle into a batch.'''
def __init__(self, x1, y1, x2, y2, batch):
self.vertex_list = batch.add(4, pyglet.gl.GL_QUADS, None,
('v2i', [x1, y1, x2, y1, x2, y2, x1, y2]),
('c4B', [200, 200, 220, 255] * 4)
)
class TextWidget(object):
"""
Texteingabe Feld
"""
def __init__(self, text, x, y, width, batch):
self.document = pyglet.text.document.UnformattedDocument(text)
self.document.set_style(0, len(self.document.text),
dict(color=(0, 0, 0, 0))
)
font = self.document.get_font()
height = font.ascent - font.descent
# checken wo groups integriert werden können da sich einige sachen überlagern
self.layout = pyglet.text.layout.IncrementalTextLayout(
self.document, width, height, multiline=False, batch=batch)
self.caret = pyglet.text.caret.Caret(self.layout)
self.layout.x = x
self.layout.y = y
# Rectangular outline
pad = 2
#self.rectangle = Rectangle(x - pad, y - pad,
#x + width + pad, y + height + pad, batch)
def hit_test(self, x, y):
return (0 < x - self.layout.x < self.layout.width and
0 < y - self.layout.y < self.layout.height)
def set_opacity (self,alpha):
self.document.set_style(0,len(self.document.text), dict(color=(0,0,0,alpha)))
#self.rectangle.opacity = alpha
def get_opacity (self):
color = self.document.get_style_range('color', 0, len(self.document.text))
#color = self.rectangle.opacity
return color[3]
class ControledTextBox(object):
"""
controller for textdisplay, input via text/button selection, sitewise type specific handling
3 Data feeds are needed:
-> a) basic information about the controller (general size, how many lines, how many columns[and their specific sizes])
-> b) dictionary which element
-> c) dictionary describing a site-tree with indexes
"""
def __init__(self, x, y, width, height,batch):
"""
constructs the basic frame
"""
self.ContentTree = None
self.currentPage = 1
self.xPos = x
self.yPos = y
self.width = width
self.height = height
def render(self):
pass
#todo: anpassen dass mouse daten übergeben werden
"""def on_mouse_motion(self, x, y, dx, dy):
# forward mouse information to active scene
self.activeScene.on_mouse_motion(self, x, y, dx, dy)
self.mouse_x = x
self.mouse_y = y
if self.d_active_widgets is not None:
for key,widget in self.d_active_widgets.items():
if widget.hit_test(x, y):
self.set_mouse_cursor(self.text_cursor)
break
else:
self.set_mouse_cursor(None)
def on_mouse_press(self, x, y, button, modifiers):
# forward mouse information to active scene
self.activeScene.on_mouse_press(self, x, y, button, modifiers)
if button == 1: # Left click
pass
for key,widget in self.d_active_widgets.items():
if widget.hit_test(x, y):
self.set_focus(widget)
break
else:
self.set_focus(None)
if self.focus:
self.focus.caret.on_mouse_press(x, y, button, modifiers)
def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
if self.focus:
self.focus.caret.on_mouse_drag(x, y, dx, dy, buttons, modifiers)
def on_key_press(self, symbol, modifiers):
# forward keypress information to active scene
self.activeScene.on_key_press(self, symbol, modifiers)
if symbol == key.ESCAPE:
self.alive = 0
if symbol == key.TAB:
if modifiers & key.MOD_SHIFT:
dir = -1
else:
dir = 1
if self.focus in self.d_active_widgets:
i = self.d_active_widgets.index(self.focus)
else:
i = 0
dir = 0
self.set_focus(self.d_active_widgets[(i + dir) % len(self.d_active_widgets)])
"""
def setPageStructure(self, d_structure):
"""
sets the structure of the containing pages
types:
-TextSelection -> pick a text from a list of texts (returns index of text in the current page)
-ListSelection -> pick a listentry gathered from a defined datapool (returns the text of the entry)
e.g.: [pageIndex]:(type,typeSpecificDetails)
e.g.: "1.1":(TextSelection,rows,maxVisibleRows)
"""
pass
def setContent(self, d_pageToContent):
"""
sets the content of each page (structure must be considered while filling it)
e.g.: [pageIndex]:{[index1]:(TEXT1), [index2]:(TEXT2)}
"""
pass
def checkInput(self):
"""
check if there is input to give back to the requester
"""
pass

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

@ -0,0 +1,30 @@
Copyright (c) 2006-2008 Alex Holkner
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of pyglet nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

@ -0,0 +1,27 @@
include LICENSE
include NOTICE
include README
include CHANGELOG
include RELEASE_NOTES
# Public tools
include tools/inspect_font.py
# Examples
recursive-include examples *
prune examples/**/dist
# Tests
recursive-include tests *
recursive-exclude tests/regression/images *.png
recursive-exclude tests *.log
# Docs
# removed - docs available separately
#recursive-include doc/html *
#recursive-include doc/pdf *
# Development artifacts
prune **/.svn
recursive-exclude * *.pyc
recursive-exclude * *.pyo

@ -0,0 +1,49 @@
pyglet
Copyright 2006-2008 Alex Holkner
http://www.pyglet.org
pyglet includes contributions from the following organisations and
individuals:
Blue Box Devices
SR Research
Jesse Archer
Ben Atkin
Anthony Baxter
Anthony Briggs
Andrew Campbell
Ondrej Certik
Peter Dilley
Casey Duncan
Dunk Fordyce
Alan Green
Brian Grogan Jr
Richard Jones
George LeCompte
Matthew Marshall
Michael Romer
Tobias Sargeant
Andreas Schiefer
Peter Shinners
Nathan Stocks
Martin Di Paola
Walter Woods
anatoly techtonik
Juan J. Martinez
Txema Vicente
Claudio Canepa
pyglet/libs/win32/constants.py is derived from Python for Windows
Extensions. Copyright 1994-2001 Mark Hammond.
pyglet/image/codecs/pypng.py is derived from png.py. Copyright 2006
Johann C. Rocholl.
contrib/layout/layout/Plex/ is derived from Plex. Copyright Greg Ewing.
tools/wraptypes/lex.py and tools/wraptypes/yacc.py are derived from ply.
Copyright 2001-2006 David M. Beazley.
pyglet/font/win32query.py is fontquery.py placed into public domain by
anatoly techtonik.

@ -0,0 +1,30 @@
Metadata-Version: 1.1
Name: pyglet
Version: 1.3.0
Summary: Cross-platform windowing and multimedia library
Home-page: http://pyglet.readthedocs.org/en/latest/
Author: Alex Holkner
Author-email: Alex.Holkner@gmail.com
License: BSD
Download-URL: http://pypi.python.org/pypi/pyglet
Description: pyglet provides an object-oriented programming
interface for developing games and other visually-rich applications
for Windows, Mac OS X and Linux.
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: MacOS X
Classifier: Environment :: Win32 (MS Windows)
Classifier: Environment :: X11 Applications
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Topic :: Games/Entertainment
Classifier: Topic :: Software Development :: Libraries :: Python Modules

@ -0,0 +1,61 @@
pyglet
======
http://www.pyglet.org/
pyglet provides an object-oriented programming interface for developing games
and other visually-rich applications for Windows, Mac OS X and Linux.
Requirements
------------
pyglet runs under Python 2.7, and 3.4+. The entire codebase is fully 2/3 dual
compatible, making use of the future module for backwards compatibility with
legacy Python. Being written in pure Python, it also works on other Python
interpreters such as PyPy. pyglet works on the following operating systems:
* Windows XP or later
* Mac OS X 10.3 or later
* Linux, with the following libraries (most recent distributions will have
these in a default installation):
* OpenGL and GLX
* GDK 2.0+ or PIL (required for loading images other than PNG and BMP)
* Pulseaudio or OpenAL (required for playing audio)
Installation
------------
If you're reading this README from a source distribution, you can install
pyglet with:
python setup.py install
There are no compilation steps during the installation; if you prefer,
you can simply add this directory to your PYTHONPATH and use pyglet without
installing it. You can also copy pyglet directly into your project folder.
The documentation is available online at pyglet.org, but if you want to
build the documentation yourself, please check the README file in the doc
directory.
Support
-------
pyglet has an active developer and user community. If you find a bug, please
open an issue at https://bitbucket.org/pyglet/pyglet/issues.
Please join us on the mailing list at:
http://groups.google.com/group/pyglet-users
For more information, visit http://www.pyglet.org
Testing
-------
pyglet makes use of pytest for it's test suite.
% py.test tests/
Please check the documentation for more information about running and writing
tests.

@ -0,0 +1,240 @@
Pyglet 1.3.0
============
This major release takes Python 3 support to the next level. The entire codebase is now compatible
with both Python 2 and Python 3 without the need for 2to3. This should make it easier to develop
pyglet and pyglet apps for both Python versions.
The rest of this release is focussed on code quality and test coverage. There are no API breaking
changes, and only a few minor additions. Dozens of bugs have been fixed, and the codebase is in a
better state for future improvement and maintainability.
New features
------------
- The procedural audio module is now more usable. This module allows synthesis of basic
waveforms, such as sine, square, triangle, sawtooth, and simple FM (two operator sine).
In addition, several basic amplitude envelopes are now available to apply to generated audio.
These include ADSR, linear decay, tremolo, and flat envelopes.
Improvements
------------
- Improved font rendering for fonts with negative bearing (#99)
- Sprites now have `scale_x` and `scale_y` attributes, allowing for aspect ratio changes. The
existing `scale` attribute sets the overall scaling, and functions as before.
- Sprites have a new `update` method which allows simultaneous changing of position, scale, and
rotation. This reduces some overhead when changing multiple attributes at once.
- The pyglet.resource module now defaults to a 2048x2048 texture for it's internal texture atlas,
but will fall back to the maximum available size that the GPU can provide.
- All modern joysticks and game controllers should now be detected on Linux and Windows.
- Refactored and reimplemented pyglet.media. Many improvements to stability. Different drivers
should now behave more similar.
- WM_CLASS hints are now set on Linux. On modern Linux desktop environments and window managers,
this allows for proper tracking of pyglet applications. Previously, pyglet apps may show up as
"Unknown" under the active window list in the environment. The window class hints are set
to the same name as the Window caption, but will fall back to "pyglet" if the Window caption
contains non-ascii characters.
- Vastly improved documentation and programming guide.
Bugfixes
--------
- Limit the minimum window size 1x1 pixel, preventing an OpenGL exception when resizing (#49).
- Font module no longer leaks memory when text is changed (#66).
- Fix crash on Python 2 when sys.argv[0] has non-ASCII characters (#74).
- Windows: Fix crash when opening multiple windows in succession (#81).
- Windows: Fix local font loading (#100).
- Windows: Italic fonts no longer render parts of their neighbors.
- Prevent memory leak from orphaned StreamingSources in long running applications (#103).
- Windows: Fix kerning regression (#115)
- Windows: Window.set_icon no longer fails when given a Texture instead of ImageData (#136)
Pyglet 1.2.3
============
Minor bugfix release.
Bugfixes:
- Windows: Fix issue where ALT key causes app to hang.
- Media: Many fixes to PulseAudio and OpenAL media drivers (a.o. #26, #27).
- OSX: Fix stealing the menu when already present in cocoa.
- Fix multi texturing support (#28).
- OSX: Prevent segfault with multiple runs (#37/GC728)
- ArchLinux: Fix segmentation fault when using gdk_pixbuf (#25)
Pyglet 1.2.2
============
Minor bugfix release. Includes documentation updates for deprecated code.
Bugfixes
--------
- BB#21: X11: Error on fontconfig cache eviction
- BB#23: Windows: Disable ARB context on Intel devices.
Pyglet 1.2.1
============
Minor bugfix release. Fixes some issues on Linux.
Bugfixes
--------
- BB#18: X11: Events not processed while animating
- X11: on_resize event not triggered
- X11: Fix deletion of PulseAudioPlayer.
Pyglet 1.2
==========
The major 1.2 release brings pyglet to Python 3. Pyglet now also runs on 64-bit operating systems
Linux, Windows and OS X. The OS X layer has switched to Cocoa.
Backwards-incompatible API changes:
* renamed Label parameter 'halign' to 'align', fix for issue:460
* remove unused module 'glext_missing' - everything should already be in 'glext_arb'
Python support
--------------
- 2.6 and up
- NEW: 3.3 and up
Platform support
----------------
- Improved win32 support
- Windows: DirectInput support
- OSX: Joystick support
- Linux: GL 3 support
- Linux: ALSA replaced by PulseAudio
- Windows: Tablet API support
- OSX: Tablet support
- Linux: Tablet support
- OSX: Cocoa support
- OSX: Support for PyObjC 2.3
Bugfixes
--------
- 294: pyglet.image.get_texture(rectangle=True) returns GL_TEXTURE_2D for tex.target if image is
POT
- 345: image mouse cursor shows up after fullscreen switch
- 347: vowel in Thai language did not display
- 353: X11: Wrong keysym reported in on_key_press/release if shift pressed.
- 355: wraptypes does not wrap hex or octal enum values properly
- 357: Non-conforming ATI cards missing glGenBuffers
- 358: ResourceNotFoundException has spelling error in message (in pyglet 1.1.2)
- 361: xlib: initial mouse dx/dy incorrect if mouse on window
- 362: Support for generic attributes are broken
- 363: pyglet.resource no longer finds files within directories
- 368: permission issues with some doc and example files
- 371: pyglet.sprite uses integer coordinates for drawing
- 376: Windows Installer Ambiguous about Supported Python Versions
- 377: on_mouse_scroll not being called with latest pyglet revision (from svn) on vista64
- 379: pyglet.media.drivers.alsa not in trunk r2421
- 380: mac osx HID not working
- 381: Missing attribute in VertexDomain when changing the group attribute of a sprite multiple
times
- 382: evdev device name unicode problem
- 387: input events stop being processed
- 391: code cleanups for pyglet.image
- 392: code cleanups for text and font
- 393: code cleanup for input and app
- 405: Virtual key codes are not mapped in OS X
- 407: random crash with pyglet.clock.tick()
- 408: IncrementalTextLayout, when deleted, still renders into its batch on document update
- 409: pyglet.media.have_avbin missing in 1.2dev (svn rev 2445)
- 411: Problem loading gif animation with alpha
- 413: TileableTexture interchanges red and blue in some JPGs
- 414: Carbon platform missing support for multiple mouse buttons during drag
- 416: Endless loop in pyglet.resource.reindex()
- 418: Vertical mouse scroll problem under windows
- 422: Documentation: pyglet.resource and pats
- 423: glMultiDrawElements called with incorrect arguments in method IndexedVertexDomain.draw
- 424: Small documentation error in document layout model page
- 426: Attempt to load resource from zipfile with no internal directory structure fail
- 429: Exception when attributed text contains multiple trailing newlines
- 439: EVENT_CLOSE test can't be passed
- 440: tests/window/WINDOW_SET_MOUSE_SYSTEM_CURSOR does not exit when escape is pressed
- 443: after the test window.EVENT_SHOW_HIDE process must be killed
- 444: tests/resources/RES_LOAD_IMAGE opens a slew of windows and doesn't close them
- 460: multiline label will not center align
- 463: Min/Mag filter cannot be used with pyglets texture
- 467: Setting the mouse position should be exposed to pyglet users
- 471: Exception when clearing text of FormattedDocument with IncrementalTextLayout
- 485: Wrapper generation (e.g. gengl.py) fails to parse L-prefaced character literals
- 487: vendor specific keys on linux are crashing pyglet
- 493: GdkPixbuf2ImageDecoder unable to decode images smaller than 1kb
- 496: Another OpenGL 1.5 non-conforming video card
- 510: Win-amd64 issues
- 512: Fix missing parenthesis in docs
- 517: tests/window/CONTEXT_SHARE.py glIsList exceptions
- 519: Windows test log errors
- 523: some incorrect key constants in the programming guide
- 524: Pyglet 1.2dev events do not fire on OS X
- 529: pyglet crashes on FreeBSD-8/amd64 if fonts are used. [patch included]
- 533: pyglet.media.Player broken on Python3
- 536: Pitch change functionality with pulseaudio driver.
- 538: deleting text before an InlineElement fails to adjust its position properly, causes
tracebacks if style changed later
- 551: image encoder fails on python 3
- 552: Memory leak in pyglet.image.load
- 558: Patch for /doc/programming_guide/graphics.txt
- 565: Race condition leads to crash calling glDeleteBuffers
- 570: xlib 100% CPU usage after post_event
- 571: pyglet fails for sys.platform=='linux3'
- 572: Patch for /pyglet/lib.py
- 579: Failing to load libraries that exist but have fatal problems is _silently_ ignored on Linux
and OS X.
- 580: image.DDS_RGB_DXT1_LOAD (and similar) throw ImageException
- 610: Wrong messages in the NOTICE file
- 611: Mouse event incorrect on OS-X
- 616: Mention font.Font.have_font() in proguide, and expose font.have_font() for convenience
- 624: mouse_motion events get delivered to cocoa windows on start
- 625: osx platform segmentation fault when opening input devices
- 630: pyglet 1.2alpha1 with Python 3.2
- 637: 'pulse' audio driver sets the volume to 100%
- 638: Player set_pitch crashes with 'directaudio' driver
- 653: Unsupported PNG color type: 3
- 657: gdiplus.py : n_delays must be long, not float.
- 659: image.save method doesnt catch correct Exception
- 660: platform_event_loop.post_event doesn't work for Cocoa loop
- 661: Player.next is converted to Player.__next__ for python3
- 662: gamepad cannot be found in linux
- 664: bug in font/win32query.py on win x64 (its not always occur )
- 665: remove_handler does not remove handler
- 668: Sync pypng with upstream
- 671: Support for local libraries
- 672: User preferences shouldn't use ~/.ApplicationName/ but ~/.config/AplicationName/ in Linux
- 673: Documentation building requirements are not documented
- 674: README errors
- 681: Tuple slice on ImageGrid documented but not implemented
- 682: Documentation Link on homepage is incorrect.
- 683: Improving "contribute" page
- 684: Displaying large font fails under very specific conditions
- 687: Exposing _draw_list_dirty in batch API.
- 688: Doc folder refactorization
- 692: docstring style modifications
- 696: 2to3 convertsizip_longest to zip_longest
- 699: SolidColorImagePattern and CheckerImagePattern appear to fail in python3 and pyglet1.2a
- 704: [patch] py3 compatibility problem in pyglet/graphics/__init__.py
- 710: resource path when using
- 715: Patch for /pyglet/image/codecs/dds.py
- 716: FIX: Pulseaudio / ctypes on Py3k
- 718: False "ImageDecodeException: Not a GIF stream" in python3.x
- 719: .bmp files traceback with py3
- 720: tests/image compatibility StringIO vs BytesIO
- 721: compatibilty py3 for tests/image TEXTURE_3D.py and TEXTURE_GRID.py
- 722: TypeError in graphics test suite with python3.x
- 723: py3 compatibility in tests/image MATRIX_RGB.py, MATRIX_RGBA.py
- 724: py3 compatibility for png s (bytes vs str)
- 727: tabs looking bad, especially in monospace fonts
- 729: "ImportError: No module named future" in image.MATRIX_RGB test suite.
- 731: Expectations about supported font formats
- 734: spurious 'class plain' showing in sphinx rendering of doc/programming_guide/text.txt
- 735: py3: BytesIO and disambiguate div for pyglet/image/__init__.py
- 736: Pyglet media fails to close PulseAudio instances
- 737: 1.2 programming guide mentions ALSA and not Pulse
- 739: FIX: Prevent user mouse stupidity
- 744: expectations and exploration of fonts in Windows
- 747: Document pyglet's "shadow window" functionality
- 754: tests/test.py -- AttributeError: 'module' object has no attribute 'platform' (i.e. pyglet
has no platform)
New features
------------
- New eventloop implementation
- Quartz image decoder
- Improved documentation
- new API: font.have_font(name) return True if named font is installed

@ -0,0 +1,75 @@
#!/usr/bin/env python
'''
'''
from __future__ import print_function
__docformat__ = 'restructuredtext'
__version__ = '$Id: $'
import pyglet
import sys
window = pyglet.window.Window()
@window.event
def on_draw():
window.clear()
remote = pyglet.input.get_apple_remote()
if not remote:
print('Apple IR Remote not available.')
sys.exit(0)
remote.open(window, exclusive=True)
@remote.select_control.event
def on_press():
print('Press select')
@remote.menu_control.event
def on_press():
print('Press menu')
@remote.up_control.event
def on_press():
print('Press up')
@remote.down_control.event
def on_press():
print('Press down')
@remote.left_control.event
def on_press():
print('Press left')
@remote.right_control.event
def on_press():
print('Press right')
@remote.select_control.event
def on_release():
print('Release select')
@remote.menu_control.event
def on_release():
print('Release menu')
@remote.up_control.event
def on_release():
print('Release up')
@remote.down_control.event
def on_release():
print('Release down')
@remote.left_control.event
def on_release():
print('Release left')
@remote.right_control.event
def on_release():
print('Release right')
pyglet.app.run()

@ -0,0 +1,226 @@
'''
A silly demonstration of how to use the Apple remote.
'''
from __future__ import print_function
__docformat__ = 'restructuredtext'
__version__ = '$Id: $'
import pyglet
from pyglet.gl import *
import sys
class MainWindow(pyglet.window.Window):
def __init__(self):
super(MainWindow, self).__init__(visible=False)
self.set_caption('Apple Remote Example')
# Look for the Apple Remote device.
remote = pyglet.input.get_apple_remote()
if not remote:
print('Apple IR Remote not available.')
sys.exit(0)
# Open the remote in exclusive mode so that pressing the remote
# buttons does not activate Front Row, change volume, etc. while
# the remote is being used by our program.
remote.open(self, exclusive=True)
# We push this class onto the remote's event handler stack so that
# the on_button_press and on_button_release methods which we define
# below will be called for the appropriate remote events.
remote.push_handlers(self)
self.carousel = Carousel()
self.setup_opengl()
pyglet.clock.schedule_interval(self.update, 1/60.0)
# Event handler for Apple Remote button press events.
# The button parameter is a string specifying the button that was pressed.
def on_button_press(self, button):
print('on_button_press', button)
if button == 'up':
self.carousel.scroll_up()
elif button == 'down':
self.carousel.scroll_down()
elif button == 'left':
self.carousel.step_left()
elif button == 'right':
self.carousel.step_right()
elif button == 'left_hold':
self.carousel.rotate_left()
elif button == 'right_hold':
self.carousel.rotate_right()
elif button == 'select' or button == 'select_hold':
self.carousel.swap_left()
elif button == 'menu' or button == 'menu_hold':
self.carousel.swap_right()
# Event handler for Apple Remote button release events.
# The button parameter is a string specifying the button that was released.
def on_button_release(self, button):
print('on_button_release', button)
if button == 'left_hold':
self.carousel.stop_rotating()
elif button == 'right_hold':
self.carousel.stop_rotating()
def on_draw(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
gluLookAt(0,3,-12,0,3,0,0,1,0)
self.carousel.draw()
def on_resize(self, width, height):
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
aspect = width / float(height)
glFrustum(-1,1,-1.8/aspect,0.2/aspect,1,100)
glMatrixMode(GL_MODELVIEW)
return pyglet.event.EVENT_HANDLED
def setup_opengl(self):
glClearColor(1,1,1,1)
glEnable(GL_DEPTH_TEST)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
def update(self, dt):
self.carousel.update(dt)
class Carousel:
"""A rotating collection of labeled tiles."""
def __init__(self):
self.num_tiles = 14
self.index = 0
self.float_index = 0.0
self.float_increment = 1.0 / self.num_tiles
self.angle = 0
self.index_diff = 0
self.is_rotating = False
self.speed = 4 * self.num_tiles
# Create the tiles in the carousel.
self.tiles = []
colors = [(255,0,0), (0,255,0), (0,0,255), (255,255,0), (0,205,205), (128,0,128), (255,165,0)]
class Tile:
value = 0
color = [255,255,255]
for i in range(self.num_tiles):
tile = Tile()
tile.value = i % 26
tile.color = colors[i%len(colors)]
self.tiles.append(tile)
# Create glyphs for the characters displayed on the tiles.
font = pyglet.font.load('Courier', 64)
self.glyphs = font.get_glyphs('ABCDEFGHIJKLMNOPQRSTUVWXYZ')
def scroll_up(self):
"""Increment the character displayed on the main tile."""
self.tiles[self.index].value = (self.tiles[self.index].value + 1) % 26
def scroll_down(self):
"""Decrement the character displayed on the main tile."""
self.tiles[self.index].value = (self.tiles[self.index].value - 1) % 26
def swap_left(self):
"""Swap the two left tiles."""
i = self.index
j = (self.index - 1) % self.num_tiles
self.tiles[i], self.tiles[j] = self.tiles[j], self.tiles[i]
def swap_right(self):
"""Swap the two right tiles."""
i = self.index
j = (self.index + 1) % self.num_tiles
self.tiles[i], self.tiles[j] = self.tiles[j], self.tiles[i]
def step_left(self):
"""Rotate the carousel one tile to the left."""
self.direction = -1
self.index_diff += 1.0
def step_right(self):
"""Rotate the carousel one tile to the right."""
self.direction = 1
self.index_diff += 1.0
def rotate_left(self):
"""Start the carousel rotating continuously to the left."""
self.is_rotating = True
self.direction = -1
def rotate_right(self):
"""Start the carousel rotating continuously to the right."""
self.is_rotating = True
self.direction = 1
def stop_rotating(self):
"""Stop continuous rotation and make sure we end up at a tile location."""
self.index_diff = round(self.float_index) - self.float_index
if self.index_diff < 0:
self.direction = -1
else:
self.direction = 1
self.index_diff = abs(self.index_diff)
def draw(self):
glPushMatrix()
glRotatef(-self.angle, 0, 1, 0)
for i in range(self.num_tiles):
self.draw_tile(i)
glPopMatrix()
def draw_tile(self, index):
angle = index * (360.0 / self.num_tiles)
glPushMatrix()
glRotatef(angle,0,1,0)
glTranslatef(0,0,-7.5)
glRotatef(-angle+self.angle,0,1,0)
texture = self.glyphs[self.tiles[index].value].texture
vertex_list = pyglet.graphics.vertex_list(4, 'v2f', ('t3f', texture.tex_coords))
vertex_list.vertices[:] = [-1, -1, 1, -1, 1, 1, -1, 1]
# Draw tile background.
glColor3ub(*self.tiles[index].color)
vertex_list.draw(GL_QUADS)
# Draw tile label.
glBindTexture(texture.target, texture.id)
glEnable(texture.target)
glColor3ub(0,0,0)
vertex_list.vertices[:] = [.8, -.8, -.8, -.8, -.8, .8, .8, .8]
glTranslatef(0,0,-.01)
vertex_list.draw(GL_QUADS)
glDisable(texture.target)
glPopMatrix()
def update(self, dt):
if self.is_rotating or self.index_diff:
increment = self.direction * self.speed * self.float_increment * dt
self.float_index = (self.float_index + increment) % self.num_tiles
if self.index_diff:
self.index_diff -= abs(increment)
if self.index_diff < 0:
self.index_diff = 0
self.float_index = round(self.float_index) % self.num_tiles
self.index = int(self.float_index)
self.is_rotating = False
self.angle = (self.float_index / self.num_tiles) * 360
if __name__ == '__main__':
window = MainWindow()
window.clear()
window.flip()
window.set_visible(True)
pyglet.app.run()

@ -0,0 +1,9 @@
Astraea
=======
This is an example program that accompanies pyglet (http://www.pyglet.org).
The source code is licensed under the BSD license, which is quite permissive
(see the source header for details).
All artwork is placed is Copyright 2007 Alex Holkner.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

@ -0,0 +1,209 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://web.resource.org/cc/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="32"
height="32"
id="svg3070"
sodipodi:version="0.32"
inkscape:version="0.44.1"
sodipodi:docbase="/home/alex/projects/pyglet/examples/astraea/assets"
sodipodi:docname="ship.svg"
version="1.0"
inkscape:export-filename="/home/alex/projects/pyglet/examples/astraea/res/ship.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs3072">
<linearGradient
id="linearGradient3119">
<stop
style="stop-color:white;stop-opacity:1;"
offset="0"
id="stop3121" />
<stop
style="stop-color:black;stop-opacity:1;"
offset="1"
id="stop3123" />
</linearGradient>
<linearGradient
id="linearGradient3109">
<stop
style="stop-color:white;stop-opacity:1;"
offset="0"
id="stop3111" />
<stop
style="stop-color:#655c5c;stop-opacity:1;"
offset="1"
id="stop3113" />
</linearGradient>
<linearGradient
id="linearGradient3099">
<stop
style="stop-color:#6b49ff;stop-opacity:1;"
offset="0"
id="stop3101" />
<stop
id="stop3107"
offset="0.5"
style="stop-color:#eebacf;stop-opacity:1;" />
<stop
style="stop-color:#4500ff;stop-opacity:1;"
offset="1"
id="stop3103" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3109"
id="radialGradient3145"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(5.070103e-2,0,0,6.638822e-2,59.18162,49.76278)"
cx="302.85715"
cy="180.26057"
fx="302.85715"
fy="180.26057"
r="283.35715" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3099"
id="linearGradient3149"
gradientUnits="userSpaceOnUse"
x1="199.5"
y1="260.93323"
x2="411.92856"
y2="260.93323"
gradientTransform="matrix(5.070103e-2,0,0,5.639934e-2,59.18162,47.44653)" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3119"
id="radialGradient3153"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(6.320242e-2,1.027872e-2,-5.698439e-3,4.335767e-2,56.84709,46.03829)"
cx="248.53267"
cy="135.56001"
fx="248.53267"
fy="135.56001"
r="94.22625" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3109"
id="radialGradient3171"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(5.070103e-2,0,0,6.638822e-2,59.18162,49.76278)"
cx="302.85715"
cy="180.26057"
fx="302.85715"
fy="180.26057"
r="283.35715" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3099"
id="linearGradient3173"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(5.070103e-2,0,0,5.639934e-2,59.18162,47.44653)"
x1="199.5"
y1="260.93323"
x2="411.92856"
y2="260.93323" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3119"
id="radialGradient3175"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(6.320242e-2,1.027872e-2,-5.698439e-3,4.335767e-2,56.84709,46.03829)"
cx="248.53267"
cy="135.56001"
fx="248.53267"
fy="135.56001"
r="94.22625" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="black"
bordercolor="#666666"
borderopacity="1.0"
gridtolerance="10000"
guidetolerance="10"
objecttolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="7.9195959"
inkscape:cx="23.023399"
inkscape:cy="1.0153475"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1230"
inkscape:window-height="972"
inkscape:window-x="1280"
inkscape:window-y="0"
height="32px"
width="32px" />
<metadata
id="metadata3075">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-58.43315,-45.9713)">
<g
id="g3162"
transform="matrix(0,1,-1,0,136.5487,-12.6049)"
inkscape:export-filename="/home/alex/projects/pyglet/examples/astraea/res/g3162.png"
inkscape:export-xdpi="92.260002"
inkscape:export-ydpi="92.260002">
<g
transform="matrix(5.407223e-2,0,0,5.923622e-2,58.21259,46.53637)"
style="fill:#878787;fill-opacity:1"
id="g3155">
<path
id="path3080"
style="fill:#878787;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 39.999991,521.64789 C 39.999991,521.64789 -1.0714379,497.09432 19.999991,413.79075 C 41.07142,330.48718 99.99999,230.57647 197.14285,190.93362 C 197.14285,190.93362 408.57143,190.93362 408.57143,190.93362 C 505.71429,230.57647 565.98215,335.48718 585.71429,413.79075 C 605.44643,492.09432 566.42858,521.64789 566.42858,521.64789 L 39.999991,521.64789 z "
sodipodi:nodetypes="czsszcc" />
<path
style="fill:#878787;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 302.85715,-0.4949608 C 293.78238,-0.56477143 200,3.7689443 200,190.93361 C 200,190.93361 144.60089,485.14868 182.82741,499.17944 C 248.05316,523.12006 387.09307,523.87754 439.71284,501.19974 C 469.58981,488.32351 411.42857,189.50504 411.42857,189.50504 C 411.42857,1.5379353 311.75335,-0.42515017 302.85715,-0.4949608 z "
id="path3089"
sodipodi:nodetypes="cssssz" />
<path
style="fill:#878787;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 302.03561,4.833993 C 258.85159,4.833993 208.91203,70.588415 213.14219,146.25535 C 213.96558,160.98368 398.45016,164.68873 399.01025,149.28581 C 402.1541,61.817775 345.21963,4.833993 302.03561,4.833993 z "
id="path3117"
sodipodi:nodetypes="csss" />
</g>
<path
id="path3143"
style="fill:url(#radialGradient3171);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 61.209659,76.867127 C 61.209659,76.867127 59.127295,75.482322 60.195639,70.784056 C 61.263982,66.08579 64.25172,60.450892 69.176962,58.215062 C 69.176962,58.215062 79.896607,58.215062 79.896607,58.215062 C 84.821849,60.450892 87.877492,66.367787 88.877931,70.784056 C 89.878371,75.200327 87.900125,76.867127 87.900125,76.867127 L 61.209659,76.867127 z "
sodipodi:nodetypes="czsszcc" />
<path
style="fill:url(#linearGradient3173);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 74.536785,47.418616 C 74.076685,47.414679 69.321823,47.659098 69.321823,58.215061 C 69.321823,58.215061 66.513032,74.808597 68.451155,75.599922 C 71.758167,76.950157 78.807632,76.992879 81.475508,75.713866 C 82.990301,74.987654 80.041467,58.134491 80.041467,58.134491 C 80.041467,47.53327 74.987832,47.422553 74.536785,47.418616 z "
id="path3147"
sodipodi:nodetypes="cssssz" />
<path
style="fill:url(#radialGradient3175);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 74.495132,47.719164 C 72.305658,47.719164 69.773672,51.427672 69.988145,55.695237 C 70.029892,56.525905 79.383448,56.734867 79.411846,55.866153 C 79.571242,50.933013 76.684606,47.719164 74.495132,47.719164 z "
id="path3151"
sodipodi:nodetypes="csss" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.7 KiB

@ -0,0 +1,895 @@
#!/usr/bin/env python
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of pyglet nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ----------------------------------------------------------------------------
'''A sprite-based game loosely based on the classic "Asteroids".
Shoot the asteroids, get high score.
Left/right: Turn ship
Up: Thrusters
Space: Shoot
'''
import math
import os
import random
import sys
import pyglet
from pyglet.gl import *
from pyglet import resource
from pyglet.window import key
PLAYER_SPIN_SPEED = 360.
PLAYER_ACCEL = 200.
PLAYER_FIRE_DELAY = 0.1
BULLET_SPEED = 1000.
MAX_ASTEROID_SPIN_SPEED = 180.
MAX_ASTEROID_SPEED = 100.
INITIAL_ASTEROIDS = [2, 3, 4, 5]
ASTEROID_DEBRIS_COUNT = 3
MAX_DIFFICULTY = len(INITIAL_ASTEROIDS) - 1
ARENA_WIDTH = 640
ARENA_HEIGHT = 480
KEY_FIRE = key.SPACE
KEY_PAUSE = key.ESCAPE
COLLISION_RESOLUTION = 8
SMOKE_ANIMATION_PERIOD = 0.05
EXPLOSION_ANIMATION_PERIOD = 0.07
PLAYER_FLASH_PERIOD = 0.15
GET_READY_DELAY = 1.
BEGIN_PLAY_DELAY = 2.
LIFE_LOST_DELAY = 2.
FONT_NAME = ('Verdana', 'Helvetica', 'Arial')
INSTRUCTIONS = \
'''Your ship is lost in a peculiar unchartered area of space-time infested with asteroids! You have no chance for survival except to rack up the highest score possible.
Left/Right: Turn ship
Up: Thrusters
Space: Shoot
Be careful, there's not much friction in space.'''
def center_anchor(img):
img.anchor_x = img.width // 2
img.anchor_y = img.height // 2
# --------------------------------------------------------------------------
# Game objects
# --------------------------------------------------------------------------
def wrap(value, width):
if value > width:
value -= width
if value < 0:
value += width
return value
def to_radians(degrees):
return math.pi * degrees / 180.0
class WrappingSprite(pyglet.sprite.Sprite):
dx = 0
dy = 0
rotation_speed = 0
def __init__(self, img, x, y, batch=None):
super(WrappingSprite, self).__init__(img, x, y, batch=batch)
self.collision_radius = self.image.width // COLLISION_RESOLUTION // 2
def update(self, dt):
x = self.x + self.dx * dt
y = self.y + self.dy * dt
rotation = self.rotation + self.rotation_speed * dt
self.x = wrap(x, ARENA_WIDTH)
self.y = wrap(y, ARENA_HEIGHT)
self.rotation = wrap(rotation, 360.)
def collision_cells(self):
'''Generate a sequence of (x, y) cells this object covers,
approximately.'''
radius = self.collision_radius
cellx = int(self.x / COLLISION_RESOLUTION)
celly = int(self.y / COLLISION_RESOLUTION)
for y in range(celly - radius, celly + radius + 1):
for x in range(cellx - radius, cellx + radius + 1):
yield x, y
class AsteroidSize(object):
def __init__(self, filename, points):
self.img = resource.image(filename)
center_anchor(self.img)
self.next_size = None
self.points = points
class Asteroid(WrappingSprite):
def __init__(self, size, x, y, batch=None):
super(Asteroid, self).__init__(size.img, x, y, batch=batch)
self.dx = (random.random() - 0.5) * MAX_ASTEROID_SPEED
self.dy = (random.random() - 0.5) * MAX_ASTEROID_SPEED
self.size = size
self.rotation = random.random() * 360.
self.rotation_speed = (random.random() - 0.5) * MAX_ASTEROID_SPIN_SPEED
self.hit = False
def destroy(self):
global score
score += self.size.points
# Modifies the asteroids list.
next_size = self.size.next_size
if next_size:
# Spawn debris
for i in range(ASTEROID_DEBRIS_COUNT):
asteroids.append(Asteroid(next_size, self.x, self.y,
batch=self.batch))
self.delete()
asteroids.remove(self)
class Player(WrappingSprite, key.KeyStateHandler):
def __init__(self, img, batch=None):
super(Player, self).__init__(img, ARENA_WIDTH // 2, ARENA_HEIGHT // 2,
batch=batch)
center_anchor(img)
self.reset()
def reset(self):
self.x = ARENA_WIDTH // 2
self.y = ARENA_HEIGHT // 2
self.dx = 0
self.dy = 0
self.rotation = 0
self.fire_timeout = 0
self.hit = False
self.invincible = True
self.visible = True
self.flash_timeout = 0
self.flash_visible = False
def update(self, dt):
# Update rotation
if self[key.LEFT]:
self.rotation -= PLAYER_SPIN_SPEED * dt
if self[key.RIGHT]:
self.rotation += PLAYER_SPIN_SPEED * dt
# Get x/y components of orientation
rotation_x = math.cos(to_radians(-self.rotation))
rotation_y = math.sin(to_radians(-self.rotation))
# Update velocity
if self[key.UP]:
self.dx += PLAYER_ACCEL * rotation_x * dt
self.dy += PLAYER_ACCEL * rotation_y * dt
# Update position
super(Player, self).update(dt)
# Fire bullet?
self.fire_timeout -= dt
if self[KEY_FIRE] and self.fire_timeout <= 0 and not self.invincible:
self.fire_timeout = PLAYER_FIRE_DELAY
# For simplicity, start the bullet at the player position. If the
# ship were bigger, or if bullets moved slower we'd adjust this
# based on the orientation of the ship.
bullets.append(Bullet(self.x, self.y,
rotation_x * BULLET_SPEED,
rotation_y * BULLET_SPEED, batch=batch))
if enable_sound:
bullet_sound.play()
# Update flash (invincible) animation
if self.invincible:
self.flash_timeout -= dt
if self.flash_timeout <= 0:
self.flash_timeout = PLAYER_FLASH_PERIOD
self.flash_visible = not self.flash_visible
else:
self.flash_visible = True
self.opacity = (self.visible and self.flash_visible) and 255 or 0
class MovingSprite(pyglet.sprite.Sprite):
def __init__(self, image, x, y, dx, dy, batch=None):
super(MovingSprite, self).__init__(image, x, y, batch=batch)
self.dx = dx
self.dy = dy
def update(self, dt):
self.x += self.dx * dt
self.y += self.dy * dt
class Bullet(MovingSprite):
def __init__(self, x, y, dx, dy, batch=None):
super(Bullet, self).__init__(bullet_image, x, y, dx, dy, batch=batch)
def update(self, dt):
self.x += self.dx * dt
self.y += self.dy * dt
if not (self.x >= 0 and self.x < ARENA_WIDTH and
self.y >= 0 and self.y < ARENA_HEIGHT):
self.delete()
bullets.remove(self)
class EffectSprite(MovingSprite):
def on_animation_end(self):
self.delete()
animations.remove(self)
class Starfield(object):
def __init__(self, img):
self.x = 0
self.y = 0
self.dx = 0.05
self.dy = -0.06
self.img = img
def update(self, dt):
self.x += self.dx * dt
self.y += self.dy * dt
def draw(self):
# Fiddle with the texture matrix to make the starfield slide slowly
# over the window.
glMatrixMode(GL_TEXTURE)
glPushMatrix()
glTranslatef(self.x, self.y, 0)
self.img.blit(0, 0, width=ARENA_WIDTH, height=ARENA_HEIGHT)
glPopMatrix()
glMatrixMode(GL_MODELVIEW)
# --------------------------------------------------------------------------
# Overlays, such as menus and "Game Over" banners
# --------------------------------------------------------------------------
class Overlay(object):
def update(self, dt):
pass
def draw(self):
pass
class Banner(Overlay):
def __init__(self, label, dismiss_func=None, timeout=None):
self.text = pyglet.text.Label(label,
font_name=FONT_NAME,
font_size=36,
x=ARENA_WIDTH // 2,
y=ARENA_HEIGHT // 2,
anchor_x='center',
anchor_y='center')
self.dismiss_func = dismiss_func
self.timeout = timeout
if timeout and dismiss_func:
pyglet.clock.schedule_once(dismiss_func, timeout)
def draw(self):
self.text.draw()
def on_key_press(self, symbol, modifiers):
if self.dismiss_func and not self.timeout:
self.dismiss_func()
return True
class Menu(Overlay):
def __init__(self, title):
self.items = []
self.title_text = pyglet.text.Label(title,
font_name=FONT_NAME,
font_size=36,
x=ARENA_WIDTH // 2,
y=350,
anchor_x='center',
anchor_y='center')
def reset(self):
self.selected_index = 0
self.items[self.selected_index].selected = True
def on_key_press(self, symbol, modifiers):
if symbol == key.DOWN:
self.selected_index += 1
elif symbol == key.UP:
self.selected_index -= 1
self.selected_index = min(max(self.selected_index, 0),
len(self.items) - 1)
if symbol in (key.DOWN, key.UP) and enable_sound:
bullet_sound.play()
def on_key_release(self, symbol, modifiers):
self.items[self.selected_index].on_key_release(symbol, modifiers)
def draw(self):
self.title_text.draw()
for i, item in enumerate(self.items):
item.draw(i == self.selected_index)
class MenuItem(object):
pointer_color = (.46, 0, 1.)
inverted_pointers = False
def __init__(self, label, y, activate_func):
self.y = y
self.text = pyglet.text.Label(label,
font_name=FONT_NAME,
font_size=14,
x=ARENA_WIDTH // 2,
y=y,
anchor_x='center',
anchor_y='center')
self.activate_func = activate_func
def draw_pointer(self, x, y, color, flip=False):
# Tint the pointer image to a color
glPushAttrib(GL_CURRENT_BIT)
glColor3f(*color)
if flip:
pointer_image_flip.blit(x, y)
else:
pointer_image.blit(x, y)
glPopAttrib()
def draw(self, selected):
self.text.draw()
if selected:
self.draw_pointer(
self.text.x - self.text.content_width // 2 -
pointer_image.width // 2,
self.y,
self.pointer_color,
self.inverted_pointers)
self.draw_pointer(
self.text.x + self.text.content_width // 2 +
pointer_image.width // 2,
self.y,
self.pointer_color,
not self.inverted_pointers)
def on_key_release(self, symbol, modifiers):
if symbol == key.ENTER and self.activate_func:
self.activate_func()
if enable_sound:
bullet_sound.play()
class ToggleMenuItem(MenuItem):
pointer_color = (.27, .82, .25)
inverted_pointers = True
def __init__(self, label, value, y, toggle_func):
self.value = value
self.label = label
self.toggle_func = toggle_func
super(ToggleMenuItem, self).__init__(self.get_label(), y, None)
def get_label(self):
return self.label + (self.value and ': ON' or ': OFF')
def on_key_release(self, symbol, modifiers):
if symbol == key.LEFT or symbol == key.RIGHT:
self.value = not self.value
self.text.text = self.get_label()
self.toggle_func(self.value)
if enable_sound:
bullet_sound.play()
class DifficultyMenuItem(MenuItem):
pointer_color = (.27, .82, .25)
inverted_pointers = True
def __init__(self, y):
super(DifficultyMenuItem, self).__init__(self.get_label(), y, None)
def get_label(self):
if difficulty == 0:
return 'Difficulty: Pebbles'
elif difficulty == 1:
return 'Difficulty: Stones'
elif difficulty == 2:
return 'Difficulty: Asteroids'
elif difficulty == 3:
return 'Difficulty: Meteors'
else:
return 'Difficulty: %d' % difficulty
def on_key_release(self, symbol, modifiers):
global difficulty
if symbol == key.LEFT:
difficulty -= 1
elif symbol == key.RIGHT:
difficulty += 1
difficulty = min(max(difficulty, 0), MAX_DIFFICULTY)
self.text.text = self.get_label()
if symbol in (key.LEFT, key.RIGHT) and enable_sound:
bullet_sound.play()
class MainMenu(Menu):
def __init__(self):
super(MainMenu, self).__init__('Astraea')
self.items.append(MenuItem('New Game', 240, begin_game))
self.items.append(MenuItem('Instructions', 200,
begin_instructions_menu))
self.items.append(MenuItem('Options', 160, begin_options_menu))
self.items.append(MenuItem('Quit', 120, sys.exit))
self.reset()
class OptionsMenu(Menu):
def __init__(self):
super(OptionsMenu, self).__init__('Options')
self.items.append(DifficultyMenuItem(280))
def set_enable_sound(value):
global enable_sound
enable_sound = value
self.items.append(ToggleMenuItem('Sound', enable_sound, 240,
set_enable_sound))
def set_enable_fullscreen(value):
win.set_fullscreen(value, width=ARENA_WIDTH, height=ARENA_HEIGHT)
self.items.append(ToggleMenuItem('Fullscreen', win.fullscreen, 200,
set_enable_fullscreen))
self.items.append(ToggleMenuItem('Vsync', win.vsync, 160,
win.set_vsync))
def set_show_fps(value):
global show_fps
show_fps = value
self.items.append(ToggleMenuItem('FPS', show_fps, 120, set_show_fps))
self.items.append(MenuItem('Ok', 60, begin_main_menu))
self.reset()
class InstructionsMenu(Menu):
def __init__(self):
super(InstructionsMenu, self).__init__('Instructions')
self.items.append(MenuItem('Ok', 50, begin_main_menu))
self.reset()
self.instruction_text = pyglet.text.Label(INSTRUCTIONS,
font_name=FONT_NAME,
font_size=14,
x=20, y=300,
width=ARENA_WIDTH - 40,
anchor_y='top',
multiline=True)
def draw(self):
super(InstructionsMenu, self).draw()
self.instruction_text.draw()
class PauseMenu(Menu):
def __init__(self):
super(PauseMenu, self).__init__('Paused')
self.items.append(MenuItem('Continue Game', 240, resume_game))
self.items.append(MenuItem('Main Menu', 200, end_game))
self.reset()
# --------------------------------------------------------------------------
# Game state functions
# --------------------------------------------------------------------------
def check_collisions():
# Check for collisions using an approximate uniform grid.
#
# 1. Mark all grid cells that the bullets are in
# 2. Mark all grid cells that the player is in
# 3. For each asteroid, check grid cells that are covered for
# a collision.
#
# This is by no means perfect collision detection (in particular,
# there are rounding errors, and it doesn't take into account the
# arena wrapping). Improving it is left as an exercise for the
# reader.
# The collision grid. It is recreated each iteration, as bullets move
# quickly.
hit_squares = {}
# 1. Mark all grid cells that the bullets are in. Assume bullets
# occupy a single cell.
for bullet in bullets:
hit_squares[int(bullet.x / COLLISION_RESOLUTION),
int(bullet.y / COLLISION_RESOLUTION)] = bullet
# 2. Mark all grid cells that the player is in.
for x, y in player.collision_cells():
hit_squares[x, y] = player
# 3. Check grid cells of each asteroid for a collision.
for asteroid in asteroids:
for x, y in asteroid.collision_cells():
if (x, y) in hit_squares:
asteroid.hit = True
hit_squares[x, y].hit = True
del hit_squares[x, y]
def begin_main_menu():
set_overlay(MainMenu())
def begin_options_menu():
set_overlay(OptionsMenu())
def begin_instructions_menu():
set_overlay(InstructionsMenu())
def begin_game():
global player_lives
global score
player_lives = 3
score = 0
begin_clear_background()
set_overlay(Banner('Get Ready', begin_first_round, GET_READY_DELAY))
def begin_first_round(*args):
player.reset()
player.visible = True
begin_round()
def next_round(*args):
global in_game
player.invincible = True
in_game = False
set_overlay(Banner('Get Ready', begin_round, GET_READY_DELAY))
def begin_round(*args):
global asteroids
global bullets
global animations
global in_game
asteroids = []
for i in range(INITIAL_ASTEROIDS[difficulty]):
x = random.random() * ARENA_WIDTH
y = random.random() * ARENA_HEIGHT
asteroids.append(Asteroid(asteroid_sizes[-1], x, y, wrapping_batch))
for bullet in bullets:
bullet.delete()
for animation in animations:
animation.delete()
bullets = []
animations = []
in_game = True
set_overlay(None)
pyglet.clock.schedule_once(begin_play, BEGIN_PLAY_DELAY)
def begin_play(*args):
player.invincible = False
def begin_life(*args):
player.reset()
pyglet.clock.schedule_once(begin_play, BEGIN_PLAY_DELAY)
def life_lost(*args):
global player_lives
player_lives -= 1
if player_lives > 0:
begin_life()
else:
game_over()
def game_over():
set_overlay(Banner('Game Over', end_game))
def pause_game():
global paused
paused = True
set_overlay(PauseMenu())
def resume_game():
global paused
paused = False
set_overlay(None)
def end_game():
global in_game
global paused
paused = False
in_game = False
player.invincible = True
pyglet.clock.unschedule(life_lost)
pyglet.clock.unschedule(begin_play)
begin_menu_background()
set_overlay(MainMenu())
def set_overlay(new_overlay):
global overlay
if overlay:
win.remove_handlers(overlay)
overlay = new_overlay
if overlay:
win.push_handlers(overlay)
def begin_menu_background():
global asteroids
global bullets
global animations
global in_game
global player_lives
asteroids = []
for i in range(11):
x = random.random() * ARENA_WIDTH
y = random.random() * ARENA_HEIGHT
asteroids.append(Asteroid(asteroid_sizes[i // 4], x, y, wrapping_batch))
for bullet in bullets:
bullet.delete()
for animation in animations:
animation.delete()
bullets = []
animations = []
in_game = False
player_lives = 0
player.visible = False
def begin_clear_background():
global asteroids
global bullets
global animations
for bullet in bullets:
bullet.delete()
for animation in animations:
animation.delete()
asteroids = []
bullets = []
animations = []
player.visible = False
# --------------------------------------------------------------------------
# Create window
# --------------------------------------------------------------------------
win = pyglet.window.Window(ARENA_WIDTH, ARENA_HEIGHT, caption='Astraea')
@win.event
def on_key_press(symbol, modifiers):
# Overrides default Escape key behaviour
if symbol == KEY_PAUSE and in_game:
if not paused:
pause_game()
else:
resume_game()
return True
elif symbol == key.ESCAPE:
sys.exit()
return pyglet.event.EVENT_HANDLED
@win.event
def on_draw():
glColor3f(1, 1, 1)
# Render
starfield.draw()
for (x, y) in ((0, ARENA_HEIGHT), # Top
(-ARENA_WIDTH, 0), # Left
(0, 0), # Center
(ARENA_WIDTH, 0), # Right
(0, -ARENA_HEIGHT)): # Bottom
glLoadIdentity()
glTranslatef(x, y, 0)
wrapping_batch.draw()
glLoadIdentity()
batch.draw()
glLoadIdentity()
if in_game:
# HUD ship lives
x = 10 + player.image.width // 2
for i in range(player_lives - 1):
player.image.blit(x, win.height - player.image.height // 2 - 10, 0)
x += player.image.width + 10
# HUD score
score_text.text = str(score)
score_text.draw()
if overlay:
overlay.draw()
if show_fps:
fps_display.draw()
# --------------------------------------------------------------------------
# Load resources
# --------------------------------------------------------------------------
batch = pyglet.graphics.Batch()
wrapping_batch = pyglet.graphics.Batch()
resource.path.append('res')
resource.reindex()
asteroid_sizes = [AsteroidSize('asteroid1.png', 100),
AsteroidSize('asteroid2.png', 50),
AsteroidSize('asteroid3.png', 10)]
for small, big in zip(asteroid_sizes[:-1], asteroid_sizes[1:]):
big.next_size = small
bullet_image = resource.image('bullet.png')
center_anchor(bullet_image)
smoke_images_image = resource.image('smoke.png')
smoke_images = pyglet.image.ImageGrid(smoke_images_image, 1, 8)
for smoke_image in smoke_images:
center_anchor(smoke_image)
smoke_animation = \
pyglet.image.Animation.from_image_sequence(smoke_images,
SMOKE_ANIMATION_PERIOD,
loop=False)
explosion_images_image = resource.image('explosion.png')
explosion_images = pyglet.image.ImageGrid(explosion_images_image, 2, 8)
explosion_images = explosion_images.get_texture_sequence()
for explosion_image in explosion_images:
center_anchor(explosion_image)
explosion_animation = \
pyglet.image.Animation.from_image_sequence(explosion_images,
EXPLOSION_ANIMATION_PERIOD,
loop=False)
pointer_image = resource.image('pointer.png')
pointer_image.anchor_x = pointer_image.width // 2
pointer_image.anchor_y = pointer_image.height // 2
pointer_image_flip = resource.image('pointer.png', flip_x=True)
explosion_sound = resource.media('explosion.wav', streaming=False)
bullet_sound = resource.media('bullet.wav', streaming=False)
starfield = Starfield(resource.image('starfield.jpg'))
player = Player(resource.image('ship.png'), wrapping_batch)
win.push_handlers(player)
# --------------------------------------------------------------------------
# Global game state vars
# --------------------------------------------------------------------------
overlay = None
in_game = False
paused = False
score = 0
difficulty = 2
show_fps = False
enable_sound = True
score_text = pyglet.text.Label('',
font_name=FONT_NAME,
font_size=18,
x=ARENA_WIDTH - 10,
y=ARENA_HEIGHT - 10,
anchor_x='right',
anchor_y='top')
fps_display = pyglet.window.FPSDisplay(win)
bullets = []
animations = []
# --------------------------------------------------------------------------
# Game update
# --------------------------------------------------------------------------
def update(dt):
if overlay:
overlay.update(dt)
if not paused:
starfield.update(dt)
player.update(dt)
for asteroid in asteroids:
asteroid.update(dt)
for bullet in bullets[:]:
bullet.update(dt)
for animation in animations[:]:
animation.update(dt)
if not player.invincible:
# Collide bullets and player with asteroids
check_collisions()
# Destroy asteroids that were hit
for asteroid in [a for a in asteroids if a.hit]:
animations.append(EffectSprite(smoke_animation,
asteroid.x, asteroid.y,
asteroid.dx, asteroid.dy,
batch=batch))
asteroid.destroy()
if enable_sound:
explosion_sound.play()
# Check if the player was hit
if player.hit:
animations.append(EffectSprite(explosion_animation,
player.x, player.y,
player.dx, player.dy,
batch=batch))
player.invincible = True
player.visible = False
pyglet.clock.schedule_once(life_lost, LIFE_LOST_DELAY)
# Check if the area is clear
if not asteroids:
next_round()
pyglet.clock.schedule_interval(update, 1/60.)
# --------------------------------------------------------------------------
# Start game
# --------------------------------------------------------------------------
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
begin_menu_background()
begin_main_menu()
pyglet.app.run()

Binary file not shown.

After

Width:  |  Height:  |  Size: 953 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

@ -0,0 +1,92 @@
#!/usr/bin/env python
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of pyglet nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ----------------------------------------------------------------------------
# An example setup.py that can be used to create both standalone Windows
# executables (requires py2exe) and Mac OS X applications (requires py2app).
#
# On Windows::
#
# python setup.py py2exe
#
# On Mac OS X::
#
# python setup.py py2app
#
from distutils.core import setup
import os
# The main entry point of the program
script_file = 'astraea.py'
# Create a list of data files. Add everything in the 'res/' directory.
data_files = []
for file in os.listdir('res'):
file = os.path.join('res', file)
if os.path.isfile(file):
data_files.append(file)
# Setup args that apply to all setups, including ordinary distutils.
setup_args = dict(
data_files=[('res', data_files)]
)
# py2exe options
try:
import py2exe
setup_args.update(dict(
windows=[dict(
script=script_file,
icon_resources=[(1, 'assets/app.ico')],
)],
))
except ImportError:
pass
# py2app options
try:
import py2app
setup_args.update(dict(
app=[script_file],
options=dict(py2app=dict(
argv_emulation=True,
iconfile='assets/app.icns',
)),
))
except ImportError:
pass
setup(**setup_args)

@ -0,0 +1,49 @@
#!/usr/bin/env python
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of pyglet nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ----------------------------------------------------------------------------
'''Prints all window events to stdout.
'''
import pyglet
window = pyglet.window.Window(resizable=True)
@window.event
def on_draw():
window.clear()
window.push_handlers(pyglet.window.event.WindowEventLogger())
pyglet.app.run()

@ -0,0 +1,156 @@
#!/usr/bin/env python
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of pyglet nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ----------------------------------------------------------------------------
# $Id:$
'''Demonstrates one way of fixing the display resolution to a certain
size, but rendering to the full screen.
The method used in this example is:
1. Set the OpenGL viewport to the fixed resolution
2. Render the scene using any OpenGL functions (here, just a polygon)
3. Copy the framebuffer into a texture
4. Reset the OpenGL viewport to the window (full screen) size
5. Blit the texture to the framebuffer
Recent video cards could also render the scene directly to the texture
using EXT_framebuffer_object. (This is not demonstrated in this example).
'''
from pyglet.gl import *
import pyglet
# Create a fullscreen window using the user's desktop resolution. You can
# also use this technique on ordinary resizable windows.
window = pyglet.window.Window(fullscreen=True)
# Use 320x200 fixed resolution to make the effect completely obvious. You
# can change this to a more reasonable value such as 800x600 here.
target_resolution = 320, 200
class FixedResolutionViewport(object):
def __init__(self, window, width, height, filtered=False):
self.window = window
self.width = width
self.height = height
self.texture = pyglet.image.Texture.create(width, height,
rectangle=True)
if not filtered:
# By default the texture will be bilinear filtered when scaled
# up. If requested, turn filtering off. This makes the image
# aliased, but is more suitable for pixel art.
glTexParameteri(self.texture.target,
GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(self.texture.target,
GL_TEXTURE_MIN_FILTER, GL_NEAREST)
def begin(self):
glViewport(0, 0, self.width, self.height)
self.set_fixed_projection()
def end(self):
buffer = pyglet.image.get_buffer_manager().get_color_buffer()
self.texture.blit_into(buffer, 0, 0, 0)
glViewport(0, 0, self.window.width, self.window.height)
self.set_window_projection()
aspect_width = self.window.width / float(self.width)
aspect_height = self.window.height / float(self.height)
if aspect_width > aspect_height:
scale_width = aspect_height * self.width
scale_height = aspect_height * self.height
else:
scale_width = aspect_width * self.width
scale_height = aspect_width * self.height
x = (self.window.width - scale_width) / 2
y = (self.window.height - scale_height) / 2
glClearColor(0, 0, 0, 1)
glClear(GL_COLOR_BUFFER_BIT)
glLoadIdentity()
glColor3f(1, 1, 1)
self.texture.blit(x, y, width=scale_width, height=scale_height)
def set_fixed_projection(self):
# Override this method if you need to change the projection of the
# fixed resolution viewport.
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0, self.width, 0, self.height, -1, 1)
glMatrixMode(GL_MODELVIEW)
def set_window_projection(self):
# This is the same as the default window projection, reprinted here
# for clarity.
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0, self.window.width, 0, self.window.height, -1, 1)
glMatrixMode(GL_MODELVIEW)
target_width, target_height = target_resolution
viewport = FixedResolutionViewport(window,
target_width, target_height, filtered=False)
def draw_scene():
'''Draw the scene, assuming the fixed resolution viewport and projection
have been set up. This just draws the rotated polygon.'''
glClearColor(1, 1, 1, 1)
glClear(GL_COLOR_BUFFER_BIT)
glLoadIdentity()
w, h = target_resolution
glTranslatef(w//2, h//2, 0)
glRotatef(rotate, 0, 0, 1)
glColor3f(1, 0, 0)
s = min(w, h) // 3
glRectf(-s, -s, s, s)
rotate = 0
def update(dt):
global rotate
rotate += dt * 20
pyglet.clock.schedule_interval(update, 1/60.)
@window.event
def on_draw():
viewport.begin()
window.clear()
draw_scene()
viewport.end()
pyglet.app.run()

@ -0,0 +1,155 @@
#!/usr/bin/env python
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of pyglet nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ----------------------------------------------------------------------------
'''A simple tool that may be used to explore font faces. (Windows only)
Only the fonts installed in the system are visible.
Use the left/right cursor keys to change font faces.
By default only the pyglet safe fonts are shown, toggle the safe flag
to see all.
Don't include tabs in the text sample (see
http://pyglet.org/doc-current/programming_guide/text.html#id9 )
'''
from __future__ import print_function, unicode_literals
import pyglet
import pyglet.font.win32query as wq
# support to generate a sample text good to spot monospace compliance.
# Chosen to do a table of fields_per_line columns, each column with field_size
# characters. Fields are filled with a rolling subset of ASCII characters.
class SampleTable(object):
field_size = 7
gap_size = 3
fields_per_line = 7
spaces = ' ' * field_size
max_chars_per_line = (field_size + gap_size) * fields_per_line - gap_size
def __init__(self):
self.lines = []
self.current_line = ''
def newline(self):
self.lines.append(self.current_line)
self.current_line = ''
def add_field(self, s):
assert len(s) <= self.field_size
to_add = self.spaces[len(s):] + s
if self.current_line:
to_add = ' ' * self.gap_size + to_add
if len(self.current_line) + len(to_add) > self.max_chars_per_line:
self.newline()
self.add_field(s)
else:
self.current_line = self.current_line + to_add
def text(self):
return '\n'.join(self.lines)
def sample_text_monospaced_table():
printables = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ '
table = SampleTable()
for i in range(6):
s = printables[i:] + printables[:i]
for k in range(0, len(printables), table.field_size):
table.add_field(s[k:k + table.field_size])
table.newline()
return table.text()
# this worked right with all fonts in a win xp installation
def pyglet_safe(fontentry):
""" this is heuristic and conservative. YMMV. """
return fontentry.vector and fontentry.family != wq.FF_DONTCARE
class Window(pyglet.window.Window):
font_num = 0
def on_text_motion(self, motion):
if motion == pyglet.window.key.MOTION_RIGHT:
self.font_num += 1
if self.font_num == len(font_names):
self.font_num = 0
elif motion == pyglet.window.key.MOTION_LEFT:
self.font_num -= 1
if self.font_num < 0:
self.font_num = len(font_names) - 1
face = font_names[self.font_num]
self.head = pyglet.text.Label(face, font_size=16, y=0,
anchor_y='bottom')
self.text = pyglet.text.Label(sample_text, font_name=face, font_size=12,
y=self.height, anchor_y='top', width=self.width, multiline=True)
def on_draw(self):
self.clear()
self.head.draw()
self.text.draw()
lorem_ipsum = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus.
Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec
consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget
libero egestas mattis sit amet vitae augue.
"""
if __name__ == '__main__':
print(__doc__)
safe = True
sample_text = lorem_ipsum + sample_text_monospaced_table()
# all fonts known by the OS
fontdb = wq.query()
if safe:
candidates = [ f for f in fontdb if pyglet_safe(f)]
else:
canditates = fontdb
# theres one fontentry for each charset supported, so reduce names
font_names = list(set([f.name for f in candidates]))
font_names.sort()
window = Window(1024, 600)
window.on_text_motion(None)
pyglet.app.run()

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -0,0 +1,33 @@
import pyglet
from game import load, resources
# Set up a window
game_window = pyglet.window.Window(800, 600)
# Set up the two top labels
score_label = pyglet.text.Label(text="Score: 0", x=10, y=575)
level_label = pyglet.text.Label(text="Version 1: Static Graphics",
x=400, y=575, anchor_x='center')
# Initialize the player sprite
player_ship = pyglet.sprite.Sprite(img=resources.player_image, x=400, y=300)
# Make three asteroids so we have something to shoot at
asteroids = load.asteroids(3, player_ship.position)
@game_window.event
def on_draw():
game_window.clear()
player_ship.draw()
for asteroid in asteroids:
asteroid.draw()
level_label.draw()
score_label.draw()
if __name__ == "__main__":
# Tell pyglet to do its thing
pyglet.app.run()

@ -0,0 +1,25 @@
import pyglet
import random
import math
from . import resources
def distance(point_1=(0, 0), point_2=(0, 0)):
"""Returns the distance between two points"""
return math.sqrt((point_1[0] - point_2[0]) ** 2 + (point_1[1] - point_2[1]) ** 2)
def asteroids(num_asteroids, player_position):
"""Generate asteroid objects with random positions and velocities,
not close to the player"""
asteroids = []
for i in range(num_asteroids):
asteroid_x, asteroid_y = player_position
while distance((asteroid_x, asteroid_y), player_position) < 100:
asteroid_x = random.randint(0, 800)
asteroid_y = random.randint(0, 600)
new_asteroid = pyglet.sprite.Sprite(img=resources.asteroid_image,
x=asteroid_x, y=asteroid_y)
new_asteroid.rotation = random.randint(0, 360)
asteroids.append(new_asteroid)
return asteroids

@ -0,0 +1,22 @@
import pyglet
def center_image(image):
"""Sets an image's anchor point to its center"""
image.anchor_x = image.width / 2
image.anchor_y = image.height / 2
# Tell pyglet where to find the resources
pyglet.resource.path = ['../resources']
pyglet.resource.reindex()
# Load the three main resources and get them to draw centered
player_image = pyglet.resource.image("player.png")
center_image(player_image)
bullet_image = pyglet.resource.image("bullet.png")
center_image(bullet_image)
asteroid_image = pyglet.resource.image("asteroid.png")
center_image(asteroid_image)

@ -0,0 +1,46 @@
import pyglet, random, math
from game import load, player, resources
# Set up a window
game_window = pyglet.window.Window(800, 600)
main_batch = pyglet.graphics.Batch()
# Set up the two top labels
score_label = pyglet.text.Label(text="Score: 0", x=10, y=575, batch=main_batch)
level_label = pyglet.text.Label(text="Version 2: Basic Motion",
x=400, y=575, anchor_x='center', batch=main_batch)
# Initialize the player sprite
player_ship = player.Player(x=400, y=300, batch=main_batch)
# Make three sprites to represent remaining lives
player_lives = load.player_lives(2, main_batch)
# Make three asteroids so we have something to shoot at
asteroids = load.asteroids(3, player_ship.position, main_batch)
# Store all objects that update each frame in a list
game_objects = [player_ship] + asteroids
# Tell the main window that the player object responds to events
game_window.push_handlers(player_ship)
@game_window.event
def on_draw():
game_window.clear()
main_batch.draw()
def update(dt):
for obj in game_objects:
obj.update(dt)
if __name__ == "__main__":
# Update the game 120 times per second
pyglet.clock.schedule_interval(update, 1 / 120.0)
# Tell pyglet to do its thing
pyglet.app.run()

@ -0,0 +1,36 @@
import pyglet, math, random
from . import physicalobject, resources
def distance(point_1=(0, 0), point_2=(0, 0)):
"""Returns the distance between two points"""
return math.sqrt((point_1[0] - point_2[0]) ** 2 + (point_1[1] - point_2[1]) ** 2)
def player_lives(num_icons, batch=None):
"""Generate sprites for player life icons"""
player_lives = []
for i in range(num_icons):
new_sprite = pyglet.sprite.Sprite(img=resources.player_image,
x=785 - i * 30, y=585,
batch=batch)
new_sprite.scale = 0.5
player_lives.append(new_sprite)
return player_lives
def asteroids(num_asteroids, player_position, batch=None):
"""Generate asteroid objects with random positions and velocities, not close to the player"""
asteroids = []
for i in range(num_asteroids):
asteroid_x, asteroid_y = player_position
while distance((asteroid_x, asteroid_y), player_position) < 100:
asteroid_x = random.randint(0, 800)
asteroid_y = random.randint(0, 600)
new_asteroid = physicalobject.PhysicalObject(img=resources.asteroid_image,
x=asteroid_x, y=asteroid_y,
batch=batch)
new_asteroid.rotation = random.randint(0, 360)
new_asteroid.velocity_x, new_asteroid.velocity_y = random.random() * 40, random.random() * 40
asteroids.append(new_asteroid)
return asteroids

@ -0,0 +1,36 @@
import pyglet
class PhysicalObject(pyglet.sprite.Sprite):
"""A sprite with physical properties such as velocity"""
def __init__(self, *args, **kwargs):
super(PhysicalObject, self).__init__(*args, **kwargs)
# In addition to position, we have velocity
self.velocity_x, self.velocity_y = 0.0, 0.0
def update(self, dt):
"""This method should be called every frame."""
# Update position according to velocity and time
self.x += self.velocity_x * dt
self.y += self.velocity_y * dt
# Wrap around the screen if necessary
self.check_bounds()
def check_bounds(self):
"""Use the classic Asteroids screen wrapping behavior"""
min_x = -self.image.width / 2
min_y = -self.image.height / 2
max_x = 800 + self.image.width / 2
max_y = 600 + self.image.height / 2
if self.x < min_x:
self.x = max_x
elif self.x > max_x:
self.x = min_x
if self.y < min_y:
self.y = max_y
elif self.y > max_y:
self.y = min_y

@ -0,0 +1,48 @@
import math
from pyglet.window import key
from . import physicalobject, resources
class Player(physicalobject.PhysicalObject):
"""Physical object that responds to user input"""
def __init__(self, *args, **kwargs):
super(Player, self).__init__(img=resources.player_image, *args, **kwargs)
# Set some easy-to-tweak constants
self.thrust = 300.0
self.rotate_speed = 200.0
self.keys = dict(left=False, right=False, up=False)
def on_key_press(self, symbol, modifiers):
if symbol == key.UP:
self.keys['up'] = True
elif symbol == key.LEFT:
self.keys['left'] = True
elif symbol == key.RIGHT:
self.keys['right'] = True
def on_key_release(self, symbol, modifiers):
if symbol == key.UP:
self.keys['up'] = False
elif symbol == key.LEFT:
self.keys['left'] = False
elif symbol == key.RIGHT:
self.keys['right'] = False
def update(self, dt):
# Do all the normal physics stuff
super(Player, self).update(dt)
if self.keys['left']:
self.rotation -= self.rotate_speed * dt
if self.keys['right']:
self.rotation += self.rotate_speed * dt
if self.keys['up']:
angle_radians = -math.radians(self.rotation)
force_x = math.cos(angle_radians) * self.thrust * dt
force_y = math.sin(angle_radians) * self.thrust * dt
self.velocity_x += force_x
self.velocity_y += force_y

@ -0,0 +1,22 @@
import pyglet
def center_image(image):
"""Sets an image's anchor point to its center"""
image.anchor_x = image.width / 2
image.anchor_y = image.height / 2
# Tell pyglet where to find the resources
pyglet.resource.path = ['../resources']
pyglet.resource.reindex()
# Load the three main resources and get them to draw centered
player_image = pyglet.resource.image("player.png")
center_image(player_image)
bullet_image = pyglet.resource.image("bullet.png")
center_image(bullet_image)
asteroid_image = pyglet.resource.image("asteroid.png")
center_image(asteroid_image)

@ -0,0 +1,68 @@
import pyglet, random, math
from game import load, player, resources
# Set up a window
game_window = pyglet.window.Window(800, 600)
main_batch = pyglet.graphics.Batch()
# Set up the two top labels
score_label = pyglet.text.Label(text="Score: 0", x=10, y=575, batch=main_batch)
level_label = pyglet.text.Label(text="Version 3: Basic Collision",
x=400, y=575, anchor_x='center', batch=main_batch)
# Initialize the player sprite
player_ship = player.Player(x=400, y=300, batch=main_batch)
# Make three sprites to represent remaining lives
player_lives = load.player_lives(2, main_batch)
# Make three asteroids so we have something to shoot at
asteroids = load.asteroids(3, player_ship.position, main_batch)
# Store all objects that update each frame in a list
game_objects = [player_ship] + asteroids
# Tell the main window that the player object responds to events
game_window.push_handlers(player_ship.key_handler)
@game_window.event
def on_draw():
game_window.clear()
main_batch.draw()
def update(dt):
for obj in game_objects:
obj.update(dt)
# To avoid handling collisions twice, we employ nested loops of ranges.
# This method also avoids the problem of colliding an object with itself.
for i in range(len(game_objects)):
for j in range(i + 1, len(game_objects)):
obj_1 = game_objects[i]
obj_2 = game_objects[j]
# Make sure the objects haven't already been killed
if not obj_1.dead and not obj_2.dead:
if obj_1.collides_with(obj_2):
obj_1.handle_collision_with(obj_2)
obj_2.handle_collision_with(obj_1)
# Get rid of dead objects
for to_remove in [obj for obj in game_objects if obj.dead]:
# Remove the object from any batches it is a member of
to_remove.delete()
# Remove the object from our list
game_objects.remove(to_remove)
if __name__ == "__main__":
# Update the game 120 times per second
pyglet.clock.schedule_interval(update, 1 / 120.0)
# Tell pyglet to do its thing
pyglet.app.run()

@ -0,0 +1,32 @@
import pyglet
import random
from . import physicalobject, resources, util
def player_lives(num_icons, batch=None):
"""Generate sprites for player life icons"""
player_lives = []
for i in range(num_icons):
new_sprite = pyglet.sprite.Sprite(img=resources.player_image,
x=785 - i * 30, y=585,
batch=batch)
new_sprite.scale = 0.5
player_lives.append(new_sprite)
return player_lives
def asteroids(num_asteroids, player_position, batch=None):
"""Generate asteroid objects with random positions and velocities, not close to the player"""
asteroids = []
for i in range(num_asteroids):
asteroid_x, asteroid_y = player_position
while util.distance((asteroid_x, asteroid_y), player_position) < 100:
asteroid_x = random.randint(0, 800)
asteroid_y = random.randint(0, 600)
new_asteroid = physicalobject.PhysicalObject(img=resources.asteroid_image,
x=asteroid_x, y=asteroid_y,
batch=batch)
new_asteroid.rotation = random.randint(0, 360)
new_asteroid.velocity_x, new_asteroid.velocity_y = random.random() * 40, random.random() * 40
asteroids.append(new_asteroid)
return asteroids

@ -0,0 +1,55 @@
import pyglet
from . import util
class PhysicalObject(pyglet.sprite.Sprite):
"""A sprite with physical properties such as velocity"""
def __init__(self, *args, **kwargs):
super(PhysicalObject, self).__init__(*args, **kwargs)
# In addition to position, we have velocity
self.velocity_x, self.velocity_y = 0.0, 0.0
# And a flag to remove this object from the game_object list
self.dead = False
def update(self, dt):
"""This method should be called every frame."""
# Update position according to velocity and time
self.x += self.velocity_x * dt
self.y += self.velocity_y * dt
# Wrap around the screen if necessary
self.check_bounds()
def check_bounds(self):
"""Use the classic Asteroids screen wrapping behavior"""
min_x = -self.image.width / 2
min_y = -self.image.height / 2
max_x = 800 + self.image.width / 2
max_y = 600 + self.image.height / 2
if self.x < min_x:
self.x = max_x
if self.y < min_y:
self.y = max_y
if self.x > max_x:
self.x = min_x
if self.y > max_y:
self.y = min_y
def collides_with(self, other_object):
"""Determine if this object collides with another"""
# Calculate distance between object centers that would be a collision,
# assuming square resources
collision_distance = self.image.width / 2 + other_object.image.width / 2
# Get distance using position tuples
actual_distance = util.distance(self.position, other_object.position)
return (actual_distance <= collision_distance)
def handle_collision_with(self, other_object):
self.dead = True

@ -0,0 +1,52 @@
import pyglet, math
from pyglet.window import key
from . import physicalobject, resources
class Player(physicalobject.PhysicalObject):
"""Physical object that responds to user input"""
def __init__(self, *args, **kwargs):
super(Player, self).__init__(img=resources.player_image, *args, **kwargs)
# Create a child sprite to show when the ship is thrusting
self.engine_sprite = pyglet.sprite.Sprite(img=resources.engine_image, *args, **kwargs)
self.engine_sprite.visible = False
# Set some easy-to-tweak constants
self.thrust = 300.0
self.rotate_speed = 200.0
# Let pyglet handle keyboard events for us
self.key_handler = key.KeyStateHandler()
def update(self, dt):
# Do all the normal physics stuff
super(Player, self).update(dt)
if self.key_handler[key.LEFT]:
self.rotation -= self.rotate_speed * dt
if self.key_handler[key.RIGHT]:
self.rotation += self.rotate_speed * dt
if self.key_handler[key.UP]:
angle_radians = -math.radians(self.rotation)
force_x = math.cos(angle_radians) * self.thrust * dt
force_y = math.sin(angle_radians) * self.thrust * dt
self.velocity_x += force_x
self.velocity_y += force_y
# If thrusting, update the engine sprite
self.engine_sprite.rotation = self.rotation
self.engine_sprite.x = self.x
self.engine_sprite.y = self.y
self.engine_sprite.visible = True
else:
# Otherwise, hide it
self.engine_sprite.visible = False
def delete(self):
# We have a child sprite which must be deleted when this object
# is deleted from batches, etc.
self.engine_sprite.delete()
super(Player, self).delete()

@ -0,0 +1,29 @@
import pyglet
def center_image(image):
"""Sets an image's anchor point to its center"""
image.anchor_x = image.width / 2
image.anchor_y = image.height / 2
# Tell pyglet where to find the resources
pyglet.resource.path = ['../resources']
pyglet.resource.reindex()
# Load the three main resources and get them to draw centered
player_image = pyglet.resource.image("player.png")
center_image(player_image)
bullet_image = pyglet.resource.image("bullet.png")
center_image(bullet_image)
asteroid_image = pyglet.resource.image("asteroid.png")
center_image(asteroid_image)
# The engine flame should not be centered on the ship. Rather, it should be shown
# behind it. To achieve this effect, we just set the anchor point outside the
# image bounds.
engine_image = pyglet.resource.image("engine_flame.png")
engine_image.anchor_x = engine_image.width * 1.5
engine_image.anchor_y = engine_image.height / 2

@ -0,0 +1,6 @@
import pyglet, math
def distance(point_1=(0, 0), point_2=(0, 0)):
"""Returns the distance between two points"""
return math.sqrt((point_1[0] - point_2[0]) ** 2 + (point_1[1] - point_2[1]) ** 2)

@ -0,0 +1,81 @@
import pyglet, random, math
from game import load, player, resources
# Set up a window
game_window = pyglet.window.Window(800, 600)
main_batch = pyglet.graphics.Batch()
# Set up the two top labels
score_label = pyglet.text.Label(text="Score: 0", x=10, y=575, batch=main_batch)
level_label = pyglet.text.Label(text="Version 4: Bullets and Structure",
x=400, y=575, anchor_x='center', batch=main_batch)
# Initialize the player sprite
player_ship = player.Player(x=400, y=300, batch=main_batch)
# Make three sprites to represent remaining lives
player_lives = load.player_lives(2, main_batch)
# Make three asteroids so we have something to shoot at
asteroids = load.asteroids(3, player_ship.position, main_batch)
# Store all objects that update each frame in a list
game_objects = [player_ship] + asteroids
# Add any specified event handlers to the event handler stack
for obj in game_objects:
for handler in obj.event_handlers:
game_window.push_handlers(handler)
@game_window.event
def on_draw():
game_window.clear()
main_batch.draw()
def update(dt):
# To avoid handling collisions twice, we employ nested loops of ranges.
# This method also avoids the problem of colliding an object with itself.
for i in range(len(game_objects)):
for j in range(i + 1, len(game_objects)):
obj_1 = game_objects[i]
obj_2 = game_objects[j]
# Make sure the objects haven't already been killed
if not obj_1.dead and not obj_2.dead:
if obj_1.collides_with(obj_2):
obj_1.handle_collision_with(obj_2)
obj_2.handle_collision_with(obj_1)
# Let's not modify the list while traversing it
to_add = []
for obj in game_objects:
obj.update(dt)
to_add.extend(obj.new_objects)
obj.new_objects = []
# Get rid of dead objects
for to_remove in [obj for obj in game_objects if obj.dead]:
# If the dying object spawned any new objects, add those to the game_objects list later
to_add.extend(obj.new_objects)
# Remove the object from any batches it is a member of
to_remove.delete()
# Remove the object from our list
game_objects.remove(to_remove)
# Add new objects to the list
game_objects.extend(to_add)
if __name__ == "__main__":
# Update the game 120 times per second
pyglet.clock.schedule_interval(update, 1 / 120.0)
# Tell pyglet to do its thing
pyglet.app.run()

@ -0,0 +1,30 @@
import random
from . import physicalobject, resources
class Asteroid(physicalobject.PhysicalObject):
"""An asteroid that divides a little before it dies"""
def __init__(self, *args, **kwargs):
super(Asteroid, self).__init__(resources.asteroid_image, *args, **kwargs)
# Slowly rotate the asteroid as it moves
self.rotate_speed = random.random() * 100.0 - 50.0
def update(self, dt):
super(Asteroid, self).update(dt)
self.rotation += self.rotate_speed * dt
def handle_collision_with(self, other_object):
super(Asteroid, self).handle_collision_with(other_object)
# Superclass handles deadness already
if self.dead and self.scale > 0.25:
num_asteroids = random.randint(2, 3)
for i in range(num_asteroids):
new_asteroid = Asteroid(x=self.x, y=self.y, batch=self.batch)
new_asteroid.rotation = random.randint(0, 360)
new_asteroid.velocity_x = random.random() * 70 + self.velocity_x
new_asteroid.velocity_y = random.random() * 70 + self.velocity_y
new_asteroid.scale = self.scale * 0.5
self.new_objects.append(new_asteroid)

@ -0,0 +1,18 @@
import pyglet
from . import physicalobject, resources
class Bullet(physicalobject.PhysicalObject):
"""Bullets fired by the player"""
def __init__(self, *args, **kwargs):
super(Bullet, self).__init__(resources.bullet_image, *args, **kwargs)
# Bullets shouldn't stick around forever
pyglet.clock.schedule_once(self.die, 0.5)
# Flag as a bullet
self.is_bullet = True
def die(self, dt):
self.dead = True

@ -0,0 +1,30 @@
import pyglet
import random
from . import asteroid, resources, util
def player_lives(num_icons, batch=None):
"""Generate sprites for player life icons"""
player_lives = []
for i in range(num_icons):
new_sprite = pyglet.sprite.Sprite(img=resources.player_image,
x=785 - i * 30, y=585,
batch=batch)
new_sprite.scale = 0.5
player_lives.append(new_sprite)
return player_lives
def asteroids(num_asteroids, player_position, batch=None):
"""Generate asteroid objects with random positions and velocities, not close to the player"""
asteroids = []
for i in range(num_asteroids):
asteroid_x, asteroid_y = player_position
while util.distance((asteroid_x, asteroid_y), player_position) < 100:
asteroid_x = random.randint(0, 800)
asteroid_y = random.randint(0, 600)
new_asteroid = asteroid.Asteroid(x=asteroid_x, y=asteroid_y, batch=batch)
new_asteroid.rotation = random.randint(0, 360)
new_asteroid.velocity_x, new_asteroid.velocity_y = random.random() * 40, random.random() * 40
asteroids.append(new_asteroid)
return asteroids

@ -0,0 +1,73 @@
import pyglet
from . import util
class PhysicalObject(pyglet.sprite.Sprite):
"""A sprite with physical properties such as velocity"""
def __init__(self, *args, **kwargs):
super(PhysicalObject, self).__init__(*args, **kwargs)
# Velocity
self.velocity_x, self.velocity_y = 0.0, 0.0
# Flags to toggle collision with bullets
self.reacts_to_bullets = True
self.is_bullet = False
# Flag to remove this object from the game_object list
self.dead = False
# List of new objects to go in the game_objects list
self.new_objects = []
# Tell the game handler about any event handlers
# Only applies to things with keyboard/mouse input
self.event_handlers = []
def update(self, dt):
"""This method should be called every frame."""
# Update position according to velocity and time
self.x += self.velocity_x * dt
self.y += self.velocity_y * dt
# Wrap around the screen if necessary
self.check_bounds()
def check_bounds(self):
"""Use the classic Asteroids screen wrapping behavior"""
min_x = -self.image.width / 2
min_y = -self.image.height / 2
max_x = 800 + self.image.width / 2
max_y = 600 + self.image.height / 2
if self.x < min_x:
self.x = max_x
if self.y < min_y:
self.y = max_y
if self.x > max_x:
self.x = min_x
if self.y > max_y:
self.y = min_y
def collides_with(self, other_object):
"""Determine if this object collides with another"""
# Ignore bullet collisions if we're supposed to
if not self.reacts_to_bullets and other_object.is_bullet:
return False
if self.is_bullet and not other_object.reacts_to_bullets:
return False
# Calculate distance between object centers that would be a collision,
# assuming square resources
collision_distance = self.image.width / 2 + other_object.image.width / 2
# Get distance using position tuples
actual_distance = util.distance(self.position, other_object.position)
return (actual_distance <= collision_distance)
def handle_collision_with(self, other_object):
if other_object.__class__ is not self.__class__:
self.dead = True

@ -0,0 +1,83 @@
import pyglet, math
from pyglet.window import key
from . import bullet, physicalobject, resources
class Player(physicalobject.PhysicalObject):
"""Physical object that responds to user input"""
def __init__(self, *args, **kwargs):
super(Player, self).__init__(img=resources.player_image, *args, **kwargs)
# Create a child sprite to show when the ship is thrusting
self.engine_sprite = pyglet.sprite.Sprite(img=resources.engine_image, *args, **kwargs)
self.engine_sprite.visible = False
# Set some easy-to-tweak constants
self.thrust = 300.0
self.rotate_speed = 200.0
self.bullet_speed = 700.0
# Player should not collide with own bullets
self.reacts_to_bullets = False
# Tell the game handler about any event handlers
self.key_handler = key.KeyStateHandler()
self.event_handlers = [self, self.key_handler]
def update(self, dt):
# Do all the normal physics stuff
super(Player, self).update(dt)
if self.key_handler[key.LEFT]:
self.rotation -= self.rotate_speed * dt
if self.key_handler[key.RIGHT]:
self.rotation += self.rotate_speed * dt
if self.key_handler[key.UP]:
# Note: pyglet's rotation attributes are in "negative degrees"
angle_radians = -math.radians(self.rotation)
force_x = math.cos(angle_radians) * self.thrust * dt
force_y = math.sin(angle_radians) * self.thrust * dt
self.velocity_x += force_x
self.velocity_y += force_y
# If thrusting, update the engine sprite
self.engine_sprite.rotation = self.rotation
self.engine_sprite.x = self.x
self.engine_sprite.y = self.y
self.engine_sprite.visible = True
else:
# Otherwise, hide it
self.engine_sprite.visible = False
def on_key_press(self, symbol, modifiers):
if symbol == key.SPACE:
self.fire()
def fire(self):
# Note: pyglet's rotation attributes are in "negative degrees"
angle_radians = -math.radians(self.rotation)
# Create a new bullet just in front of the player
ship_radius = self.image.width / 2
bullet_x = self.x + math.cos(angle_radians) * ship_radius
bullet_y = self.y + math.sin(angle_radians) * ship_radius
new_bullet = bullet.Bullet(bullet_x, bullet_y, batch=self.batch)
# Give it some speed
bullet_vx = self.velocity_x + math.cos(angle_radians) * self.bullet_speed
bullet_vy = self.velocity_y + math.sin(angle_radians) * self.bullet_speed
new_bullet.velocity_x, new_bullet.velocity_y = bullet_vx, bullet_vy
# Add it to the list of objects to be added to the game_objects list
self.new_objects.append(new_bullet)
# Play the bullet sound
resources.bullet_sound.play()
def delete(self):
# We have a child sprite which must be deleted when this object
# is deleted from batches, etc.
self.engine_sprite.delete()
super(Player, self).delete()

@ -0,0 +1,32 @@
import pyglet
def center_image(image):
"""Sets an image's anchor point to its center"""
image.anchor_x = image.width / 2
image.anchor_y = image.height / 2
# Tell pyglet where to find the resources
pyglet.resource.path = ['../resources']
pyglet.resource.reindex()
# Load the three main resources and get them to draw centered
player_image = pyglet.resource.image("player.png")
center_image(player_image)
bullet_image = pyglet.resource.image("bullet.png")
center_image(bullet_image)
asteroid_image = pyglet.resource.image("asteroid.png")
center_image(asteroid_image)
# The engine flame should not be centered on the ship. Rather, it should be shown
# behind it. To achieve this effect, we just set the anchor point outside the
# image bounds.
engine_image = pyglet.resource.image("engine_flame.png")
engine_image.anchor_x = engine_image.width * 1.5
engine_image.anchor_y = engine_image.height / 2
# Load the bullet sound _without_ streaming so we can play it more than once at a time
bullet_sound = pyglet.resource.media("bullet.wav", streaming=False)

@ -0,0 +1,12 @@
import pyglet, math
def distance(point_1=(0, 0), point_2=(0, 0)):
"""Returns the distance between two points"""
return math.sqrt((point_1[0] - point_2[0]) ** 2 + (point_1[1] - point_2[1]) ** 2)
def center_image(image):
"""Sets an image's anchor point to its center"""
image.anchor_x = image.width / 2
image.anchor_y = image.height / 2

@ -0,0 +1,163 @@
import pyglet, random, math
from game import asteroid, load, player, resources
# Set up a window
game_window = pyglet.window.Window(800, 600)
main_batch = pyglet.graphics.Batch()
# Set up the two top labels
score_label = pyglet.text.Label(text="Score: 0", x=10, y=575, batch=main_batch)
level_label = pyglet.text.Label(text="Version 5: It's a Game!",
x=400, y=575, anchor_x='center', batch=main_batch)
# Set up the game over label offscreen
game_over_label = pyglet.text.Label(text="GAME OVER",
x=400, y=-300, anchor_x='center',
batch=main_batch, font_size=48)
counter = pyglet.clock.ClockDisplay()
player_ship = None
player_lives = []
score = 0
num_asteroids = 3
game_objects = []
# We need to pop off as many event stack frames as we pushed on
# every time we reset the level.
event_stack_size = 0
def init():
global score, num_asteroids
score = 0
score_label.text = "Score: " + str(score)
num_asteroids = 3
reset_level(2)
def reset_level(num_lives=2):
global player_ship, player_lives, game_objects, event_stack_size
# Clear the event stack of any remaining handlers from other levels
while event_stack_size > 0:
game_window.pop_handlers()
event_stack_size -= 1
for life in player_lives:
life.delete()
# Initialize the player sprite
player_ship = player.Player(x=400, y=300, batch=main_batch)
# Make three sprites to represent remaining lives
player_lives = load.player_lives(num_lives, main_batch)
# Make some asteroids so we have something to shoot at
asteroids = load.asteroids(num_asteroids, player_ship.position, main_batch)
# Store all objects that update each frame in a list
game_objects = [player_ship] + asteroids
# Add any specified event handlers to the event handler stack
for obj in game_objects:
for handler in obj.event_handlers:
game_window.push_handlers(handler)
event_stack_size += 1
@game_window.event
def on_draw():
game_window.clear()
main_batch.draw()
counter.draw()
def update(dt):
global score, num_asteroids
player_dead = False
victory = False
# To avoid handling collisions twice, we employ nested loops of ranges.
# This method also avoids the problem of colliding an object with itself.
for i in range(len(game_objects)):
for j in range(i + 1, len(game_objects)):
obj_1 = game_objects[i]
obj_2 = game_objects[j]
# Make sure the objects haven't already been killed
if not obj_1.dead and not obj_2.dead:
if obj_1.collides_with(obj_2):
obj_1.handle_collision_with(obj_2)
obj_2.handle_collision_with(obj_1)
# Let's not modify the list while traversing it
to_add = []
# Check for win condition
asteroids_remaining = 0
for obj in game_objects:
obj.update(dt)
to_add.extend(obj.new_objects)
obj.new_objects = []
# Check for win condition
if isinstance(obj, asteroid.Asteroid):
asteroids_remaining += 1
if asteroids_remaining == 0:
# Don't act on victory until the end of the time step
victory = True
# Get rid of dead objects
for to_remove in [obj for obj in game_objects if obj.dead]:
if to_remove == player_ship:
player_dead = True
# If the dying object spawned any new objects, add those to the
# game_objects list later
to_add.extend(to_remove.new_objects)
# Remove the object from any batches it is a member of
to_remove.delete()
# Remove the object from our list
game_objects.remove(to_remove)
# Bump the score if the object to remove is an asteroid
if isinstance(to_remove, asteroid.Asteroid):
score += 1
score_label.text = "Score: " + str(score)
# Add new objects to the list
game_objects.extend(to_add)
# Check for win/lose conditions
if player_dead:
# We can just use the length of the player_lives list as the number of lives
if len(player_lives) > 0:
reset_level(len(player_lives) - 1)
else:
game_over_label.y = 300
elif victory:
num_asteroids += 1
player_ship.delete()
score += 10
reset_level(len(player_lives))
if __name__ == "__main__":
# Start it up!
init()
# Update the game 120 times per second
pyglet.clock.schedule_interval(update, 1 / 120.0)
# Tell pyglet to do its thing
pyglet.app.run()

@ -0,0 +1,30 @@
import random
from . import physicalobject, resources
class Asteroid(physicalobject.PhysicalObject):
"""An asteroid that divides a little before it dies"""
def __init__(self, *args, **kwargs):
super(Asteroid, self).__init__(resources.asteroid_image, *args, **kwargs)
# Slowly rotate the asteroid as it moves
self.rotate_speed = random.random() * 100.0 - 50.0
def update(self, dt):
super(Asteroid, self).update(dt)
self.rotation += self.rotate_speed * dt
def handle_collision_with(self, other_object):
super(Asteroid, self).handle_collision_with(other_object)
# Superclass handles deadness already
if self.dead and self.scale > 0.25:
num_asteroids = random.randint(2, 3)
for i in range(num_asteroids):
new_asteroid = Asteroid(x=self.x, y=self.y, batch=self.batch)
new_asteroid.rotation = random.randint(0, 360)
new_asteroid.velocity_x = random.random() * 70 + self.velocity_x
new_asteroid.velocity_y = random.random() * 70 + self.velocity_y
new_asteroid.scale = self.scale * 0.5
self.new_objects.append(new_asteroid)

@ -0,0 +1,18 @@
import pyglet
from . import physicalobject, resources
class Bullet(physicalobject.PhysicalObject):
"""Bullets fired by the player"""
def __init__(self, *args, **kwargs):
super(Bullet, self).__init__(resources.bullet_image, *args, **kwargs)
# Bullets shouldn't stick around forever
pyglet.clock.schedule_once(self.die, 0.5)
# Flag as a bullet
self.is_bullet = True
def die(self, dt):
self.dead = True

@ -0,0 +1,30 @@
import pyglet
import random
from . import asteroid, resources, util
def player_lives(num_icons, batch=None):
"""Generate sprites for player life icons"""
player_lives = []
for i in range(num_icons):
new_sprite = pyglet.sprite.Sprite(img=resources.player_image,
x=785 - i * 30, y=585,
batch=batch)
new_sprite.scale = 0.5
player_lives.append(new_sprite)
return player_lives
def asteroids(num_asteroids, player_position, batch=None):
"""Generate asteroid objects with random positions and velocities, not close to the player"""
asteroids = []
for i in range(num_asteroids):
asteroid_x, asteroid_y = player_position
while util.distance((asteroid_x, asteroid_y), player_position) < 100:
asteroid_x = random.randint(0, 800)
asteroid_y = random.randint(0, 600)
new_asteroid = asteroid.Asteroid(x=asteroid_x, y=asteroid_y, batch=batch)
new_asteroid.rotation = random.randint(0, 360)
new_asteroid.velocity_x, new_asteroid.velocity_y = random.random() * 40, random.random() * 40
asteroids.append(new_asteroid)
return asteroids

@ -0,0 +1,74 @@
import pyglet
from . import util
class PhysicalObject(pyglet.sprite.Sprite):
"""A sprite with physical properties such as velocity"""
def __init__(self, *args, **kwargs):
super(PhysicalObject, self).__init__(*args, **kwargs)
# Velocity
self.velocity_x, self.velocity_y = 0.0, 0.0
# Flags to toggle collision with bullets
self.reacts_to_bullets = True
self.is_bullet = False
# Flag to remove this object from the game_object list
self.dead = False
# List of new objects to go in the game_objects list
self.new_objects = []
# Tell the game handler about any event handlers
# Only applies to things with keyboard/mouse input
self.event_handlers = []
def update(self, dt):
"""This method should be called every frame."""
# Update position according to velocity and time
self.x += self.velocity_x * dt
self.y += self.velocity_y * dt
# Wrap around the screen if necessary
self.check_bounds()
def check_bounds(self):
"""Use the classic Asteroids screen wrapping behavior"""
min_x = -self.image.width / 2
min_y = -self.image.height / 2
max_x = 800 + self.image.width / 2
max_y = 600 + self.image.height / 2
if self.x < min_x:
self.x = max_x
if self.y < min_y:
self.y = max_y
if self.x > max_x:
self.x = min_x
if self.y > max_y:
self.y = min_y
def collides_with(self, other_object):
"""Determine if this object collides with another"""
# Ignore bullet collisions if we're supposed to
if not self.reacts_to_bullets and other_object.is_bullet:
return False
if self.is_bullet and not other_object.reacts_to_bullets:
return False
# Calculate distance between object centers that would be a collision,
# assuming square resources
collision_distance = self.image.width * 0.5 * self.scale \
+ other_object.image.width * 0.5 * other_object.scale
# Get distance using position tuples
actual_distance = util.distance(self.position, other_object.position)
return (actual_distance <= collision_distance)
def handle_collision_with(self, other_object):
if other_object.__class__ is not self.__class__:
self.dead = True

@ -0,0 +1,83 @@
import pyglet, math
from pyglet.window import key
from . import bullet, physicalobject, resources
class Player(physicalobject.PhysicalObject):
"""Physical object that responds to user input"""
def __init__(self, *args, **kwargs):
super(Player, self).__init__(img=resources.player_image, *args, **kwargs)
# Create a child sprite to show when the ship is thrusting
self.engine_sprite = pyglet.sprite.Sprite(img=resources.engine_image, *args, **kwargs)
self.engine_sprite.visible = False
# Set some easy-to-tweak constants
self.thrust = 300.0
self.rotate_speed = 200.0
self.bullet_speed = 700.0
# Player should not collide with own bullets
self.reacts_to_bullets = False
# Tell the game handler about any event handlers
self.key_handler = key.KeyStateHandler()
self.event_handlers = [self, self.key_handler]
def update(self, dt):
# Do all the normal physics stuff
super(Player, self).update(dt)
if self.key_handler[key.LEFT]:
self.rotation -= self.rotate_speed * dt
if self.key_handler[key.RIGHT]:
self.rotation += self.rotate_speed * dt
if self.key_handler[key.UP]:
# Note: pyglet's rotation attributes are in "negative degrees"
angle_radians = -math.radians(self.rotation)
force_x = math.cos(angle_radians) * self.thrust * dt
force_y = math.sin(angle_radians) * self.thrust * dt
self.velocity_x += force_x
self.velocity_y += force_y
# If thrusting, update the engine sprite
self.engine_sprite.rotation = self.rotation
self.engine_sprite.x = self.x
self.engine_sprite.y = self.y
self.engine_sprite.visible = True
else:
# Otherwise, hide it
self.engine_sprite.visible = False
def on_key_press(self, symbol, modifiers):
if symbol == key.SPACE:
self.fire()
def fire(self):
# Note: pyglet's rotation attributes are in "negative degrees"
angle_radians = -math.radians(self.rotation)
# Create a new bullet just in front of the player
ship_radius = self.image.width / 2
bullet_x = self.x + math.cos(angle_radians) * ship_radius
bullet_y = self.y + math.sin(angle_radians) * ship_radius
new_bullet = bullet.Bullet(bullet_x, bullet_y, batch=self.batch)
# Give it some speed
bullet_vx = self.velocity_x + math.cos(angle_radians) * self.bullet_speed
bullet_vy = self.velocity_y + math.sin(angle_radians) * self.bullet_speed
new_bullet.velocity_x, new_bullet.velocity_y = bullet_vx, bullet_vy
# Add it to the list of objects to be added to the game_objects list
self.new_objects.append(new_bullet)
# Play the bullet sound
resources.bullet_sound.play()
def delete(self):
# We have a child sprite which must be deleted when this object
# is deleted from batches, etc.
self.engine_sprite.delete()
super(Player, self).delete()

@ -0,0 +1,32 @@
import pyglet
def center_image(image):
"""Sets an image's anchor point to its center"""
image.anchor_x = image.width / 2
image.anchor_y = image.height / 2
# Tell pyglet where to find the resources
pyglet.resource.path = ['../resources']
pyglet.resource.reindex()
# Load the three main resources and get them to draw centered
player_image = pyglet.resource.image("player.png")
center_image(player_image)
bullet_image = pyglet.resource.image("bullet.png")
center_image(bullet_image)
asteroid_image = pyglet.resource.image("asteroid.png")
center_image(asteroid_image)
# The engine flame should not be centered on the ship. Rather, it should be shown
# behind it. To achieve this effect, we just set the anchor point outside the
# image bounds.
engine_image = pyglet.resource.image("engine_flame.png")
engine_image.anchor_x = engine_image.width * 1.5
engine_image.anchor_y = engine_image.height / 2
# Load the bullet sound _without_ streaming so we can play it more than once at a time
bullet_sound = pyglet.resource.media("bullet.wav", streaming=False)

@ -0,0 +1,12 @@
import pyglet, math
def distance(point_1=(0, 0), point_2=(0, 0)):
"""Returns the distance between two points"""
return math.sqrt((point_1[0] - point_2[0]) ** 2 + (point_1[1] - point_2[1]) ** 2)
def center_image(image):
"""Sets an image's anchor point to its center"""
image.anchor_x = image.width / 2
image.anchor_y = image.height / 2

@ -0,0 +1,179 @@
#!/usr/bin/env python
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of pyglet nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ----------------------------------------------------------------------------
'''Displays a rotating torus using the pyglet.graphics API.
This example is very similar to examples/opengl.py, but uses the
pyglet.graphics API to construct the indexed vertex arrays instead of
using OpenGL calls explicitly. This has the advantage that VBOs will
be used on supporting hardware automatically.
The vertex list is added to a batch, allowing it to be easily rendered
alongside other vertex lists with minimal overhead.
'''
from math import pi, sin, cos
import pyglet
from pyglet.gl import *
try:
# Try and create a window with multisampling (antialiasing)
config = Config(sample_buffers=1, samples=4,
depth_size=16, double_buffer=True,)
window = pyglet.window.Window(resizable=True, config=config)
except pyglet.window.NoSuchConfigException:
# Fall back to no multisampling for old hardware
window = pyglet.window.Window(resizable=True)
@window.event
def on_resize(width, height):
# Override the default on_resize handler to create a 3D projection
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(60., width / float(height), .1, 1000.)
glMatrixMode(GL_MODELVIEW)
return pyglet.event.EVENT_HANDLED
def update(dt):
global rx, ry, rz
rx += dt * 1
ry += dt * 80
rz += dt * 30
rx %= 360
ry %= 360
rz %= 360
pyglet.clock.schedule(update)
@window.event
def on_draw():
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
glTranslatef(0, 0, -4)
glRotatef(rz, 0, 0, 1)
glRotatef(ry, 0, 1, 0)
glRotatef(rx, 1, 0, 0)
batch.draw()
def setup():
# One-time GL setup
glClearColor(1, 1, 1, 1)
glColor3f(1, 0, 0)
glEnable(GL_DEPTH_TEST)
glEnable(GL_CULL_FACE)
# Uncomment this line for a wireframe view
#glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
# Simple light setup. On Windows GL_LIGHT0 is enabled by default,
# but this is not the case on Linux or Mac, so remember to always
# include it.
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_LIGHT1)
# Define a simple function to create ctypes arrays of floats:
def vec(*args):
return (GLfloat * len(args))(*args)
glLightfv(GL_LIGHT0, GL_POSITION, vec(.5, .5, 1, 0))
glLightfv(GL_LIGHT0, GL_SPECULAR, vec(.5, .5, 1, 1))
glLightfv(GL_LIGHT0, GL_DIFFUSE, vec(1, 1, 1, 1))
glLightfv(GL_LIGHT1, GL_POSITION, vec(1, 0, .5, 0))
glLightfv(GL_LIGHT1, GL_DIFFUSE, vec(.5, .5, .5, 1))
glLightfv(GL_LIGHT1, GL_SPECULAR, vec(1, 1, 1, 1))
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, vec(0.5, 0, 0.3, 1))
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, vec(1, 1, 1, 1))
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 50)
class Torus(object):
list = None
def __init__(self, radius, inner_radius, slices, inner_slices,
batch, group=None):
# Create the vertex and normal arrays.
vertices = []
normals = []
u_step = 2 * pi / (slices - 1)
v_step = 2 * pi / (inner_slices - 1)
u = 0.
for i in range(slices):
cos_u = cos(u)
sin_u = sin(u)
v = 0.
for j in range(inner_slices):
cos_v = cos(v)
sin_v = sin(v)
d = (radius + inner_radius * cos_v)
x = d * cos_u
y = d * sin_u
z = inner_radius * sin_v
nx = cos_u * cos_v
ny = sin_u * cos_v
nz = sin_v
vertices.extend([x, y, z])
normals.extend([nx, ny, nz])
v += v_step
u += u_step
# Create a list of triangle indices.
indices = []
for i in range(slices - 1):
for j in range(inner_slices - 1):
p = i * inner_slices + j
indices.extend([p, p + inner_slices, p + inner_slices + 1])
indices.extend([p, p + inner_slices + 1, p + 1])
self.vertex_list = batch.add_indexed(len(vertices)//3,
GL_TRIANGLES,
group,
indices,
('v3f/static', vertices),
('n3f/static', normals))
def delete(self):
self.vertex_list.delete()
setup()
batch = pyglet.graphics.Batch()
torus = Torus(1, 0.3, 50, 30, batch=batch)
rx = ry = rz = 0
pyglet.app.run()

@ -0,0 +1,78 @@
#!/usr/bin/env python
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of pyglet nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ----------------------------------------------------------------------------
'''A simple demonstration of the HTMLLabel class, as it might be used on a
help or introductory screen.
'''
__docformat__ = 'restructuredtext'
__version__ = '$Id: $'
import os
import pyglet
html = '''
<h1>HTML labels in pyglet</h1>
<p align="center"><img src="pyglet.png" /></p>
<p>HTML labels are a simple way to add formatted text to your application.
Different <font face="Helvetica,Arial" size=+2>fonts</font>, <em>styles</em>
and <font color=maroon>colours</font> are supported.
<p>This window has been made resizable; text will reflow to fit the new size.
'''
window = pyglet.window.Window(resizable=True)
location = pyglet.resource.FileLocation(os.path.dirname(__file__))
label = pyglet.text.HTMLLabel(html, location=location,
width=window.width,
multiline=True, anchor_y='center')
@window.event
def on_resize(width, height):
# Wrap text to the width of the window
label.width = window.width
# Keep text vertically centered in the window
label.y = window.height // 2
@window.event
def on_draw():
window.clear()
label.draw()
pyglet.gl.glClearColor(1, 1, 1, 1)
pyglet.app.run()

@ -0,0 +1,68 @@
#!/usr/bin/env python
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of pyglet nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ----------------------------------------------------------------------------
'''Convert an image to another file format supported by pyglet.
Usage::
python image_convert.py <src-file> <dest-file>
'''
from __future__ import print_function
import sys
import pyglet
def convert(src, dest):
if '.dds' in src.lower():
# Compressed textures need to be uploaded to the video card before
# they can be saved.
texture = pyglet.image.load(src).get_texture()
texture.save(dest)
else:
# Otherwise just save the loaded image in the new format.
image = pyglet.image.load(src)
image.save(dest)
if __name__ == '__main__':
if len(sys.argv) != 3:
print(__doc__)
sys.exit(1)
src = sys.argv[1]
dest = sys.argv[2]
convert(src, dest)

@ -0,0 +1,84 @@
#!/usr/bin/env python
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of pyglet nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ----------------------------------------------------------------------------
'''Display an image.
Usage::
display.py <filename>
A checkerboard background is visible behind any transparent areas of the
image.
'''
from __future__ import print_function
import sys
import pyglet
from pyglet.gl import *
window = pyglet.window.Window(visible=False, resizable=True)
@window.event
def on_draw():
background.blit_tiled(0, 0, 0, window.width, window.height)
img.blit(window.width // 2, window.height // 2, 0)
if __name__ == '__main__':
if len(sys.argv) != 2:
print(__doc__)
sys.exit(1)
filename = sys.argv[1]
img = pyglet.image.load(filename).get_texture(rectangle=True)
img.anchor_x = img.width // 2
img.anchor_y = img.height // 2
checks = pyglet.image.create(32, 32, pyglet.image.CheckerImagePattern())
background = pyglet.image.TileableTexture.create_for_image(checks)
# Enable alpha blending, required for image.blit.
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
window.width = img.width
window.height = img.height
window.set_visible()
pyglet.app.run()

@ -0,0 +1,45 @@
#!/usr/bin/env python
'''
'''
from __future__ import print_function
__docformat__ = 'restructuredtext'
__version__ = '$Id: $'
import pyglet
window = pyglet.window.Window()
devices = pyglet.input.get_devices()
def watch_control(device, control):
@control.event
def on_change(value):
print('%r: %r.on_change(%r)' % (device, control, value))
if isinstance(control, pyglet.input.base.Button):
@control.event
def on_press():
print('%r: %r.on_press()' % (device, control))
@control.event
def on_release():
print('%r: %r.on_release()' % (device, control))
print('Devices:')
for device in devices:
print(' ', device.name, end=' ')
try:
device.open(window=window)
print('OK')
for control in device.get_controls():
print(' ', control.name)
watch_control(device, control)
except pyglet.input.DeviceException:
print('Fail')
pyglet.app.run()

@ -0,0 +1,63 @@
#!/usr/bin/env python
'''
'''
__docformat__ = 'restructuredtext'
__version__ = '$Id: $'
import pyglet
from pyglet.gl import *
joysticks = pyglet.input.get_joysticks()
assert joysticks, 'No joystick device is connected'
joystick = joysticks[0]
joystick.open()
window = pyglet.window.Window()
@window.event
def on_draw():
x = (0.8*joystick.x + 1) * window.width / 2
y = (-0.8*joystick.y + 1) * window.height / 2
z = joystick.z
angle = joystick.rz * 180
# Axes
glClear(GL_COLOR_BUFFER_BIT)
glColor3f(1, 0, 0)
glLoadIdentity()
glTranslatef(x, y, 0)
glScalef(1 + z, 1 + z, 1 + z)
glRotatef(-angle, 0, 0, 1)
glBegin(GL_TRIANGLES)
glVertex2f(-10, 0)
glVertex2f(0, 13)
glVertex2f(10, 0)
glEnd()
# Buttons
glLoadIdentity()
x = 10
y = 10
glPointSize(5)
glBegin(GL_POINTS)
for button in joystick.buttons:
if button:
glVertex2f(x, y)
x += 20
glEnd()
# Hat
glColor3f(0, 0, 1)
x = window.width / 2
y = window.height / 2
glBegin(GL_POINTS)
glVertex2f(x + joystick.hat_x * 50, y + joystick.hat_y * 50)
glEnd()
pyglet.clock.schedule(lambda dt: None)
pyglet.app.run()

@ -0,0 +1,94 @@
#!/usr/bin/env python
'''Print details of a media file that pyglet can open (requires AVbin).
Usage::
media_info.py <filename>
'''
from __future__ import print_function
__docformat__ = 'restructuredtext'
__version__ = '$Id: $'
import sys
import pyglet
def print_avbin_info():
from pyglet.media import have_avbin
if have_avbin():
from pyglet.media.sources import avbin
print('Using AVbin version %d (FFmpeg r%d)' % (
avbin.get_version(),
avbin.av.avbin_get_ffmpeg_revision()))
else:
print('AVbin not available; required for media decoding.')
print('http://code.google.com/p/avbin')
print()
def print_source_info(source):
if source.info:
if source.info.title:
print('Title: %s' % source.info.title)
if source.info.album:
print('Album: %s' % source.info.album)
if source.info.author:
print('Author: %s' % source.info.author)
if source.info.year:
print('Year: %d' % source.info.year)
if source.info.track:
print('Track: %d' % source.info.track)
if source.info.genre:
print('Genre: %s' % source.info.genre)
if source.info.copyright:
print('Copyright: %s' % source.info.copyright)
if source.info.comment:
print('Comment: %s' % source.info.comment)
if source.audio_format:
af = source.audio_format
print('Audio: %d channel(s), %d bits, %.02f Hz' % (
af.channels, af.sample_size, af.sample_rate))
if source.video_format:
vf = source.video_format
if vf.frame_rate:
frame_rate = '%.02f' % vf.frame_rate
else:
frame_rate = 'unknown'
if vf.sample_aspect >= 1:
display_width = vf.sample_aspect * vf.width
display_height = vf.height
else:
display_width = vf.width
display_height = vf.sample_aspect / vf.height
print('Video: %dx%d at aspect %r (displays at %dx%d), %s fps' % (
vf.width, vf.height, vf.sample_aspect,
display_width, display_height, frame_rate))
hours = int(source.duration / 3600)
minutes = int(source.duration / 60) % 60
seconds = int(source.duration) % 60
milliseconds = int(source.duration * 1000) % 1000
print('Duration: %d:%02d:%02d.%03d' % (
hours, minutes, seconds, milliseconds))
if __name__ == '__main__':
if len(sys.argv) != 2:
print(__doc__)
print_avbin_info()
sys.exit(1)
print_avbin_info()
filename = sys.argv[1]
try:
source = pyglet.media.load(filename, streaming=True)
print_source_info(source)
except pyglet.media.MediaException:
print('Could not open %s' % filename)

@ -0,0 +1,345 @@
#!/usr/bin/env python
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of pyglet nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ----------------------------------------------------------------------------
'''Audio and video player with simple GUI controls.
'''
from __future__ import print_function
__docformat__ = 'restructuredtext'
__version__ = '$Id: $'
import sys
from pyglet.gl import *
import pyglet
from pyglet.window import key
def draw_rect(x, y, width, height):
glBegin(GL_LINE_LOOP)
glVertex2f(x, y)
glVertex2f(x + width, y)
glVertex2f(x + width, y + height)
glVertex2f(x, y + height)
glEnd()
class Control(pyglet.event.EventDispatcher):
x = y = 0
width = height = 10
def __init__(self, parent):
super(Control, self).__init__()
self.parent = parent
def hit_test(self, x, y):
return (self.x < x < self.x + self.width and
self.y < y < self.y + self.height)
def capture_events(self):
self.parent.push_handlers(self)
def release_events(self):
self.parent.remove_handlers(self)
class Button(Control):
charged = False
def draw(self):
if self.charged:
glColor3f(1, 0, 0)
draw_rect(self.x, self.y, self.width, self.height)
glColor3f(1, 1, 1)
self.draw_label()
def on_mouse_press(self, x, y, button, modifiers):
self.capture_events()
self.charged = True
def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
self.charged = self.hit_test(x, y)
def on_mouse_release(self, x, y, button, modifiers):
self.release_events()
if self.hit_test(x, y):
self.dispatch_event('on_press')
self.charged = False
Button.register_event_type('on_press')
class TextButton(Button):
def __init__(self, *args, **kwargs):
super(TextButton, self).__init__(*args, **kwargs)
self._text = pyglet.text.Label('', anchor_x='center', anchor_y='center')
def draw_label(self):
self._text.x = self.x + self.width / 2
self._text.y = self.y + self.height / 2
self._text.draw()
def set_text(self, text):
self._text.text = text
text = property(lambda self: self._text.text,
set_text)
class Slider(Control):
THUMB_WIDTH = 6
THUMB_HEIGHT = 10
GROOVE_HEIGHT = 2
def draw(self):
center_y = self.y + self.height / 2
draw_rect(self.x, center_y - self.GROOVE_HEIGHT / 2,
self.width, self.GROOVE_HEIGHT)
pos = self.x + self.value * self.width / (self.max - self.min)
draw_rect(pos - self.THUMB_WIDTH / 2, center_y - self.THUMB_HEIGHT / 2,
self.THUMB_WIDTH, self.THUMB_HEIGHT)
def coordinate_to_value(self, x):
return float(x - self.x) / self.width * (self.max - self.min) + self.min
def on_mouse_press(self, x, y, button, modifiers):
value = self.coordinate_to_value(x)
self.capture_events()
self.dispatch_event('on_begin_scroll')
self.dispatch_event('on_change', value)
def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
value = min(max(self.coordinate_to_value(x), self.min), self.max)
self.dispatch_event('on_change', value)
def on_mouse_release(self, x, y, button, modifiers):
self.release_events()
self.dispatch_event('on_end_scroll')
Slider.register_event_type('on_begin_scroll')
Slider.register_event_type('on_end_scroll')
Slider.register_event_type('on_change')
class PlayerWindow(pyglet.window.Window):
GUI_WIDTH = 400
GUI_HEIGHT = 40
GUI_PADDING = 4
GUI_BUTTON_HEIGHT = 16
def __init__(self, player):
super(PlayerWindow, self).__init__(caption='Media Player',
visible=False,
resizable=True)
self.player = player
self.player.push_handlers(self)
# TODO compat #self.player.eos_action = self.player.EOS_PAUSE
self.slider = Slider(self)
self.slider.x = self.GUI_PADDING
self.slider.y = self.GUI_PADDING * 2 + self.GUI_BUTTON_HEIGHT
self.slider.on_begin_scroll = lambda: player.pause()
self.slider.on_end_scroll = lambda: player.play()
self.slider.on_change = lambda value: player.seek(value)
self.play_pause_button = TextButton(self)
self.play_pause_button.x = self.GUI_PADDING
self.play_pause_button.y = self.GUI_PADDING
self.play_pause_button.height = self.GUI_BUTTON_HEIGHT
self.play_pause_button.width = 45
self.play_pause_button.on_press = self.on_play_pause
win = self
self.window_button = TextButton(self)
self.window_button.x = self.play_pause_button.x + \
self.play_pause_button.width + self.GUI_PADDING
self.window_button.y = self.GUI_PADDING
self.window_button.height = self.GUI_BUTTON_HEIGHT
self.window_button.width = 90
self.window_button.text = 'Windowed'
self.window_button.on_press = lambda: win.set_fullscreen(False)
self.controls = [
self.slider,
self.play_pause_button,
self.window_button,
]
x = self.window_button.x + self.window_button.width + self.GUI_PADDING
i = 0
for screen in self.display.get_screens():
screen_button = TextButton(self)
screen_button.x = x
screen_button.y = self.GUI_PADDING
screen_button.height = self.GUI_BUTTON_HEIGHT
screen_button.width = 80
screen_button.text = 'Screen %d' % (i + 1)
screen_button.on_press = \
(lambda s: lambda: win.set_fullscreen(True, screen=s))(screen)
self.controls.append(screen_button)
i += 1
x += screen_button.width + self.GUI_PADDING
def on_eos(self):
self.gui_update_state()
def gui_update_source(self):
if self.player.source:
source = self.player.source
self.slider.min = 0.
self.slider.max = source.duration
self.gui_update_state()
def gui_update_state(self):
if self.player.playing:
self.play_pause_button.text = 'Pause'
else:
self.play_pause_button.text = 'Play'
def get_video_size(self):
if not self.player.source or not self.player.source.video_format:
return 0, 0
video_format = self.player.source.video_format
width = video_format.width
height = video_format.height
if video_format.sample_aspect > 1:
width *= video_format.sample_aspect
elif video_format.sample_aspect < 1:
height /= video_format.sample_aspect
return width, height
def set_default_video_size(self):
'''Make the window size just big enough to show the current
video and the GUI.'''
width = self.GUI_WIDTH
height = self.GUI_HEIGHT
video_width, video_height = self.get_video_size()
width = max(width, video_width)
height += video_height
self.set_size(int(width), int(height))
def on_resize(self, width, height):
'''Position and size video image.'''
super(PlayerWindow, self).on_resize(width, height)
self.slider.width = width - self.GUI_PADDING * 2
height -= self.GUI_HEIGHT
if height <= 0:
return
video_width, video_height = self.get_video_size()
if video_width == 0 or video_height == 0:
return
display_aspect = width / float(height)
video_aspect = video_width / float(video_height)
if video_aspect > display_aspect:
self.video_width = width
self.video_height = width / video_aspect
else:
self.video_height = height
self.video_width = height * video_aspect
self.video_x = (width - self.video_width) / 2
self.video_y = (height - self.video_height) / 2 + self.GUI_HEIGHT
def on_mouse_press(self, x, y, button, modifiers):
for control in self.controls:
if control.hit_test(x, y):
control.on_mouse_press(x, y, button, modifiers)
def on_key_press(self, symbol, modifiers):
if symbol == key.SPACE:
self.on_play_pause()
elif symbol == key.ESCAPE:
self.dispatch_event('on_close')
def on_close(self):
self.player.pause()
self.close()
def on_play_pause(self):
if self.player.playing:
self.player.pause()
else:
if self.player.time >= self.player.source.duration:
self.player.seek(0)
self.player.play()
self.gui_update_state()
def on_draw(self):
self.clear()
# Video
if self.player.source and self.player.source.video_format:
self.player.get_texture().blit(self.video_x,
self.video_y,
width=self.video_width,
height=self.video_height)
# GUI
self.slider.value = self.player.time
for control in self.controls:
control.draw()
if __name__ == '__main__':
if len(sys.argv) < 2:
print('Usage: media_player.py <filename> [<filename> ...]')
sys.exit(1)
have_video = False
for filename in sys.argv[1:]:
player = pyglet.media.Player()
window = PlayerWindow(player)
source = pyglet.media.load(filename)
player.queue(source)
have_video = have_video or bool(source.video_format)
window.gui_update_source()
window.set_default_video_size()
window.set_visible(True)
player.play()
window.gui_update_state()
if not have_video:
pyglet.clock.schedule_interval(lambda dt: None, 0.2)
pyglet.app.run()

@ -0,0 +1,80 @@
#!/usr/bin/env python
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of pyglet nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ----------------------------------------------------------------------------
'''Demonstrates how to manage OpenGL calls between two independent windows.
'''
import pyglet
from pyglet.gl import *
def on_resize(width, height):
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(60., width / float(height), 1., 100.)
glMatrixMode(GL_MODELVIEW)
def setup():
glClearColor(1, 1, 1, 1)
glColor3f(.5, .5, .5)
def on_draw():
glClear(GL_COLOR_BUFFER_BIT)
glLoadIdentity()
glTranslatef(0, 0, -5)
glRotatef(r, 0, 0, 1)
glRectf(-1, -1, 1, 1)
r = 0
def update(dt):
global r
r += 1
if r > 360:
r = 0
pyglet.clock.schedule_interval(update, 1/20.)
w1 = pyglet.window.Window(200, 200, caption='First window', resizable=True)
w1.on_resize = on_resize
w1.on_draw = on_draw
w1.switch_to()
setup()
w2 = pyglet.window.Window(300, 300, caption='Second window', resizable=True)
w2.on_resize = on_resize
w2.on_draw = on_draw
w2.switch_to()
setup()
pyglet.app.run()

@ -0,0 +1,11 @@
noisy
=====
This is an example program that accompanies pyglet (http://www.pyglet.org).
Due to licensing restrictions on some of the assets, this game cannot be used
for commercial purposes.
The source code is licensed under the BSD license, which is quite permissive
(see the source header for details).
All artwork and the sound is Copyright 2007 Alex Holkner.

Binary file not shown.

After

Width:  |  Height:  |  Size: 996 B

@ -0,0 +1,116 @@
#!/usr/bin/env python
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of pyglet nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ----------------------------------------------------------------------------
'''Bounces balls around a window and plays noises.
This is a simple demonstration of how pyglet efficiently manages many sound
channels without intervention.
'''
import os
import random
import sys
from pyglet.gl import *
import pyglet
from pyglet.window import key
BALL_IMAGE = 'ball.png'
BALL_SOUND = 'ball.wav'
if len(sys.argv) > 1:
BALL_SOUND = sys.argv[1]
sound = pyglet.resource.media(BALL_SOUND, streaming=False)
class Ball(pyglet.sprite.Sprite):
ball_image = pyglet.resource.image(BALL_IMAGE)
width = ball_image.width
height = ball_image.height
def __init__(self):
x = random.random() * (window.width - self.width)
y = random.random() * (window.height - self.height)
super(Ball, self).__init__(self.ball_image, x, y, batch=balls_batch)
self.dx = (random.random() - 0.5) * 1000
self.dy = (random.random() - 0.5) * 1000
def update(self, dt):
if self.x <= 0 or self.x + self.width >= window.width:
self.dx *= -1
sound.play()
if self.y <= 0 or self.y + self.height >= window.height:
self.dy *= -1
sound.play()
self.x += self.dx * dt
self.y += self.dy * dt
self.x = min(max(self.x, 0), window.width - self.width)
self.y = min(max(self.y, 0), window.height - self.height)
window = pyglet.window.Window(640, 480)
@window.event
def on_key_press(symbol, modifiers):
if symbol == key.SPACE:
balls.append(Ball())
elif symbol == key.BACKSPACE:
if balls:
del balls[-1]
elif symbol == key.ESCAPE:
window.has_exit = True
@window.event
def on_draw():
window.clear()
balls_batch.draw()
label.draw()
def update(dt):
for ball in balls:
ball.update(dt)
pyglet.clock.schedule_interval(update, 1/30.)
balls_batch = pyglet.graphics.Batch()
balls = []
label = pyglet.text.Label('Press space to add a ball, backspace to remove',
font_size=14,
x=window.width // 2, y=10,
anchor_x='center')
if __name__ == '__main__':
pyglet.app.run()

@ -0,0 +1,190 @@
#!/usr/bin/env python
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of pyglet nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ----------------------------------------------------------------------------
'''Displays a rotating torus using OpenGL.
This example demonstrates:
* Using a 3D projection on a window by overriding the default on_resize
handler
* Enabling multisampling if available
* Drawing a simple 3D primitive using vertex and index arrays
* Using a display list
* Fixed-pipeline lighting
'''
from math import pi, sin, cos
from pyglet.gl import *
import pyglet
try:
# Try and create a window with multisampling (antialiasing)
config = Config(sample_buffers=1, samples=4,
depth_size=16, double_buffer=True,)
window = pyglet.window.Window(resizable=True, config=config)
except pyglet.window.NoSuchConfigException:
# Fall back to no multisampling for old hardware
window = pyglet.window.Window(resizable=True)
@window.event
def on_resize(width, height):
# Override the default on_resize handler to create a 3D projection
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(60., width / float(height), .1, 1000.)
glMatrixMode(GL_MODELVIEW)
return pyglet.event.EVENT_HANDLED
def update(dt):
global rx, ry, rz
rx += dt * 1
ry += dt * 80
rz += dt * 30
rx %= 360
ry %= 360
rz %= 360
pyglet.clock.schedule(update)
@window.event
def on_draw():
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
glTranslatef(0, 0, -4)
glRotatef(rz, 0, 0, 1)
glRotatef(ry, 0, 1, 0)
glRotatef(rx, 1, 0, 0)
torus.draw()
def setup():
# One-time GL setup
glClearColor(1, 1, 1, 1)
glColor3f(1, 0, 0)
glEnable(GL_DEPTH_TEST)
glEnable(GL_CULL_FACE)
# Uncomment this line for a wireframe view
#glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
# Simple light setup. On Windows GL_LIGHT0 is enabled by default,
# but this is not the case on Linux or Mac, so remember to always
# include it.
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_LIGHT1)
# Define a simple function to create ctypes arrays of floats:
def vec(*args):
return (GLfloat * len(args))(*args)
glLightfv(GL_LIGHT0, GL_POSITION, vec(.5, .5, 1, 0))
glLightfv(GL_LIGHT0, GL_SPECULAR, vec(.5, .5, 1, 1))
glLightfv(GL_LIGHT0, GL_DIFFUSE, vec(1, 1, 1, 1))
glLightfv(GL_LIGHT1, GL_POSITION, vec(1, 0, .5, 0))
glLightfv(GL_LIGHT1, GL_DIFFUSE, vec(.5, .5, .5, 1))
glLightfv(GL_LIGHT1, GL_SPECULAR, vec(1, 1, 1, 1))
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, vec(0.5, 0, 0.3, 1))
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, vec(1, 1, 1, 1))
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 50)
class Torus(object):
def __init__(self, radius, inner_radius, slices, inner_slices):
# Create the vertex and normal arrays.
vertices = []
normals = []
u_step = 2 * pi / (slices - 1)
v_step = 2 * pi / (inner_slices - 1)
u = 0.
for i in range(slices):
cos_u = cos(u)
sin_u = sin(u)
v = 0.
for j in range(inner_slices):
cos_v = cos(v)
sin_v = sin(v)
d = (radius + inner_radius * cos_v)
x = d * cos_u
y = d * sin_u
z = inner_radius * sin_v
nx = cos_u * cos_v
ny = sin_u * cos_v
nz = sin_v
vertices.extend([x, y, z])
normals.extend([nx, ny, nz])
v += v_step
u += u_step
# Create ctypes arrays of the lists
vertices = (GLfloat * len(vertices))(*vertices)
normals = (GLfloat * len(normals))(*normals)
# Create a list of triangle indices.
indices = []
for i in range(slices - 1):
for j in range(inner_slices - 1):
p = i * inner_slices + j
indices.extend([p, p + inner_slices, p + inner_slices + 1])
indices.extend([p, p + inner_slices + 1, p + 1])
indices = (GLuint * len(indices))(*indices)
# Compile a display list
self.list = glGenLists(1)
glNewList(self.list, GL_COMPILE)
glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT)
glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_NORMAL_ARRAY)
glVertexPointer(3, GL_FLOAT, 0, vertices)
glNormalPointer(GL_FLOAT, 0, normals)
glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, indices)
glPopClientAttrib()
glEndList()
def draw(self):
glCallList(self.list)
setup()
torus = Torus(1, 0.3, 50, 30)
rx = ry = rz = 0
pyglet.app.run()

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save