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:
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:
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):
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.
Metoder för animering så att man ser när sakerna ritas upp skulle vara kul. Jag försökte lägga in canvas.show efter varje rad i ”färgexplosionen” men det funkar inte. Det verkar som den fastnar inne i den metoden. Vad gör den egentligen? Är den ärvd från Gosu?
Ja, klassen Canvas ärver från Gosu-klassen Window och show är den metod som öppnar själva grafikfönstret. Om du vill skapa animeringar kan du implementera metoden update i klassen Canvas och lägga ritkoden i den. Kika på de första ”lektionerna” här för mer info: http://rorbecker.com/spelskola/
Ja jag kom faktiskt på det efter jag skrivit. Funderade på att göra ett enkelt litet ritprogram tillsammans med ungarna.
Nu har jag lyckats lura ut hur jag fångar musens position, så att man kan rita. Men har du någon aning om man kan få ut ett Gosu-fönster med sitt program i på webben? Om man nu skulle vilja det någon gång.
Nej, vad jag vet kan du inte använda Gosu för det ändamålet. Rekommenderar dig i så fall att titta på HTML5 och Javascript. Det finns massvis av ramverk för Javascript som fyller samma funktion som Gosu – det går snabbt att komma igång och skapa spel. Googla t ex ”Javascript game engine” så får du massvis med förslag. Och så kanske du kan ha nytta av det här gamla inlägget: https://kulmedkod.wordpress.com/2013/02/20/hej-javascript/