Прикреплённый файл «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 из ссылки «[получить]», так как он чисто внутренний и может измениться.

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