Att rita geometriska figurer på skärmen, det är ju sådant som exempelvis Javascript är bra på. Men hur gör man bäst om man vill använda Ruby? Det har jag funderat på de senaste dagarna. Efter att ha testat ett par olika sätt har jag skrivit, eller snarare börjat skriva på, ett litet program som jag har tänkt att ungarna ska få leka med framöver.

Programmet, som jag kallar för Canvas (”canvas.rb” i exemplen nedan), ger tillgång till en ”målarduk” (”canvas” på engelska) och ett knippe metoder för att rita olika figurer. Följande kodsnutt visar hur det kan användas.

require_relative 'canvas.rb'

canvas = Canvas.new

canvas.paint_background("lightblue")
canvas.draw_circle(250, 250, 100, "red", true)
canvas.draw_box(50, 100, 200, 100, "darkblue", true)
canvas.draw_triangle(275, 250, 350, 125, 425, 250, "green")
canvas.draw_polygon(400, 400, 75, 9, "pink", 10)
canvas.fill(400, 400, "yellow")
canvas.draw_line(50, 475, 475, 175, "orange", 7)

canvas.show

Den första raden exekverar ”canvas.rb” som ska ligga i samma katalog som koden ovan. Sedan skapas ett nytt objekt av klassen Canvas, det vill säga själva ”målarduken”. Därefter ritar och målar jag på duken med de olika metoderna, innan konstverket till sist visas på skärmen med metoden show. Resultatet ser ut så här:

konst

Inte särskilt vackert, det medges. Men ett hyfsat smidigt sätt att skapa grafik av det här slaget. Jag måste dock erkänna att det inte är mitt program som står för magin här. I stället är det Gosu – ramverket för spelprogrammering som jag har skrivit om tidigare – och det tillhörande verktyget Texplay som gör jobbet. Syftet med Canvas är främst att göra de metoder som redan finns i Texplay lite lättare att använda och att minska mängden omgivande kod. Jag har också lagt till en metod för att rita trianglar samt så kallade RGB-värden för ytterligare några färger.

Jag ska strax gå närmare in på hur metoderna används. Men först lite mer lek. I koden nedan tar jag hjälp av slumpen (metoden rand returnerar ett slumptal) och en loop…

require_relative 'canvas.rb'

canvas = Canvas.new

canvas.paint_background("red")
100.times do
  canvas.draw_line(250, 250, rand(500), rand(500), "white")
  canvas.draw_line(250, 250, rand(500), rand(500), "yellow")
  canvas.draw_line(250, 250, rand(500), rand(500), "green")
  canvas.draw_line(250, 250, rand(500), rand(500), "turquoise")
  canvas.draw_line(250, 250, rand(500), rand(500), "tyrian")
  canvas.draw_line(250, 250, rand(500), rand(500), "orange")
  canvas.draw_line(250, 250, rand(500), rand(500), "cyan")
end

canvas.show

… för att skapa denna färgexplosion:

canvas

När mina barn premiärtestade programmet häromkvällen ritade vi flaggor. Med den här koden…

require_relative 'canvas.rb'

canvas = Canvas.new(800, 400)

canvas.draw_line(0, 400, 280, 0, "darkblue")
canvas.fill(10, 10, "darkblue")
canvas.draw_line(0, 400, 500, 0, "yellow")
canvas.fill(290, 10, "yellow")
canvas.draw_line(0, 400, 800, 130, "red")
canvas.fill(510, 10, "red")
canvas.draw_line(0, 400, 800, 270, "darkgreen")
canvas.fill(790, 390, "darkgreen")

canvas.show

… skapade vi till exempel Seychellernas flagga (med reservation för att färgnyanserna inte är helt korrekta):

seychellerna

Om du själv vill prova att rita med Canvas måste du förstås ha installerat Ruby på din dator. Därutöver måste du ha installerat Gosu och Texplay (görs enkelt genom att skriva gem install gosu respektive gem install texplay vid kommandoprompten). Och så måste du ha filen ”canvas.rb” i din arbetskatalog. Längst ner i inlägget hittar du en länk till källkoden som får kopieras fritt. Programmet är på intet sätt färdigt, utan jag planerar att lägga till fler metoder, bland annat för animering. Kom gärna med synpunkter och förslag!

Okej, här följer nu en genomgång av metoderna och de argument (det som står inom parenteserna) de tar:

paint_background("färg")

Målar bakgrunden i angiven färg. Färgen måste skrivas på engelska, inom citattecken. De färger som i skrivande stund stöds är: ”black”, ”blue”, ”brown”, ”cyan”, ”green”, ”grey”, ”orange”, ”purple”, ”red”, ”turquoise”, ”tyrian”, ”white”, ”yellow”, ”darkblue”, ”lightblue”, ”darkgreen”, ”tomato”, ”darkred”, ”pink” och ”deeppink”.

draw_circle(x, y, r, "färg", true/false)

Ritar en cirkel med mittpunkten x, y och radien r (mätt i pixlar). Målarduken är i standardläget 500 gånger 500 pixlar. Längst upp i vänstra hörnet är koordinaterna 0, 0 och längst ner i högra hörnet är de 500, 500. Det femte och sista argumentet anger om cirkeln ska vara fylld (true) eller ej (false). Standardvärdet är false, så om cirkeln inte ska vara fylld behövs inget femte argument. (Även färgargumentet är egentligen frivilligt, standardfärgen är svart.)

draw_box(x, y, bredd, höjd, "färg", true/false)

Ritar en rektangel/kvadrat vars övre vänstra hörn får positionen x, y.

draw_triangle(x1, y1, x2, y2, x3, y3, "färg", tjocklek)

Drar linjer mellan de tre angivna punkterna, dvs ritar en triangel. Här saknas möjlighet att fylla triangeln direkt, utan det får i stället göras med fill-metoden nedan (detsamma gäller månghörningar). Det sista argumentet avser linjens tjocklek, standardvärdet är 1.

draw_polygon(x, y, r, antal sidor, "färg", tjocklek)

Ritar en regelbunden polygon/månghörning med mittpunkten x, y och radien r.

draw_line(x1, y1, x2, y2, "färg", tjocklek)

Drar en linje mellan två punkter.

fill(x, y, "färg")

Fyller ett avgränsat område med färg genom att man anger en punkt inuti området. Fungerar alltså på samma sätt som ”flood fill” i ett ritprogram. Kan användas för att fylla trianglar och månghörningar.

Till sist några ord om storleken på målarduken. Som flaggexemplet ovan visar går det att ändra storleken genom att skicka med måtten när Canvas-objektet bildas (t ex canvas = Canvas.new(800, 400)). Det här funkar dock inte helt perfekt. Gosu gillar nämligen inte när fönstret blir för stort, och vad som är ”för stort” tycks bero på skärmens upplösning. På min dator verkar maxstorleken vara 1000 gånger 600 pixlar. Om jag överskrider den gränsen börjar programmet bete sig knasigt.

Det var allt för den här gången. Låt mig gärna veta vad du tycker om inlägget, antingen här på bloggen eller på Twitter. Vi hörs!

/Mats

Du hittar källkoden till Canvas här.