Прикреплённый файл «2013-11-29-smartbowling.py»
Загрузка 1 #!/usr/bin/env python
2 # coding: utf
3 '''
4 Упражнение с мячом и битой
5 '''
6
7 import sys, pygame
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 = 1000,800
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
48 def Overlap(pos):
49 '''Пересекается ли бита по координатам pos с мячом?'''
50 rect = beatrect.copy()
51 rect.center=pos
52 return ballrect.colliderect(rect) and \
53 ballmask.overlap(beatmask, (rect.left-ballrect.left, rect.top-ballrect.top))
54
55 def Interact(act=None):
56 '''Влияние биты на скорость мяча'''
57 act = act or beaten
58 # угол удара (направление от мяча к точке соударения)
59 a = atan2(act[1]-ballrect.centery, act[0]-ballrect.centerx)
60 if (a-ballspeed[0]+2.5*pi)%(2*pi)<pi:
61 # удар спереди: отразим от плоскости соприкосновения
62 return pi-ballspeed[0]+2*a
63 else:
64 # удар сзади не считается
65 return ballspeed[0]
66
67 def Recalc():
68 '''Пересчёт игрового пространства'''
69 global beaten, ballspeed
70 if not beaten and Overlap(cbeatpos):
71 beaten = cbeatpos
72 if beaten:
73 ballspeed[0] = Interact()
74 beaten = None
75 x,y = ballpos[-1][0]+ballspeed[1]*cos(ballspeed[0]),ballpos[-1][1]+ballspeed[1]*sin(ballspeed[0])
76 if not ballrect.width/2<x<width-ballrect.width/2: ballspeed[0]=pi-ballspeed[0]
77 if not ballrect.height/2<y<height-ballrect.height/2: ballspeed[0]=-ballspeed[0]
78 x,y = ballpos[-1][0]+ballspeed[1]*cos(ballspeed[0]),ballpos[-1][1]+ballspeed[1]*sin(ballspeed[0])
79 # TODO а вдруг это не поможет?
80 # TODO бита не должна уж совсем на шар налезать
81 ballpos.pop(0)
82 ballpos.append((x,y))
83 beatpos.pop(0)
84 beatpos.append(cbeatpos)
85
86 def Redraw():
87 '''Отображение игрового пространства'''
88 ballrect.center=(int(ballpos[-1][0]),int(ballpos[-1][1]))
89 beatrect.center=cbeatpos
90 screen.fill(back)
91 screen.blit(ball, ballrect)
92 screen.blit(beat, beatrect)
93 if debug:
94 a=Interact(beatrect.center)
95 draw_arrow(screen, pygame.Color("green"), ballrect.center, (ballrect.centerx+ballspeed[1]*cos(ballspeed[0])*50, ballrect.centery+ballspeed[1]*sin(ballspeed[0])*50))
96 draw_arrow(screen, pygame.Color("yellow"), ballrect.center, (ballrect.centerx+ballspeed[1]*cos(a)*50, ballrect.centery+ballspeed[1]*sin(a)*50))
97 draw_arrow(screen, pygame.Color("magenta"), beatrect.center, ballrect.center)
98
99 pygame.mouse.set_visible(False)
100 # Смена игрового времени
101 pygame.time.set_timer(pygame.USEREVENT, 50)
102 while again:
103 # Какие события пришли (минимум одно)?
104 for event in [pygame.event.wait()]+pygame.event.get():
105 if event.type == pygame.QUIT:
106 again = False
107 # Смена игрового времени
108 elif event.type == pygame.USEREVENT:
109 recalc = True
110 # Управление: события могут накладываться, логика их обработки разная
111 elif event.type == pygame.MOUSEMOTION:
112 cbeatpos = event.pos
113 # если бита коснулась шара, неважно, успеют ли её передвинуть
114 if not beaten and Overlap(cbeatpos):
115 beaten=cbeatpos
116 redraw = True
117 elif event.type == pygame.MOUSEBUTTONDOWN:
118 if event.button == 2:
119 ballspeed=[atan2(event.pos[1]-ballrect.centery, event.pos[0]-ballrect.centerx), sqrt(qlength(ballrect.center,event.pos))/50]
120 elif event.type == pygame.KEYDOWN:
121 if event.key == pygame.K_F1:
122 debug = True
123 # Взаимодействие объектов
124 if recalc:
125 Recalc()
126 redraw, recalc = True, False
127 # Обновление картинки
128 if redraw:
129 Redraw()
130 redraw = False
131 pygame.display.flip()
132 pygame.quit()
Прикреплённые файлы
Для ссылки на прикреплённый файл в тексте страницы напишите attachment:имяфайла, как показано ниже в списке файлов. Не используйте URL из ссылки «[получить]», так как он чисто внутренний и может измениться.- [получить | показать] (2013-12-06 14:13:23, 4.0 KB) [[attachment:2013-11-29-balls.py]]
- [получить | показать] (2013-12-07 08:45:07, 4.8 KB) [[attachment:2013-11-29-polynom.py]]
- [получить | показать] (2013-12-04 21:12:18, 5.4 KB) [[attachment:2013-11-29-smartbowling.py]]
- [получить | показать] (2013-12-05 14:02:56, 11.3 KB) [[attachment:bowling.png]]
- [получить | показать] (2013-12-05 14:02:51, 1.0 KB) [[attachment:bowling.seg]]
Вам нельзя прикреплять файлы к этой странице.