doc_extras/guides/opening-a-window.md

# Your first Exray application

## Baby Steps - Running from IEX to get the vibe

`Made with 0.4.0`. Likely out of date, but a good overall jist of what's going on.

Once you have ensured that you are setup by adding `:exray` to your [mix dependencies](../../README.md#adding-exray-to-your-mixexs-dependencies) and [compiled your NIFs](../../README.md#compiling-exray-nifs), you're ready to rumble.

Begin by running `iex -S mix` in the root of your project, then try the following:

```elixir

$> iex -S mix
#> Generated exray app
#> Interactive Elixir (1.17.3) - press Ctrl+C to exit (type h() ENTER for help)

## We first import Exray.Core.Window so we can call it's functions.
iex> import Exray.Core.Window
#> Exray.Core.Window

## Then, we can call init_window/3, which takes a width / height / title.
iex> init_window(200, 200, "Hello World!")
#> [INFO] : Initializing raylib 5.0
#> [INFO] : Platform backend: DESKTOP (GLFW)
#> [INFO] : Supported raylib modules:
#> [INFO] :     > rcore:..... loaded (mandatory)
#> ... SNIP ...
#> [INFO] : RLGL: Default OpenGL state initialized successfully
#> [INFO] : TEXTURE: [ID 2] Texture loaded successfully (128x128 | GRAY_ALPHA | 1 mipmaps)
#> [INFO] : FONT: Default font loaded successfully (224 glyphs)
#> :ok

## Without a running loop, it makes update & draw calls difficult. So for now, we'll close it up.
iex> close_window()
#> Segmentation fault (core dumped)
```

Wait- What? Segmentation fault (core dumped)??

Don't worry, we didn't exactly close it 'clean'; we called close_window but we hadn't done anything with the window, so it was pretty much holding itself together in a state of ".. Please, update and draw me".

Segmentation faults are unfortunately something that will trigger the entire BEAM VM to crash and there just isn't a good way to debug them. Thankfully, with a bit of knowledge working with the NIFs I've found a pretty decent way to at least get the game running and callback the Raylib C without it deciding it doesn't feel like it today, causing a segfault.

## Basic Game Loop

So we're going to create a new file (exs|ex) and open it up to flesh it out.

### Stage 1; initial module setup & function structure

Start with defining the module:
```elixir
defmodule SuperCoolGame do

end
```

Then adding in a few functions, which will make sense shortly:
```elixir
defmodule SuperCoolGame do
  
  def run() do

  end

  defp main_loop() do

  end

  defp update() do

  end

  defp draw() do

  end

end
```

Now what we've just done is create 3 private functions; `main_loop()`, `update()` and `draw()` as well as a public function named `run()` which is where we're actually going to enter this module from.

Let's add a little more structure, so the functions can call correctly:
```elixir
defmodule SuperCoolGame do
  
  def run(width \\ 200, height \\ 200, title \\ "Hello World!") do
    main_loop()
    :ok # :ok, because we're :ok :)
  end

  defp main_loop() do
    update()
    draw()

    main_loop()
  end

  defp update() do

  end

  defp draw() do

  end

end
```

### Stage 2; adding Raylib stuff

And finally, let's organize some logic so we can setup a window, poll input and exit safely:
```elixir
defmodule SuperCoolGame do

  # We import Exray.Core.Window, like we did in IEX.
  import Exray.Core.Window
  # But, we also import Exray.Core.Drawing, to have access to begin_draw() and end_draw() calls.
  # This is to poll for window_should_close?() events, as without end_draw() no inputs will be polled at all.
  import Exray.Core.Drawing
  # We also need to import Exray.Core.Timing in order to set our FPS. This is VERY important.
  import Exray.Core.Timing
  
  def run(width \\ 200, height \\ 200, title \\ "Hello World!") do
    init_window(width, height, title)
    set_target_fps(60) # <-- SUPER important! Call this just after you init_window, or segfaults are gonna happen a lot.
    main_loop()

    # As another layer of safety, if for some reason our window *didn't* close, we can do it here in this check.
    if window_should_close?() do
      close_window()
    end

    :ok # :ok, because we're :ok :)
  end

  defp main_loop() do

    # Stay out of update and draw unless our window is ready to update and draw.
    unless window_is_ready?(), do: main_loop()

    # If at any point we press Raylib's default "Quit Application" key, (ESCAPE), stop looping and exit.
    unless window_should_close?() do
      update()
      draw()
      main_loop()
    end
  end

  defp update() do
    # Nothing yet!
  end

  defp draw() do
    # Before drawing, we'll clear the background with the Exray.Utils.Colors.black function result- Which is %Exray.Structs.Color{r: 0, g: 0, b: 0, a: 255}.
    clear_background(Exray.Utils.Colors.black())
    begin_drawing()

    # Nothing yet!

    end_drawing()
  end

end
```

Granted, you may still `segfault`, however you're doing the best you can to avoid it. As Exray develops, I'm hoping to add a lot more defenses against this illusive (and transient) problem, but for now it's kind of just something that happens. I've found it's safest when running from a `.exs` file, but I'm not really sure why.

In any case, you can now run this module by restarting your IEX and calling `SuperCoolGame.run()`.

```elixir
$> iex -S mix
#> Generated exray app
#> Interactive Elixir (1.17.3) - press Ctrl+C to exit (type h() ENTER for help)

iex> SuperCoolGame.run()
#> [INFO] : Initializing raylib 5.0
#> [INFO] : Platform backend: DESKTOP (GLFW)
#> [INFO] : Supported raylib modules:
#> [INFO] :     > rcore:..... loaded (mandatory)
#> [INFO] :     > rlgl:...... loaded (mandatory)
#> [INFO] :     > rshapes:... loaded (optional)
#> .......
```

At that point, a window should pop up with a clear black screen, 200x200 across with the title "Hello World!". You can close it by pressing ESCAPE.