the_empire_blog

Getting Started

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:

That’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:

Empty black screen

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

A white screen, and a black ball

We have successfully rendered something! That will be enough for today. In the next one, we will be handling events!