7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ElixirAdvent Calendar 2024

Day 23

Elixirで作る「DDJ-FLX4のジョグ対応ブロックくずし」 その9 ゲームのメイン処理をつくる

Last updated at Posted at 2024-12-22

Elixirで作る「DDJ-FLX4のジョグ対応ブロックくずし」 その8 あたり判定を作る
のづつきです

今回は、ゲームのメイン処理をつくります

今回の部分のgithub

仕様

Blockモジュール

  • main(nil)

    • マップを初期化します
      • wall: 壁の座標のリスト
        • [x 横座標, y 縦座標, w 横幅, h 縦幅]の形式 以後、座標のリストはこの形式
      • blocks: ブロックの座標のリスト
        • ブロックが当たると削除していく仕様にします
      • player: プレイヤー座標です 左右の移動のみ
      • ball: ボールの座標です 壁、ブロック、プレイヤーに当たると反射します
      • ball_speed_x,ball_speed_y: ボールの速度、反射の時は符号が反転します
  • main(%{} = data)

    • ブロックのあたり判定
      • ボールがブロックに当たると該当のブロックの座標がリストから消えます
    • ボールの反射処理(速度)
      • 壁、プレイヤー、ブロックにボールが当たった時に反転します
    • ボールの座標更新
      • 上記のボールの反射処理(速度)を元に座標を加算します
    • プレイヤーの座標更新
      • Agentの元に座標を加算します(DJコントローラーを動かすとAgentの値が変化します)
      • Agentの値を0にします(変化量をクリアします)
    • マップを更新する

DdjBlockモジュール

前回からの仕様変更

  • set_state
    • 加算でなくDJコントローラーの値を格納する
  • main_loop
    • Block.main(data)を呼ぶ
    • 描画するリストを作る
    • drawで描画するリストの内容を描画
  • draw(draw_list)
    • 描画するリストの内容を描画
    • 四角ののみ描画できる

ソースを書く

ddj_block/lib/block.ex
defmodule Block do
  def main(nil) do
    blocks =
      1..3
      |> Enum.flat_map(fn y -> creat_blocks(y) end)

    %{
      wall: [
        [0.0, 0.0, 10.0, 900.0],
        [790.0, 0.0, 10.0, 900.0],
        [0.0, 0.0, 900.0, 10.0],
        [0.0, 900.0, 900.0, 10.0]
      ],
      blocks: blocks,
      player: [[350.0, 790.0, 100.0, 10.0]],
      ball: [[350.0, 400.0, 10.0, 10.0]],
      ball_speed_x: -2.0,
      ball_speed_y: -2.0
    }
  end

  def main(%{} = data) do
    [[x, y, w, h]] = data.ball
    wall_lr = data.wall |> Enum.slice(0..1)
    wall_t = data.wall |> Enum.slice(2..3)

    {collided, blocks} = Game.collided_with_filter(x, y, w, h, data.blocks)

    ball_speed_y =
      if Game.collided?(x, y, w, h, wall_t ++ data.player) or collided,
        do: data.ball_speed_y * -1.0,
        else: data.ball_speed_y * 1.0

    ball_speed_x =
      if Game.collided?(x, y, w, h, wall_lr ++ data.player) or collided,
        do: data.ball_speed_x * -1.0,
        else: data.ball_speed_x * 1.0

    [[bx, by, bw, bh]] = data.ball
    ball = [[bx + ball_speed_x, by + ball_speed_y, bw, bh]]

    [[px, py, pw, ph]] = data.player
    player = [[px + DdjBlock.get_state() * 20, py, pw, ph]]
    DdjBlock.set_state(0.0)

    Map.merge(data, %{
      ball_speed_y: ball_speed_y,
      ball_speed_x: ball_speed_x,
      ball: ball,
      player: player,
      blocks: blocks
    })
  end

  def creat_blocks(y) do
    1..5
    |> Enum.map(fn x ->
      [120.0 * x, 100.0 * y, 100.0, 50.0]
    end)
  end
end

ddj_block/lib/ddj_block.ex
defmodule DdjBlock do
  @moduledoc """
  Documentation for `DdjBlock`.
  """
  alias Rayex.Structs.Rectangle
  use Rayex
  alias Socket.Web

  @sleep 10
  @color %{r: 0, g: 255, b: 0, a: 255}

  def main() do
    Agent.start_link(fn -> 400.0 end, name: __MODULE__)
    socket = Web.connect!("localhost", 4000, path: "/socket/websocket?token=undefined&vsn=2.0.0")

    socket
    |> join()

    Task.async(fn ->
      socket_loop(socket)
    end)

    init_window(800, 800, "DdjBlock")
    main_loop(true, nil)
  end

  def socket_loop(socket) do
    {_, text} = Socket.Web.recv!(socket)

    text
    |> Jason.decode!()
    |> Enum.at(4)
    |> Map.get("body", "0.0")
    |> String.to_float()
    |> set_state()

    socket_loop(socket)
  end

  defp main_loop(true, data) do
    data = Block.main(data)
    draw_list = data.wall ++ data.blocks ++ data.player ++ data.ball

    begin_drawing()
    clear_background(%{r: 0, g: 0, b: 0, a: 0})
    draw(draw_list)
    end_drawing()

    Process.sleep(@sleep)
    main_loop(!window_should_close(), data)
  end

  defp main_loop(_, data), do: nil

  defp draw(draw_list) do
    draw_list
    |> Enum.each(fn draw ->
      [x, y, w, h] = draw
      rectangle = %Rectangle{x: x, y: y, width: w, height: h}
      draw_rectangle_lines_ex(rectangle, 1, @color)
    end)
  end

  def send_data(socket, data) do
    data = """
    ["3","4","ddj:lobby","new_msg",{"body":"#{data}"}]
    """

    Web.send!(socket, {:text, data})
    socket
  end

  def join(socket) do
    phx_join = """
    ["3","3","ddj:lobby","phx_join",{}]
    """

    Web.send!(socket, {:text, phx_join})
    socket
  end

  def get_state, do: Agent.get(__MODULE__, & &1)

  def set_state(v) do
    Agent.update(__MODULE__, fn _ -> v end)
  end
end


動かす

ddj_server
ddj_block/ddj_server$ mix phx.server
ddj_client
ddj_block/ddj_client$ mix run --eval "DdjClient.hello"
ddj_block
ddj_block/ddj_block$  mix run --eval "DdjBlock.main"

動作動画

今回はここまで

つづく

7
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?