This thread got me interested in trying to make a drawing function, so like was mentioned before, I tried making a UDD. It works a lot better than the button method but it's still far from perfect. Never used UDD before as never needed it so it's probably a bit messy but here it is.
Code: Select all
lDraw_Pos = [] ## List of displayable colors positions
class Draw(renpy.Displayable):
def __init__(self, color, size, width, height):
super(Draw, self).__init__()
self.col = color ## Brush color
self.size = size ## Brush size tuple
self.canvas_w = width ## Width of drawing space
self.canvas_h = height ## Height of drawing space
self.drawing = False
self.erasing = False
self.pos = (0, 0) ## Cursor position tuple
def render(self, width, height, st, at):
global lDraw_Pos
## Create drawing space
canvas = renpy.Render(self.canvas_w, self.canvas_h)
canvas.canvas().rect('#FFF', (0, 0, self.canvas_w, self.canvas_h))
## Set brush location
x, y = self.pos
w, h = self.size
x -= w / 2
y -= h / 2
## Prevent brush from leaving drawing space
if x < 0:
x = 0
elif x > self.canvas_w - w:
x = self.canvas_w - w
if y < 0:
y = 0
elif y > self.canvas_h - h:
y = self.canvas_h - h
## Create brushes
t_brush = Transform(child=Solid(self.col), size=self.size)
brush = renpy.render(t_brush, width, height, st, at)
t_eraser = Transform(child=Solid('#FFF'), size=self.size)
eraser = renpy.render(t_eraser, width, height, st, at)
## Add displayables to lists
if self.drawing and (brush, (x, y)) not in lDraw_Pos:
lDraw_Pos.append( (brush, (x, y)) )
elif self.erasing and (eraser, (x, y)) not in lDraw_Pos:
lDraw_Pos.append( (eraser, (x, y)) )
## Add the list of displayables to the drawing space
for v in lDraw_Pos:
canvas.blit(v[0], v[1])
return canvas
def event(self, ev, x, y, st):
# Set variable to true when key is pressed and set to false when released to create a pseudo key hold
if renpy.map_event(ev, 'mousedown_1'):
## Start drawing
self.drawing = True
elif renpy.map_event(ev, 'mouseup_1'):
## Stop drawing
self.drawing = False
if renpy.map_event(ev, 'mousedown_3'):
## Start erasing
self.erasing = True
elif renpy.map_event(ev, 'mouseup_3'):
## Stop erasing
self.erasing = False
renpy.redraw(self, 0.0)
## Get cursor position
self.pos = (x, y)
Have to define the displayable list as global to allow for color and size changes as when you click a button the screen updates, resetting the UDD. I suppose you could set it as a screen variable and pass it as an argument to the UDD so it resets when you leave and return to the screen.
One big issue is that when you move the cursor too fast, it can't keep up with the mouse tracking and you end up with spaces between each pixel but not sure that can be fixed.
If you change it a bit and have it display an image of a circle instead of a solid block of color, you could get a "cheap" antialiasing effect, using matrix color to change the color etc. but I haven't tried it yet.
But the code is there if anyone wants to use or improve it.
Sample screen to show UDD with buttons to change color/size and clear the canvas:
Code: Select all
screen canvas():
tag menu
default color_list = [ '#FFFFFF', '#000000', '#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#00FFFF', '#FF00FF' ]
default draw_color = '#000000'
default brush_size = (2, 2)
vbox:
add Draw(draw_color, brush_size, 500, 500)
grid 4 2:
for v in color_list:
button xysize (20, 20):
action SetScreenVariable('draw_color', v)
background v
hbox:
textbutton "Size 2" action SetScreenVariable('brush_size', (2, 2))
textbutton "Size 4" action SetScreenVariable('brush_size', (4, 4))
textbutton "Size 10" action SetScreenVariable('brush_size', (10, 10))
textbutton "Clear Canvas" action SetVariable('lDraw_Pos', []) selected False
And of course, here's your complimentary snail pic.