Well, all great adventures start with rails new
crystal init
! So let me see:
killa@killa-MS-7A34:~/workspace$ crystal init app the_empire
create /home/killa/workspace/the_empire/.gitignore
create /home/killa/workspace/the_empire/.editorconfig
create /home/killa/workspace/the_empire/LICENSE
create /home/killa/workspace/the_empire/README.md
create /home/killa/workspace/the_empire/shard.yml
create /home/killa/workspace/the_empire/src/the_empire.cr
create /home/killa/workspace/the_empire/spec/spec_helper.cr
create /home/killa/workspace/the_empire/spec/the_empire_spec.cr
Initialized empty Git repository in /home/killa/workspace/the_empire/.git/
hooray! What I am mainly interested in in is this:
# src/the_empire.cr
# TODO: Write documentation for `TheEmpire`
module TheEmpire
VERSION = "0.1.0"
# TODO: Put your code here
end
Since it needs to be a visual app, I chose to use CrSFML. It seems to give me what I’m going to need.
Adding to shards.yml
:
dependencies:
crsfml:
github: oprypin/crsfml
version: ~> 2.5.2
Running shards install
:
killa@killa-MS-7A34:~/workspace/the_empire$ shards install
Resolving dependencies
Fetching https://github.com/oprypin/crsfml.git
Installing crsfml (2.5.2)
Postinstall of crsfml: make
Writing shard.lock
So far, so good. For my initial code, tutorial gives suggests this:
require "crsfml"
window = SF::RenderWindow.new(SF::VideoMode.new(800, 600), "My window")
# run the program as long as the window is open
while window.open?
# check all the window's events that were triggered since the last iteration of the loop
while event = window.poll_event
# "close requested" event: we close the window
if event.is_a? SF::Event::Closed
window.close
end
end
end
Let me analyze it:
SF::RenderWindow
#open?
SF::Event::Closed
, I need to close that windowThat’s very interesting! And very different to webdev, which I’m used to. I’ll change TheEmpire
to be a class like so:
# src/the_empire.cr
require "crsfml"
class TheEmpire
def initialize
@window_width = 1920
@window_height = 1080
@window = SF::RenderWindow.new(SF::VideoMode.new(@window_width, @window_height), "My window")
# If I don't do that, it actually renders ~20000 FPS, lol
@window.framerate_limit = 60
# I have 3 screens, and if I don't set it, it renders in my left-most screen.
# I would appreciate the option to define main screen, actually.
@window.position = SF.vector2(6500, 1800)
end
def running?
@window.open?
end
def handle_events
while event = @window.poll_event
handle_event(event)
end
end
# Handle the close event specifically
def handle_event(event : SF::Event::Closed)
@window.close
end
# Ignore any other event
def handle_event(event)
end
end
I’ll also introduce a startup file like so:
# src/main.cr
require "./the_empire"
the_empire = TheEmpire.new
while the_empire.running?
the_empire.handle_events
end
And a quick trip to crystal src/main.cr
gives us this:
Nice. Why is it black? A tutorial page on drawing contains an extension of the code we were supposed to write last time:
# clear the window with black color
window.clear(SF::Color::Black)
# draw everything here...
window.draw(...)
# end the current frame
window.display
So I am going to do exactly that. And a circle, for good measure:
# src/the_empire.cr, class TheEmpire
def render
@window.clear(SF::Color::White)
shape = SF::CircleShape.new(300)
shape.fill_color = SF::Color::Black
@window.draw(shape)
@window.display
end
Main loop needs to be updated as well:
# src/main.cr
require "./the_empire"
the_empire = TheEmpire.new
while the_empire.running?
the_empire.handle_events
the_empire.render
end
And that will give us
We have successfully rendered something! That will be enough for today. In the next one, we will be handling events!