Painting game, persist drawing

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By agent3bood

Hi all
I want to make a 2D painting game, so I want my canvas to not update on every frame.
I have node2D and this is what I did
func _ready(): get_tree().get_root().set_render_target_update_mode(1)
but it is not working.

also I tried this
func _ready(): get_tree().get_root().set_render_target_clear_on_new_frame(false)
the drawing persist, but the screen keep flickering!

note: in godot3 the code bellow works fine, but the engine is crashing under ubuntu so I cannot use it now
func _ready(): get_tree().get_root().render_target_clear_mode = 2

I made an example project for this but I don’t have it right now, need to get back home first.
Basically you can use a secondary viewport and accumulate whatever drawable stuff you want in it by disabling clear

Zylann | 2018-02-26 18:32

:bust_in_silhouette: Reply From: Zylann

Here is an example script in Godot 2 that lets you paint ont a Control node:

Project: http://zylannprods.fr/dl/godot/ChalkBoard.zip

extends Control

var _pen = null
var _prev_mouse_pos = Vector2()


func _ready():
	# Create the viewport
	var viewport = Viewport.new()
	# Make it so it renders on a texture
	viewport.set_as_render_target(true)
	# Set the size of it
	var rect = get_rect()
	viewport.set_rect(Rect2(0, 0, rect.size.x, rect.size.y))
	
	# I tried to set the background color, but none of this worked...
#	var world = World.new()
#	var env = Environment.new()
#	env.set_background(Environment.BG_COLOR)
#	env.set_background_param(Environment.BG_PARAM_COLOR, Color(0,0,0))
#	world.set_environment(env)
#	viewport.set_world(world)
#	viewport.set_use_own_world(true)
	
	_pen = Node2D.new()
	viewport.add_child(_pen)
	_pen.connect("draw", self, "_on_draw")
	
	# Don't clear the frame when it gets updated so it will accumulate drawings
	viewport.set_render_target_clear_on_new_frame(false)
	
	add_child(viewport)
	
	# Use a TextureFrame to display the result texture (because pivot is top-left)
	var rt = viewport.get_render_target_texture()
	var board = TextureFrame.new()
	board.set_texture(rt)
	add_child(board)
	
	set_process(true)


func _process(delta):
	_pen.update()


func _on_draw():
	var mouse_pos = get_local_mouse_pos()
	
	if Input.is_mouse_button_pressed(BUTTON_LEFT):
		_pen.draw_line(mouse_pos, _prev_mouse_pos, Color(1, 1, 0))
	
	_prev_mouse_pos = mouse_pos

hi Zylann, your ChalkBoard demo is work well in godot 2.0 but how it works in godot 3.0?

zhengying | 2018-09-20 10:17

It’s almost the same, I managed to make it work in Godot 3 like this:

Project: http://zylannprods.fr/dl/godot/godot3/ChalkBoard.zip

extends Control

var _pen = null
var _prev_mouse_pos = Vector2()


func _ready():
	var viewport = Viewport.new()
	var rect = get_rect()
	viewport.size = rect.size
	viewport.usage = Viewport.USAGE_2D
	# Note: I also tried CLEAR_MODE_NEVER but it doesn't draw anything.
	# (see issue https://github.com/godotengine/godot/issues/20775)
	viewport.render_target_clear_mode = Viewport.CLEAR_MODE_ONLY_NEXT_FRAME
	viewport.render_target_v_flip = true
	
	_pen = Node2D.new()
	viewport.add_child(_pen)
	_pen.connect("draw", self, "_on_draw")
	
	add_child(viewport)
	
	# Use a sprite to display the result texture
	var rt = viewport.get_texture()
	var board = TextureRect.new()
	board.set_texture(rt)
	add_child(board)


func _process(delta):
	_pen.update()


func _on_draw():
	var mouse_pos = get_local_mouse_position()
	
	if Input.is_mouse_button_pressed(BUTTON_LEFT):
		_pen.draw_line(mouse_pos, _prev_mouse_pos, Color(1, 1, 0))
	
	_prev_mouse_pos = mouse_pos

Zylann | 2018-09-20 19:31

thanks Zylann.
It’s works well!

zhengying | 2018-09-21 02:18

Hi Zylann,
I saw you tried a few different methods to change the background for your chalkboard that were all unsuccesful. Have you found out a way to do it yet? I am creating a notepad type app in godot and wanted the ability to draw in a textbox. I tried overlaying a control node with your sample script over the textbox but then the text is covered up as well. Is there a way to make the background transparent?

kingpinpenguin | 2020-01-16 04:45

Hey kingpinpenguin,

Almost a year late and I’m not Zylann, but I’ve got a solution. Put this anywhere before adding “viewport” as a child in _ready():

viewport.set_transparent_background(true)

FakeSky | 2020-12-08 20:39