Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Sprite explosion

sprite_explosion.livemd

Sprite explosion

Mix.install([
  {:zexray, github: "jn-jairo/zexray", depth: 1}
])

Code example

Example complexity rating: [★★☆☆] 2/4

defmodule ExampleState do
  require Record

  Record.defrecord(:example_state,
    # Explosion sound
    fx_boom: nil,
    # Explosion texture
    explosion: nil,
    # Sprite one frame rectangle width
    frame_width: 0,
    # Sprite one frame rectangle height
    frame_height: 0,
    current_frame: 0,
    current_line: 0,
    frame_rec: nil,
    position: nil,
    frames_counter: 0,
    active: false
  )

  @type example_state ::
          record(:example_state,
            fx_boom: Zexray.Type.Sound.t_resource(),
            explosion: Zexray.Type.Texture2D.t_resource(),
            frame_width: non_neg_integer,
            frame_height: non_neg_integer,
            current_frame: non_neg_integer,
            current_line: non_neg_integer,
            frame_rec: Zexray.Type.Rectangle.t(),
            position: Zexray.Type.Vector2.t(),
            frames_counter: non_neg_integer,
            active: boolean
          )
end

defmodule Example do
  @resources_dir System.tmp_dir!() <> "/zexray/resources"
  @resources_url "https://github.com/raysan5/raylib/raw/3e336e4470f7975af67f716d4d809441883d7eef"

  use Zexray.Enum
  use Zexray.Type

  import ExampleState

  def download_resources do
    File.mkdir_p!(@resources_dir)

    resources = %{
      "#{@resources_dir}/boom.wav" => "#{@resources_url}/examples/textures/resources/boom.wav",
      "#{@resources_dir}/explosion.png" =>
        "#{@resources_url}/examples/textures/resources/explosion.png"
    }

    :inets.start()
    :ssl.start()

    Enum.each(resources, fn {file, url} ->
      if not File.exists?(file) do
        {:ok, :saved_to_file} =
          :httpc.request(:get, {~c"#{url}", []}, [], stream: ~c"#{file}")
      end
    end)
  end

  @screen_width 800
  @screen_height 450
  @title "zexray [textures] example - sprite explosion"

  @num_frames_per_line 5
  @num_lines 5

  def init do
    # Initialize window
    Zexray.Window.with_window(@screen_width, @screen_height, @title, fn ->
      # Initialize audio device
      Zexray.Audio.with_audio(fn ->
        # Set our game to run at 60 frames-per-second
        Zexray.Timing.set_target_fps(60)

        # Manage resources loading/unloading
        Zexray.Resource.with_resource(
          fn ->
            # Load explosion sound
            fx_boom = Zexray.Audio.load_sound("#{@resources_dir}/boom.wav", :resource)

            # Load explosion texture
            explosion = Zexray.Texture.load("#{@resources_dir}/explosion.png", :resource)

            type_texture_2d(width: explosion_width, height: explosion_height) =
              Zexray.Resource.content!(explosion)

            # Sprite one frame rectangle width
            frame_width = div(explosion_width, @num_frames_per_line)

            # Sprite one frame rectangle height
            frame_height = div(explosion_height, @num_lines)

            frame_rec = type_rectangle(x: 0, y: 0, width: frame_width, height: frame_height)
            position = type_vector2(x: 0, y: 0)

            example_state(
              fx_boom: fx_boom,
              explosion: explosion,
              frame_width: frame_width,
              frame_height: frame_height,
              frame_rec: frame_rec,
              position: position
            )
          end,
          &amp;loop/1
        )
      end)
    end)
  end

  defp loop(state) do
    # Detect window close button or ESC key
    if Zexray.Window.should_close?() do
      :ok
    else
      # Update

      example_state(
        fx_boom: fx_boom,
        explosion: explosion,
        frame_width: frame_width,
        frame_height: frame_height,
        frame_rec: frame_rec,
        position: position,
        current_frame: current_frame,
        current_line: current_line,
        frames_counter: frames_counter,
        active: active
      ) = state

      # Check for mouse button pressed and activate explosion (if not active)
      {position, active} =
        if not active and Zexray.Mouse.pressed?(enum_mouse_button(:left)) do
          type_vector2(x: position_x, y: position_y) = Zexray.Mouse.get_position()

          position =
            type_vector2(
              x: position_x - frame_width / 2,
              y: position_y - frame_height / 2
            )

          Zexray.Audio.play(fx_boom)

          {position, true}
        else
          {position, active}
        end

      # Compute explosion animation frames
      {frames_counter, current_frame, current_line, active} =
        if active do
          frames_counter = frames_counter + 1

          {frames_counter, current_frame, current_line, active} =
            if frames_counter > 2 do
              current_frame = current_frame + 1

              {current_frame, current_line, active} =
                if current_frame >= @num_frames_per_line do
                  current_frame = 0
                  current_line = current_line + 1

                  {current_line, active} =
                    if current_line >= @num_lines do
                      {0, false}
                    else
                      {current_line, active}
                    end

                  {current_frame, current_line, active}
                else
                  {current_frame, current_line, active}
                end

              frames_counter = 0

              {frames_counter, current_frame, current_line, active}
            else
              {frames_counter, current_frame, current_line, active}
            end

          {frames_counter, current_frame, current_line, active}
        else
          {frames_counter, current_frame, current_line, active}
        end

      frame_rec =
        type_rectangle(frame_rec,
          x: frame_width * current_frame,
          y: frame_height * current_line
        )

      # Draw

      Zexray.Drawing.with_drawing(fn ->
        Zexray.Drawing.clear_background(enum_color(:raywhite))

        # Draw explosion required frame rectangle
        if active do
          Zexray.Texture.draw_rec(explosion, frame_rec, position, enum_color(:white))
        end
      end)

      state
      |> example_state(
        frame_rec: frame_rec,
        position: position,
        current_frame: current_frame,
        current_line: current_line,
        frames_counter: frames_counter,
        active: active
      )
      |> loop()
    end
  end
end
Example.download_resources()
Example.init()