Прикреплённый файл «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 из ссылки «[получить]», так как он чисто внутренний и может измениться.- [получить | показать] (2014-04-04 13:15:14, 1.6 KB) [[attachment:2014-03-28-ubclient.py]]
- [получить | показать] (2014-04-04 13:15:30, 3.1 KB) [[attachment:2014-03-28-udp.py]]
- [получить | показать] (2014-04-04 13:14:39, 6.6 KB) [[attachment:2014-03-28-udpbowling.py]]
- [получить | показать] (2014-03-28 09:43:10, 0.3 KB) [[attachment:pybroad.py]]
- [получить | показать] (2014-03-28 09:43:02, 0.6 KB) [[attachment:pyudp.py]]
Вам нельзя прикреплять файлы к этой странице.