Elixirで作る「DDJ-FLX4のジョグ対応ブロックくずし」 その8 あたり判定を作る
のづつきです
今回は、ゲームのメイン処理をつくります
今回の部分のgithub
仕様
Blockモジュール
-
main(nil)
- マップを初期化します
- wall: 壁の座標のリスト
- [x 横座標, y 縦座標, w 横幅, h 縦幅]の形式 以後、座標のリストはこの形式
- blocks: ブロックの座標のリスト
- ブロックが当たると削除していく仕様にします
- player: プレイヤー座標です 左右の移動のみ
- ball: ボールの座標です 壁、ブロック、プレイヤーに当たると反射します
- ball_speed_x,ball_speed_y: ボールの速度、反射の時は符号が反転します
- wall: 壁の座標のリスト
- マップを初期化します
-
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"
動作動画
今回はここまで
つづく