Attachment '2013-12-20-greditor.py'

Download

   1 #!/usr/bin/env python
   2 # coding: utf
   3 '''
   4 Примитивный графический редактор,
   5 иллюстрирующий объектное планирование игрового пространства
   6 '''
   7 
   8 import pygame
   9 from math import *
  10 
  11 pygame.init()
  12 black = pygame.Color("black")
  13 tan = pygame.Color("tan")
  14 red = pygame.Color("tomato")
  15 green = pygame.Color("limegreen")
  16 
  17 color = green
  18 
  19 class Dot:
  20     '''Точка'''
  21     def __init__(self, size=3):
  22         '''size — размер точки при рисовании'''
  23         self.dots = []
  24         self.ndots = 1
  25         self.size = size
  26         self.color = color
  27 
  28     def append(self, dot):
  29         '''Добавить точку'''
  30         if not self.is_complete():
  31             self.dots.append(dot)
  32 
  33     def is_complete(self):
  34         '''Редактирование фигуры закончено?'''
  35         return len(self.dots) >= self.ndots
  36 
  37     def draw(self, scr, pos=None):
  38         '''Нарисовать точку по имеющимся координатам илив позиции pos'''
  39         if self.is_complete():
  40             pygame.draw.circle(scr, self.color, self.dots[0], self.size)
  41         elif pos:
  42             pygame.draw.circle(scr, self.color, pos, self.size)
  43 
  44 class Line(Dot):
  45     '''Отрезок'''
  46     def __init__(self, size=2):
  47         '''size — размер точки при рисовании'''
  48         Dot.__init__(self, size)
  49         self.ndots = 2
  50 
  51     def shape(self, scr, pos1, pos2):
  52         '''Нарисовать линию'''
  53         pygame.draw.line(scr, self.color, pos1, pos2, self.size)
  54 
  55     def draw(self, scr, pos=None):
  56         '''Нарисовать в зависимости от количества введённых точек:
  57         0 — точку в позиции pos
  58         1 — фигуру по введённой опорной точке и pos
  59         2 — фигуру по введённым опорной и второй точке'''
  60         if self.is_complete():
  61             self.shape(scr, self.dots[0], self.dots[1])
  62         elif pos:
  63             pygame.draw.circle(scr, self.color, pos, self.size)
  64             if self.dots:
  65                 self.shape(scr, self.dots[0], pos)
  66 
  67 class Polygon(Line):
  68     def __init__(self, size=2):
  69         '''size — размер точки при рисовании'''
  70         Line.__init__(self, size)
  71         self.ndots = 1000
  72 
  73     def shape(self, scr, pos_unused, pos):
  74         '''Нарисовать многоугольник, поле pos_unused не используется'''
  75         if self.is_complete():
  76             pygame.draw.polygon(scr, self.color, self.dots, self.size)
  77         elif len(self.dots)>0:
  78             pygame.draw.lines(scr, self.color, False, self.dots+[pos], self.size)
  79 
  80     def complete(self):
  81         '''Если точек больше двух, считать многоугольник готовым'''
  82         if len(self.dots)>2:
  83             self.ndots = len(self.dots)
  84 
  85 class Circle(Line):
  86     '''Окружность'''
  87     def shape(self, scr, pos1, pos2):
  88         '''Нарисовать окружность с центром в pos1 и проходящую черех pos2'''
  89         r=sqrt((pos1[0]-pos2[0])**2+(pos1[1]-pos2[1])**2)
  90         pygame.draw.circle(scr, self.color, pos1, int(r>self.size and r or self.size), self.size)
  91 
  92 class Square(Line):
  93     '''Квадрат'''
  94     def shape(self, scr, pos1, pos2):
  95         '''Нарисовать крадрат с диагональю pos1 - pos2'''
  96         cx, cy = (pos1[0]+pos2[0])/2, (pos1[1]+pos2[1])/2
  97         pos3 = cx+cy-pos1[1], cy+pos1[0]-cx
  98         pos4 = cx+pos1[1]-cy, cy+cx-pos1[0]
  99         pygame.draw.line(scr, self.color, pos1, pos3, self.size)
 100         pygame.draw.line(scr, self.color, pos3, pos2, self.size)
 101         pygame.draw.line(scr, self.color, pos2, pos4, self.size)
 102         pygame.draw.line(scr, self.color, pos4, pos1, self.size)
 103 
 104 class ColorChooser:
 105     '''Панель выбора цвета'''
 106     color = (0,0,0)
 107     def draw(self, scr, pos=None):
 108         '''Отобразить панель цветов'''
 109         sz, fr = 25, 20
 110         c = pygame.Color(0,0,0)
 111         grect = scr.get_rect().inflate(-2*fr,-2*fr)
 112         sx, sy = grect.w/sz, grect.h/sz
 113         ds = dl = int(sqrt(grect.w/sz))
 114         for y in xrange(sy):
 115             for x in xrange(ds*dl):
 116                 H = y*360/(sy-1)
 117                 S = (x%ds)*100/(ds-1)
 118                 L = (x/ds)*100/(dl-1)
 119                 #print H,S,L, x,sx
 120                 c.hsla = H,S,L,100
 121                 scr.fill(c, (fr+x*sz, fr+y*sz, sz, sz))
 122         scr.fill(self.color, (fr, fr, sz, sz))
 123 
 124 def Edit(event):
 125     '''Основной режим работы'''
 126     global Mainloop, figures, debug, nearfig, neardot
 127     if debug:
 128         print event
 129     if event.type == pygame.MOUSEMOTION:
 130         if event.buttons[0] and nearfig:
 131             i=nearfig.dots.index(neardot)
 132             neardot=nearfig.dots[i]=event.pos
 133         else:
 134             nearfig, neardot = GetNear(event.pos)
 135     elif event.type == pygame.MOUSEBUTTONDOWN:
 136         nearfig, neardot = GetNear(event.pos)
 137     elif event.type == pygame.KEYDOWN:
 138         if event.unicode in Constructors:
 139             figures.append(Constructors[event.unicode]())
 140             Mainloop = FigureEdit
 141             pygame.mouse.set_visible(False)
 142         elif event.unicode == u' ':
 143             figures.append(ColorChooser())
 144             Mainloop = ColorChoose
 145         elif event.key == pygame.K_F1:
 146             debug = not debug
 147     return None
 148 
 149 def ColorChoose(event):
 150     '''Режим выбора цвета'''
 151     global color, Mainloop, figures, debug
 152     if event.type == pygame.MOUSEMOTION:
 153         figures[-1].color=screen.get_at(event.pos)
 154     if event.type == pygame.MOUSEBUTTONDOWN:
 155         color = screen.get_at(event.pos)
 156         figures.pop()
 157         Mainloop = Edit
 158 
 159 def FigureEdit(event):
 160     '''Режим ввода фигуры'''
 161     global pos, Mainloop, figures
 162     if event.type == pygame.MOUSEMOTION:
 163         pos = event.pos
 164     elif event.type == pygame.MOUSEBUTTONDOWN:
 165         pos = event.pos
 166         if figures:
 167             figures[-1].append(pos)
 168         if event.button != 1 and hasattr(figures[-1], 'complete'):
 169             figures[-1].complete()
 170     if not figures or figures[-1].is_complete():
 171         Mainloop = Edit
 172         pygame.mouse.set_visible(True)
 173     return pos
 174 
 175 def GetNear(pos):
 176     '''Возвращает фигуру и точку в ней, ближайшую к pos.
 177     None,None — если все точки слишком далеко'''
 178     f, d = None, None
 179     alldots = [((pos[0]-x)**2+(pos[1]-y)**2,f,(x,y)) for f in figures if hasattr(f,'dots')for x,y in f.dots]
 180     if alldots:
 181         l, f, d = min(alldots)
 182     return f, d
 183 
 184 Constructors={'d': Dot, 'l': Line, 'c': Circle, 's': Square, 'p': Polygon }
 185 
 186 def Redraw(scr, pos):
 187     '''Нарисовать поле сфигурами, координаты курсора — pos'''
 188     scr.fill(black)
 189     for figure in figures:
 190         figure.draw(scr, pos)
 191         if nearfig:
 192             pygame.draw.circle(scr, black, neardot, 5)
 193             pygame.draw.circle(scr, tan, neardot, 4)
 194 
 195 size = width, height = 1000,700
 196 
 197 screen = pygame.display.set_mode(size)
 198 
 199 figures,Mainloop=[],Edit
 200 nearfig, neardot = None, None
 201 pos, again, debug = None, True, False
 202 while again:
 203     event = pygame.event.wait()
 204     # Общие события
 205     if event.type == pygame.QUIT:
 206         again = False
 207     Mainloop(event)
 208     Redraw(screen, pos)
 209     pygame.display.flip()

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.

You are not allowed to attach a file to this page.