one-file-projects/colortest.py

248 lines
8.3 KiB
Python

import pygame
from pygame.locals import *
from random import random,randint
from math import sqrt
screen = None
color = (128,128,128)
color_vel = (0,0,0)
running = True
class Vector(tuple):
def __add__(self,other):
if len(self) != len(other):
raise Exception("Can't add vectors of different size: %d %d" % (len(self), len(other)))
return Vector([ self[i]+other[i] for i in range(len(self)) ])
def __sub__(self,other):
if len(self) != len(other):
raise Exception("Can't subtract vectors of different size")
return Vector([ self[i]-other[i] for i in range(len(self)) ])
def __mul__(self,factor):
return Vector([ self[i]*factor for i in range(len(self)) ])
def __div__(self,factor):
return self.__mul__(1.0/factor)
def __truediv__(self,factor):
return self.__div__(factor)
def __rmul__(self,factor):
return self.__mul__(factor)
def __rdiv__(self,factor):
raise NotImplemented
def __iadd__(self,other):
return self.__add__(other)
def __isub__(self,other):
return self.__sub__(other)
def __neg__(self):
return self.__mul__(-1.0)
def __setitem__(self,k,v):
raise Exception("Not available") # immutable
def distance(self, other):
if len(self) != len(other):
raise Exception("Can't calculate distance between vectors of different size")
return sqrt(sum([ (self[i]-other[i])**2 for i in range(len(self)) ]))
def length(self):
return self.distance( Vector( (0,0) ) )
class Tick(object):
def __init__(self, tickrange):
self.tickrange = tickrange
self.m_tick = 0
def tick(self):
self.m_tick = (self.m_tick+1)%self.tickrange
return self.m_tick == 0
class Mode(object):
def __init__(self, screensize):
self.screensize = screensize
def update(self):
pass
def draw(self,screen):
pass
def minmax(vmin,vmax):
return lambda v: min(vmax,max(vmin,v))
class TransitionMode(Mode):
t = 0.3
a = 30
def __init__(self, screensize):
Mode.__init__(self,screensize)
self.color = Vector( (127,127,127) )
self.color_vel = Vector( 2*self.a*random()+self.a for i in range(3) )
self.utick = Tick(10)
def update(self):
if self.utick.tick():
randvec = Vector( (2*self.a*random()-self.a) for i in range(3) )
self.color_vel = (1-self.t)*self.color_vel+self.t*randvec
self.color = Vector( map(minmax(0,255), self.color+self.color_vel) )
def draw(self,screen):
screen.fill( self.color )
class LelMode(Mode):
color = [(255,0,0),(0,255,0)]
size = 10
def __init__(self,screensize):
Mode.__init__(self,screensize)
self.offset = 0
self.tick = 0
def update(self):
self.offset = (self.offset+1)%2
def draw(self,screen):
w,h = screen.get_size()
for x in range(w):
color = self.color[ (x//self.size + self.offset)%2]
pygame.draw.line(screen, color, (x,0), (x,h) )
class BallMode(Mode):
def __init__(self,screensize):
Mode.__init__(self,screensize)
self.ball = [200,200]
self.radius = 70
self.velocity = [10,10]
def update(self):
w, h = self.screensize
if self.ball[0] + self.radius >= w:
self.velocity[0] = -abs(self.velocity[0])
elif self.ball[0] - self.radius < 0:
self.velocity[0] = abs(self.velocity[0])
elif self.ball[1] + self.radius >= h:
self.velocity[1] = -abs(self.velocity[1])
elif self.ball[1] - self.radius < 0:
self.velocity[1] = abs(self.velocity[1])
for i in range(2):
self.ball[i] += self.velocity[i]
def draw(self,screen):
screen.fill( (0,0,0) )
pygame.draw.circle(screen, (255,0,0), tuple(self.ball), self.radius)
class Particle:
def __init__(self,color, pos, vel):
self.color = color
self.pos = Vector(pos)
self.vel = Vector(vel)
def updateVel(self,gravity,max_v=20):
gravity = Vector(gravity)
#Update velocity
self.vel = 0.95*self.vel+0.01*random()*(gravity-self.pos)+0.1*random()*Vector( randint(-70,70) for i in range(2) )
#Limit speed
l = self.vel.length()
self.vel *= max_v/l
def updatePos(self):
self.pos = self.pos + self.vel
def draw(self,screen):
w,h = 1280,800
if self.pos[0] > 0 and self.pos[0] < w and self.pos[1] > 0 and self.pos[1] < h:
pos = tuple(map(int,self.pos))
velpos = tuple(map(int,self.pos+self.vel))
pygame.draw.circle(screen, self.color, pos, 5)
pygame.draw.line(screen, (255,255,255), pos, velpos, 1 )
@staticmethod
def generate(xmax,ymax):
return Particle( tuple( randint(100,255) for i in range(3) ), ( randint(0,xmax), randint(0,ymax) ), tuple( randint(-50,50) for i in range(2) ) )
class SwarmMode(Mode):
swarmsize = 60
def __init__(self,screensize):
Mode.__init__(self,screensize)
self.particles = list( Particle.generate(1280,800) for i in range(self.swarmsize) )
self.generateGravity()
self.gtick = Tick(150)
self.utick = Tick(2)
def generateGravity(self):
#self.gravity = tuple( randint(0,m) for m in [1280,800] )
self.gravity = Vector( (1280,800) )/2
def update(self):
if self.gtick.tick():
self.generateGravity()
v = self.utick.tick()
#king = self.particles[0]
#if v: king.updateVel(self.gravity, max_v=3)
#king.updatePos()
for p in self.particles:
if v: p.updateVel(self.gravity)
p.updatePos()
def draw(self,screen):
screen.fill( (0,0,0) )
for p in self.particles:
p.draw(screen)
class Game(object):
def __init__(self, modes=[SwarmMode,TransitionMode,LelMode,BallMode]):
self.modes = modes
pygame.init()
self.screen = pygame.display.set_mode( (1280,800), pygame.HWSURFACE )
pygame.mouse.set_visible(False)
self.setmode(0)
self.running = True
def update(self):
self.mode.update()
def setmode(self,i):
self.modeindex = i
self.mode = self.modes[i%len(self.modes)](self.screen.get_size())
def nextmode(self):
self.setmode( self.modeindex+1 )
def draw(self):
self.mode.draw(self.screen)
pygame.display.flip()
def getevents(self):
for event in pygame.event.get():
if event.type == QUIT:
self.running = False
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.event.post(pygame.event.Event(QUIT))
elif event.key == K_SPACE:
self.nextmode()
def run(self):
clock = pygame.time.Clock()
while self.running:
clock.tick(30)
self.getevents()
self.update()
self.draw()
if __name__ == '__main__':
Game().run()