| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
__author__ = 'Kousu <kousue@gmail.com>' |
|---|
| 8 |
__copyright__ = 'BSD License, 2006' |
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 |
""" |
|---|
| 13 |
Todo: |
|---|
| 14 |
Dump dir() on this module and all classes in the real module and such and implement everything exactly like it should be |
|---|
| 15 |
Fixup controller mappings to be easier to work with |
|---|
| 16 |
Protect the display from being reinitialized somehow? |
|---|
| 17 |
make it wipe the mouse trail every time instead of relying on the user code to wipe the screen. Would have to cache stuff. |
|---|
| 18 |
""" |
|---|
| 19 |
|
|---|
| 20 |
from __future__ import division |
|---|
| 21 |
|
|---|
| 22 |
import sys |
|---|
| 23 |
import pygame, SFont |
|---|
| 24 |
from pygame.locals import * |
|---|
| 25 |
|
|---|
| 26 |
class Controller: |
|---|
| 27 |
"""This class gives access to the state of the pad and buttons. The state is read upon instantiation and is accessible through read-only properties. |
|---|
| 28 |
""" |
|---|
| 29 |
|
|---|
| 30 |
def __init__(self): |
|---|
| 31 |
"""Read the current state of the 'controller'. |
|---|
| 32 |
This should be read-only to follow fraca's idiot way, but oh well. |
|---|
| 33 |
See the code for what each PSP control is mapped to |
|---|
| 34 |
|
|---|
| 35 |
While the controller has a mousepos property the mouse is being dragged which is mapped to the joystick being moved. mousepos is used to calculate a distance to pretend the joystick is moving. |
|---|
| 36 |
""" |
|---|
| 37 |
|
|---|
| 38 |
|
|---|
| 39 |
|
|---|
| 40 |
|
|---|
| 41 |
|
|---|
| 42 |
|
|---|
| 43 |
|
|---|
| 44 |
|
|---|
| 45 |
self.analogX, self.analogY = 0,0 |
|---|
| 46 |
if hasattr(self, 'mousepos'): |
|---|
| 47 |
newpos = pygame.mouse.get_pos() |
|---|
| 48 |
pygame.draw.line(pygame.display.get_surface(), (0,0,0), self.mousepos, newpos) |
|---|
| 49 |
pygame.display.flip() |
|---|
| 50 |
self.analogX, self.analogY = (b-a for a,b in zip(self.mousepos, newpos)) |
|---|
| 51 |
|
|---|
| 52 |
if -127>self.analogX: self.analogX=-127 |
|---|
| 53 |
elif self.analogX>128: self.analogX=128 |
|---|
| 54 |
if -127>self.analogY: self.analogY=-127 |
|---|
| 55 |
elif self.analogY>128: self.analogY=128 |
|---|
| 56 |
|
|---|
| 57 |
|
|---|
| 58 |
pygame.event.pump() |
|---|
| 59 |
keys = pygame.key.get_pressed() |
|---|
| 60 |
keys = [i for i,pressed in enumerate(keys) if pressed] |
|---|
| 61 |
|
|---|
| 62 |
|
|---|
| 63 |
self.start = K_F1 in keys |
|---|
| 64 |
self.select = K_F2 in keys |
|---|
| 65 |
|
|---|
| 66 |
|
|---|
| 67 |
|
|---|
| 68 |
|
|---|
| 69 |
|
|---|
| 70 |
|
|---|
| 71 |
|
|---|
| 72 |
|
|---|
| 73 |
|
|---|
| 74 |
|
|---|
| 75 |
|
|---|
| 76 |
self.triangle = K_i in keys |
|---|
| 77 |
self.square = K_j in keys |
|---|
| 78 |
|
|---|
| 79 |
self.circle = K_l in keys |
|---|
| 80 |
|
|---|
| 81 |
self.cross = K_k in keys |
|---|
| 82 |
|
|---|
| 83 |
|
|---|
| 84 |
self.up = K_w in keys or K_UP in keys |
|---|
| 85 |
|
|---|
| 86 |
self.left = K_a in keys or K_LEFT in keys |
|---|
| 87 |
|
|---|
| 88 |
self.down = K_s in keys or K_DOWN in keys |
|---|
| 89 |
|
|---|
| 90 |
self.right = K_d in keys or K_RIGHT in keys |
|---|
| 91 |
|
|---|
| 92 |
|
|---|
| 93 |
|
|---|
| 94 |
|
|---|
| 95 |
|
|---|
| 96 |
self.l = K_LSHIFT in keys |
|---|
| 97 |
self.r = K_RSHIFT in keys |
|---|
| 98 |
|
|---|
| 99 |
|
|---|
| 100 |
for e in pygame.event.get(): |
|---|
| 101 |
if e.type == QUIT: sys.exit(0) |
|---|
| 102 |
if e.type == MOUSEBUTTONDOWN: |
|---|
| 103 |
Controller.mousepos = e.pos |
|---|
| 104 |
|
|---|
| 105 |
if e.type == MOUSEBUTTONUP: |
|---|
| 106 |
del Controller.mousepos |
|---|
| 107 |
|
|---|
| 108 |
|
|---|
| 109 |
class Color: |
|---|
| 110 |
""" |
|---|
| 111 |
Represents a colour. |
|---|
| 112 |
In pygame, this would be: |
|---|
| 113 |
(r,g,b) or (r,g,b,a) |
|---|
| 114 |
""" |
|---|
| 115 |
def __init__(self, r, g, b, a = 0): |
|---|
| 116 |
self.red = r |
|---|
| 117 |
self.green = g |
|---|
| 118 |
self.blue = b |
|---|
| 119 |
self.alpha = a |
|---|
| 120 |
def tuple(self): |
|---|
| 121 |
"""Turns this colour into a pygame-style tuple |
|---|
| 122 |
this is a non-standard extension. NOT PART OS PYPSP!""" |
|---|
| 123 |
return (self.red, self.green, self.blue, self.alpha) |
|---|
| 124 |
|
|---|
| 125 |
|
|---|
| 126 |
|
|---|
| 127 |
|
|---|
| 128 |
|
|---|
| 129 |
|
|---|
| 130 |
IMG_PNG = 0 |
|---|
| 131 |
IMG_JPEG = 1 |
|---|
| 132 |
|
|---|
| 133 |
class Image: |
|---|
| 134 |
|
|---|
| 135 |
|
|---|
| 136 |
def __init__(self, *args): |
|---|
| 137 |
""" |
|---|
| 138 |
3 different constructors: |
|---|
| 139 |
__init__(self, filename) |
|---|
| 140 |
__init__(self, w, h) |
|---|
| 141 |
__init__(self, img) |
|---|
| 142 |
""" |
|---|
| 143 |
|
|---|
| 144 |
if len(args)==1: |
|---|
| 145 |
arg = args[0] |
|---|
| 146 |
if type(arg)==type(""): |
|---|
| 147 |
self.surface = pygame.image.load(arg) |
|---|
| 148 |
elif type(arg)==type(self): |
|---|
| 149 |
|
|---|
| 150 |
self.surface = arg.surface.copy() |
|---|
| 151 |
|
|---|
| 152 |
elif len(args)==2: |
|---|
| 153 |
self.surface = pygame.Surface(args, pygame.SRCALPHA, 32) |
|---|
| 154 |
else: raise TypeError("__init__() takes either 1 or 2 arguments (%d given)" % len(args)) |
|---|
| 155 |
|
|---|
| 156 |
def clear(self, color): |
|---|
| 157 |
self.surface.fill(color.tuple()) |
|---|
| 158 |
|
|---|
| 159 |
def blit(self, source, sx=0, sy=0, w=-1, h=-1, dx=0, dy=0, blend=False, dw=-1, dh=-1): |
|---|
| 160 |
|
|---|
| 161 |
|
|---|
| 162 |
if w == -1: w = source.width |
|---|
| 163 |
if h == -1: h = source.height |
|---|
| 164 |
|
|---|
| 165 |
if dw == -1: dw = source.width |
|---|
| 166 |
if dh == -1: dh = source.height |
|---|
| 167 |
|
|---|
| 168 |
r = source.surface.subsurface((sx,sy,w,h)) |
|---|
| 169 |
r = pygame.transform.scale(r, (dw,dh)) |
|---|
| 170 |
|
|---|
| 171 |
self.surface.blit(r, (dx,dy)) |
|---|
| 172 |
|
|---|
| 173 |
def fillRect(self, x, y, w, h, color): |
|---|
| 174 |
self.surface.fill((x,y,w,h), color.tuple()) |
|---|
| 175 |
|
|---|
| 176 |
def saveToFile(self, filename, type=IMG_PNG): |
|---|
| 177 |
|
|---|
| 178 |
pygame.image.save(self.surface, filename) |
|---|
| 179 |
|
|---|
| 180 |
def putPixel(self, x, y, color): |
|---|
| 181 |
self.surface.set_at((x,y), color.tuple()) |
|---|
| 182 |
|
|---|
| 183 |
def getPixel(self, x, y): |
|---|
| 184 |
color = self.surface.get_at((x,y)) |
|---|
| 185 |
return Color(*color) |
|---|
| 186 |
width = property(lambda self: self.surface.get_width()) |
|---|
| 187 |
height = property(lambda self: self.surface.get_height()) |
|---|
| 188 |
|
|---|
| 189 |
|
|---|
| 190 |
class Screen(Image): |
|---|
| 191 |
surface = pygame.display.set_mode((480,272)) |
|---|
| 192 |
|
|---|
| 193 |
|
|---|
| 194 |
def __init__(self): |
|---|
| 195 |
"""Override the constructor to kill it so |
|---|
| 196 |
i) you don't get to pick the info. HAH. |
|---|
| 197 |
ii) Screen.surface isn't overriden by self.surface. |
|---|
| 198 |
""" |
|---|
| 199 |
pass |
|---|
| 200 |
def swap(self): |
|---|
| 201 |
pygame.display.flip() |
|---|
| 202 |
|
|---|
| 203 |
|
|---|
| 204 |
class Font(SFont.Font): |
|---|
| 205 |
"""Wrap an SFont to make it look like PSP Python fonts""" |
|---|
| 206 |
def textWidth(self, text): |
|---|
| 207 |
return self.size(text)[0] |
|---|
| 208 |
def textHeight(self, text): |
|---|
| 209 |
return self.size(text)[1] |
|---|
| 210 |
def drawText(self, image, x, y, text): |
|---|
| 211 |
self.write(image.surface, (x,y), text) |
|---|
| 212 |
|
|---|
| 213 |
|
|---|
| 214 |
class BlitBatch: |
|---|
| 215 |
def __init__(self): raise NotImplementedError("This class allows the user to batch several blitting operations. It was written for optimization purposes but it doesn\u2019t seem to really make a difference.") |
|---|
| 216 |
|
|---|
| 217 |
|
|---|
| 218 |
|
|---|
| 219 |
class Mask: |
|---|
| 220 |
def __init__(self, img, x, y, w, h, threshold): |
|---|
| 221 |
raise NotImplementedError |
|---|
| 222 |
def collide(self, msk): |
|---|
| 223 |
pass |
|---|
| 224 |
def union(self, msk): pass |
|---|
| 225 |
def isIn(self, x, y): pass |
|---|
| 226 |
|
|---|
| 227 |
|
|---|
| 228 |
TR_PLUS = 0 |
|---|
| 229 |
TR_MULT = 1 |
|---|
| 230 |
class Transform: |
|---|
| 231 |
def __init__(self, *args): |
|---|
| 232 |
""" |
|---|
| 233 |
__init__(self, type, param) |
|---|
| 234 |
__init__(self, cb) |
|---|
| 235 |
""" |
|---|
| 236 |
if len(args)==2: |
|---|
| 237 |
pass |
|---|
| 238 |
elif len(args)==1: |
|---|
| 239 |
pass |
|---|
| 240 |
else: raise TypeError("__init__() takes either 1 or 2 arguments (%d given)" % len(args)) |
|---|
| 241 |
|
|---|
| 242 |
def apply(self, img): |
|---|
| 243 |
pass |
|---|
| 244 |
|
|---|
| 245 |
class Timer: |
|---|
| 246 |
"""Fraca says: 'A timer class that doesn\u2019t run in its own thread (unlike the standard threading.Timer class).' |
|---|
| 247 |
Since I really really really don't know how to manage that I'm just going to use threading.Timer |
|---|
| 248 |
This timer dies after one run, if you want it to go again you should, as the last thing in fire(), make a new one |
|---|
| 249 |
and start it. I think. Hopefully that will still allow the old thread to die. |
|---|
| 250 |
""" |
|---|
| 251 |
def __init__(self, timeout): |
|---|
| 252 |
self.t=threading.Timer(timeout/1000, self.fire) |
|---|
| 253 |
|
|---|
| 254 |
def fire(self): raise NotImplementedError("Timer.fire() must be overridden to be any use, idiot") |
|---|
| 255 |
|
|---|
| 256 |
def run(self): |
|---|
| 257 |
self.t.start() |
|---|