Прикреплённый файл «2014-03-28-udpbowling.py»

Загрузка

   1 #!/usr/bin/env python
   2 # coding: utf
   3 '''
   4 Упражнение с мячом и битой, UDP-сервер
   5 '''
   6 
   7 import sys, pygame, socket, select, time
   8 from math import *
   9 
  10 def qlength(start, end): return (start[0]-end[0])**2+(start[1]-end[1])**2
  11 
  12 def draw_arrow(surface, color, butt, head, width=10.):
  13     '''Функция рисования стрелочки без единого синуса :)'''
  14     # края стрелочки — диагонали квадратов со стороной  butt → head…
  15     x1,y1=butt[0]-butt[1]+head[1],butt[1]-head[0]+butt[0]
  16     x2,y2=butt[0]-head[1]+butt[1],butt[1]-butt[0]+head[0]
  17     # …уменьшенные до длины width (на самом деле синус тут :)
  18     l=sqrt(qlength(butt, head)*2)
  19     x1=(x1-head[0])*10/l+head[0]
  20     y1=(y1-head[1])*10/l+head[1]
  21     x2=(x2-head[0])*10/l+head[0]
  22     y2=(y2-head[1])*10/l+head[1]
  23     pygame.draw.line(surface, color, butt, head)
  24     pygame.draw.line(surface, color, (x1,y1), head)
  25     pygame.draw.line(surface, color, (x2,y2), head)
  26 
  27 pygame.init()
  28 
  29 size = width, height = 320,200
  30 screen = pygame.display.set_mode(size)
  31 back = pygame.Color("midnightblue")
  32 
  33 ball = pygame.image.load("ball.gif")
  34 ballmask = pygame.mask.from_surface(ball)
  35 beat = pygame.transform.rotozoom(ball, 90, 0.5)
  36 beatmask = pygame.mask.from_surface(beat)
  37 
  38 ballrect = ball.get_rect()
  39 beatrect = beat.get_rect()
  40 # Длина траекторий
  41 TRAIL=5
  42 ballspeed = [pi/4, 3.]
  43 ballpos = [screen.get_rect().center]*TRAIL
  44 beatpos = [(0,0)]*TRAIL
  45 cbeatpos = beatpos[0]
  46 debug,again,redraw,recalc,beaten=False,True,True,True,None
  47 SPORT=2014
  48 CPORT=2015
  49 MAXBUF=16384
  50 
  51 def Overlap(pos):
  52     '''Пересекается ли бита по координатам pos с мячом?'''
  53     rect = beatrect.copy()
  54     rect.center=pos
  55     return ballrect.colliderect(rect) and \
  56            ballmask.overlap(beatmask, (rect.left-ballrect.left, rect.top-ballrect.top))
  57 
  58 def Interact(act=None):
  59     '''Влияние биты на скорость мяча'''
  60     act = act or beaten
  61     # угол удара (направление от мяча к точке соударения)
  62     a = atan2(act[1]-ballrect.centery, act[0]-ballrect.centerx)
  63     if (a-ballspeed[0]+2.5*pi)%(2*pi)<pi:
  64         # удар спереди: отразим от плоскости соприкосновения
  65         return pi-ballspeed[0]+2*a
  66     else:
  67         # удар сзади не считается
  68         return ballspeed[0]
  69 
  70 def Recalc():
  71     '''Пересчёт игрового пространства'''
  72     global beaten, ballspeed
  73     if not beaten and Overlap(cbeatpos):
  74         beaten = cbeatpos
  75     if beaten:
  76         ballspeed[0] = Interact()
  77         beaten = None
  78     x,y = ballpos[-1][0]+ballspeed[1]*cos(ballspeed[0]),ballpos[-1][1]+ballspeed[1]*sin(ballspeed[0])
  79     if not ballrect.width/2<x<width-ballrect.width/2: ballspeed[0]=pi-ballspeed[0]
  80     if not ballrect.height/2<y<height-ballrect.height/2: ballspeed[0]=-ballspeed[0]
  81     x,y = ballpos[-1][0]+ballspeed[1]*cos(ballspeed[0]),ballpos[-1][1]+ballspeed[1]*sin(ballspeed[0])
  82     # TODO а вдруг это не поможет?
  83     # TODO бита не должна уж совсем на шар налезать
  84     ballpos.pop(0)
  85     ballpos.append((x,y))
  86     beatpos.pop(0)
  87     beatpos.append(cbeatpos)
  88 
  89 def Redraw():
  90     '''Отображение игрового пространства'''
  91     ballrect.center=(int(ballpos[-1][0]),int(ballpos[-1][1]))
  92     beatrect.center=cbeatpos
  93     screen.fill(back)
  94     screen.blit(ball, ballrect)
  95     screen.blit(beat, beatrect)
  96     if debug:
  97         a=Interact(beatrect.center)
  98         draw_arrow(screen, pygame.Color("green"), ballrect.center, (ballrect.centerx+ballspeed[1]*cos(ballspeed[0])*50, ballrect.centery+ballspeed[1]*sin(ballspeed[0])*50))
  99         draw_arrow(screen, pygame.Color("yellow"), ballrect.center, (ballrect.centerx+ballspeed[1]*cos(a)*50, ballrect.centery+ballspeed[1]*sin(a)*50))
 100         draw_arrow(screen, pygame.Color("magenta"), beatrect.center, ballrect.center)
 101 
 102 def init_server(port):
 103     sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 104     sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
 105     sock.bind(('', port))
 106     check = select.poll()
 107     check.register(sock,select.POLLIN|select.POLLPRI)
 108     return sock, check
 109 
 110 def init_broad():
 111     s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 112     s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
 113     return s
 114 
 115 
 116 pygame.mouse.set_visible(False)
 117 Sock, Check = init_server(SPORT)
 118 Broad = init_broad()
 119 # Смена игрового времени
 120 GRATE=50
 121 pygame.time.set_timer(pygame.USEREVENT, GRATE)
 122 pygame.time.set_timer(pygame.USEREVENT+1, 5000)
 123 psz=len(pygame.image.tostring(screen, 'RGB'))
 124 while again:
 125     conns = Check.poll(1)
 126     for c in conns:
 127         cmd, (addr,tport) = Sock.recvfrom(1024)
 128         cmd = cmd.strip()
 129         if cmd == "GET":
 130             tosend = pygame.image.tostring(screen, 'RGB')
 131             sent = 0
 132             while sent != len(tosend):
 133                 sent+=Sock.sendto((sent and "FLOW" or "DATA")+tosend[sent:sent+MAXBUF-4],(addr,CPORT))-4
 134                 time.sleep(0.01)
 135         print cmd, addr
 136     # Какие события пришли (минимум одно)?
 137     for event in [pygame.event.wait()]+pygame.event.get():
 138         if event.type == pygame.QUIT:
 139             again = False
 140         # Смена игрового времени
 141         elif event.type == pygame.USEREVENT:
 142             recalc = True
 143         elif event.type == pygame.USEREVENT+1:
 144             Broad.sendto("BOWLING {} {} {}\n".format(width, height, psz), ('<broadcast>', CPORT))
 145         # Управление: события могут накладываться, логика их обработки разная
 146         elif event.type == pygame.MOUSEMOTION:
 147             cbeatpos = event.pos
 148             # если бита коснулась шара, неважно, успеют ли её передвинуть
 149             if not beaten and Overlap(cbeatpos):
 150                 beaten=cbeatpos
 151             redraw = True
 152         elif event.type == pygame.MOUSEBUTTONDOWN:
 153             if event.button == 2:
 154                 ballspeed=[atan2(event.pos[1]-ballrect.centery, event.pos[0]-ballrect.centerx), sqrt(qlength(ballrect.center,event.pos))/50]
 155         elif event.type == pygame.KEYDOWN:
 156             if event.key == pygame.K_F1:
 157                 debug = True
 158     # Взаимодействие объектов
 159     if recalc:
 160         Recalc()
 161         redraw, recalc = True, False
 162     # Обновление картинки
 163     if redraw:
 164         Redraw()
 165         redraw = False
 166     pygame.display.flip()
 167 pygame.quit()

Прикреплённые файлы

Для ссылки на прикреплённый файл в тексте страницы напишите attachment:имяфайла, как показано ниже в списке файлов. Не используйте URL из ссылки «[получить]», так как он чисто внутренний и может измениться.

Вам нельзя прикреплять файлы к этой странице.