Skip to content

Instantly share code, notes, and snippets.

@admalledd
Created October 17, 2012 03:17
Show Gist options
  • Save admalledd/3903518 to your computer and use it in GitHub Desktop.
Save admalledd/3903518 to your computer and use it in GitHub Desktop.
pygame joysticks and timedeltas
import random
import itertools
import pygame
import pygame.gfxdraw
from pygame.locals import *
SIZE=(1024,768)
#generate colors: we have three tables: (x,0,0) (x,y,0), (x,y,z) where xyz locations are random
#meaning that we have primary colors, colors with two, and colors with all three
#for the "target" colors, we only allow 4 per primary (dark, dim, lit, bright) (64,128,192,255)
c_range=(192,255)
#first, ct1
ct1=[]
for color in range(3):
for level in c_range:
tmp_color=[0,0,0]
tmp_color[color]=level
ct1.append(tuple(tmp_color))
ct1=tuple(ct1)
#two randomish...
ct2=[]
for hold_this in range(3):
tmp_lists=[c_range,c_range,c_range]
tmp_lists[hold_this]=(0,0,0)#the one color we hold to 0 throughout
ct2.append(tuple(itertools.product(*tmp_lists)))
ct2=tuple(itertools.chain(*ct2))
COLORS=(ct1,ct2)
ct3=tuple(itertools.product(c_range,repeat=3)) #all three colors
#COLORS=(ct1,ct2,ct3)
class joystick(object):
def __init__(self,pygamejoy):
self.joy = pygamejoy
self.right_stick = axi_pair('right',self.joy,2,3,(255,255,0),True)
self.left_stick = axi_pair('left',self.joy,2,3,(0,255,255),False)
def draw(self,screen,timedelta):
self.left_stick.draw(screen,timedelta)
self.right_stick.draw(screen,timedelta)
def reset(self):
self.left_stick.x_spd=0.0
self.left_stick.y_spd=0.0
self.left_stick.pos=(SIZE[0]/2,SIZE[1]/2)
self.right_stick.x_spd=0.0
self.right_stick.y_spd=0.0
self.right_stick.pos=(SIZE[0]/2,SIZE[1]/2)
class axi_pair(object):
def __init__(self,name,joy,x,y,color,invert):
self.name=name
self.invert=invert
self.x_axis=x
self.y_axis=y
self.joy=joy
self.x_spd=0.0
self.y_spd=0.0
self.pos=(SIZE[0]/2,SIZE[1]/2)#center of screen
self.color=list(color)
self.color_vector=[0,0,0]
self.new_color()
def update_vector(self,timedelta):
'''checks if it is time to update the vector speed yet.
uses two "times": time since last accel and time since last drag
TODO:: allow arbritrary frame rate by dividing the calculation by the time-per-frame
'''
#how much we speed up by
chgx = (self.joy.get_axis(self.x_axis)/500)*timedelta
chgy = (self.joy.get_axis(self.y_axis)/500)*timedelta
if self.invert:
chgx=-chgx
chgy=-chgy
self.x_spd+=chgx
self.y_spd+=chgy
#how much we slow down by
scale=1+((0.05/1000)*timedelta)
self.x_spd/=scale
self.y_spd/=scale
#print scale,timedelta
xs=self.x_spd if self.x_spd != 0.0 else float('inf')
ys=self.y_spd if self.y_spd != 0.0 else float('inf')
vdx = (scale/xs) - chgx
vdy = (scale/ys) - chgy
#print "%s vector = (%0.3f,%0.3f)<%0.3f,%0.3f> vd: {%0.3f,%0.3f}"%(
# self.name,chgx,chgy,self.x_spd,self.y_spd,vdx,vdy)
#check if we are below threshhold and set to 0 therefore (coast to stop, really)
#the and !=0 is so that we only print out the debug line once, if we move at all within the deadban it resets.
if 0.005 > self.x_spd > -0.005 and self.x_spd != 0.0:
self.x_spd = 0.0
print "%s: haltx (%s)@<%s>"%(self.name,(self.x_spd,self.y_spd),self.pos)
if 0.005 > self.y_spd > -0.005 and self.y_spd != 0.0:
self.y_spd = 0.0
print "%s: halty (%s)@<%s>"%(self.name,(self.x_spd,self.y_spd),self.pos)
return (self.x_spd,self.y_spd)
def new_color(self,color=None,time=2000):
'''get a new color and reset things for new vector calculations'''
if color is None:
color = list(random.choice(random.choice(COLORS)))
self.color_target=color
#print "%s new color: (%s)<%s>"%(self.name,color,self.color_target)
self.color_timestamp=0#current "time" since last self.new_color()
self.color_timetarget=time#how long it should take us to get to the new color
def update_color(self,timedelta):
'''change color only sligtly.
should take 2 seconds to fully transition no matter what, although the "vector" is chosen at the start.
'''
self.color_timestamp+=timedelta
#code to check "color distance" from target
if 7.5 > sum(self.color)-sum(self.color_target) > -7.5:
#we have made it to the target (ish)
#calculate new vector
self.new_color(None,2500)
for i in range(3):
#new vector
#color change remaining/time remaining == change per timestep
#change per timestep * timedelta == ammount we need to change for this many timesteps
color_delta=self.color_target[i]-self.color[i]
time_pressure=float(self.color_timetarget-self.color_timestamp)
#print "%s i:%s d = %0.3f tp = %s td = %s"%(self.name,i, color_delta,time_pressure,timedelta)
self.color_vector[i]=(color_delta/time_pressure)*timedelta
r,g,b=self.color
rv,gv,bv=self.color_vector
rt,gt,bt=self.color_target
#print "%s color change: k:%0.3f t:(%s,%s,%s) c:<%0.3f,%0.3f,%0.3f> v:{%0.3f,%0.3f,%0.3f}"%(
# self.name,sum(self.color)-sum(self.color_target),rt,gt,bt,r,g,b,rv,gv,bv)
for i in range(3):
#add vector
self.color[i]+=self.color_vector[i]
if self.color[i] > 255: self.color[i]=255.0
elif self.color[i] < 0: self.color[i]=0.0
def draw(self,screen,timedelta):
#move current pos to new coords by +- vector, but limit to size of screen.
x,y=self.pos
vec=self.update_vector(timedelta)
#invert joymotion here?
xx,yy=x+vec[0],y+vec[1]
#check screen limits, dont want to go outside those now...
rect=screen.get_rect()
#x
if xx > rect.right:
xx=rect.left #too far right
elif xx < rect.left:
xx=rect.right #too far left
#y
if yy > rect.bottom:
yy=rect.top #too far down
elif yy < rect.top:
yy=rect.bottom #too far up
#update color to semi-randomness...
self.update_color(timedelta)
##pygame.gfxdraw.pixel(screen,int(xx),int(yy),self.color)
pygame.draw.circle(screen,self.color,(int(xx),int(yy)),2,0)
self.pos=xx,yy
def main():
pygame.init()
pygame.joystick.init()
screen = pygame.display.set_mode(SIZE,pygame.SRCALPHA)
clock=pygame.time.Clock()
j = pygame.joystick.Joystick(0)
j.init()
joy = joystick(j)
while True:
timedelta = clock.tick()
print "fps: %0.3f"%clock.get_fps()
events = pygame.event.get()
for event in events:
if event.type == QUIT:
pygame.quit()
return
elif event.type == MOUSEBUTTONDOWN and event.button==1:
print event.pos
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
return
elif event.key == K_SPACE:
#clear screen
screen.fill((0, 0, 0))
joy.reset()
elif event.type == JOYBUTTONDOWN:
if event.button == 9:
#clear screen
screen.fill((0, 0, 0))
joy.reset()
elif event.button == 10:
#left stick
joy.left_stick.pos=(SIZE[0]/2,SIZE[1]/2)
joy.left_stick.x_spd=0.0
joy.left_stick.y_spd=0.0
elif event.button == 11:
#right stick
joy.right_stick.pos=(SIZE[0]/2,SIZE[1]/2)
joy.right_stick.x_spd=0.0
joy.right_stick.y_spd=0.0
elif event.button == 6:
#left color
joy.left_stick.new_color()
elif event.button == 7:
#right color
joy.right_stick.new_color()
#no clearing of screen out of loop: keep all old points.
joy.draw(screen,timedelta)
pygame.display.flip()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment