defmodule TetrisuiWeb.TetrisLive do use Phoenix.LiveView use TetrisuiWeb, :live_view import Phoenix.HTML, only: [raw: 1] @debug true @box_width 20 @box_height 20 defp mount_test(_params,_session, socket) do { :ok, assign(socket, brick: Tetris.Brick.new_random |> Tetris.Brick.to_string, tetromino: [ {1, 1, :orange}, {2, 1, :orange}, {3, 1, :red} , {4, 1, :blue}, ], name: "julz" ) } end def mount(_params, _session, socket) do socket2 = assign(socket,appstate: "loading") case connected?(socket2) do true -> {:ok, start_game(socket2)} false -> {:ok, socket2} end end defp start_game(socket) do :timer.send_interval 1000, self(), :tick assign(socket, appstate: "loaded", state: :starting, ) end defp new_game(socket) do assign(socket, appstate: "loaded", state: :playing, score: 0, bottom: %{}, game_over: false ) |> new_block |> show end def new_block(socket) do brick = Tetris.Brick.new_random() |> Map.put(:location, {3, -3}) assign(socket,brick: brick) end def show(socket) do brick = socket.assigns.brick points_with_colour = brick |> Tetris.Brick.prepare |> Tetris.Points.move_to_location(brick.location) |> Tetris.Points.with_colour(colour(brick)) assign(socket, tetromino: points_with_colour) end def render(%{appstate: "loading"}=assigns) do ~L"""

Tetris

Loading...
""" end def render(%{state: :starting}=assigns) do ~L"""

Welcome to Tetris

""" end def render(%{appstate: "loaded", state: :playing}=assigns) do #
<%= @brick%>
#
~L"""

Tetris <%= @score %>

<%= raw svg_head()%> <%= raw boxes(@tetromino)%> <%= raw boxes(Map.values(@bottom)) %> <%= raw svg_foot()%>
<%= debug(assigns) %> """ end def render(%{appstate: "loaded", state: :game_over}=assigns) do #
<%= @brick%>
#
~L"""

Tetris - GAME OVER - score: <%= @score %>

<%= debug(assigns) %> """ end #def render(%{appstate: _other}=assigns) do # ~L"

tetrisui - unknown app state <%= @appstate %>

" #end def svg_head() do """ """ end def svg_foot(), do: "" def boxes(points_with_colours) do points_with_colours |> Enum.map( fn {x,y,colour} -> box({x,y}, colour) end) |> Enum.join("\n") end def box(point,colour) do """ #{square(point, shades(colour).light)} #{triangle(point, shades(colour).dark)} """ end def square(point,shade) do {x,y} = to_pixels(point) """ """ end def triangle(point,shade) do {x,y} = to_pixels(point) {w,h} = {@box_width, @box_height} """ """ end defp to_pixels({x,y}), do: {(x-1) * @box_width, (y-1) * @box_height} defp shades(:red ), do: %{ light: "DB7160", dark: "AB574B"} defp shades(:blue ), do: %{ light: "83C1C8", dark: "66969C"} defp shades(:green ), do: %{ light: "8BBF57", dark: "769359"} defp shades(:orange ), do: %{ light: "CB8E4E", dark: "AC7842"} defp shades(:grey ), do: %{ light: "A1A09E", dark: "7F7F7E"} defp colour(%{name: :t}), do: :red defp colour(%{name: :i}), do: :blue defp colour(%{name: :l}), do: :green defp colour(%{name: :o}), do: :orange defp colour(%{name: :z}), do: :grey def drop(:playing, socket, fast) do old_brick = socket.assigns.brick response = Tetris.drop( old_brick, socket.assigns.bottom, colour(old_brick) ) bonus = if fast, do: 2, else: 0 state = if response.game_over, do: :game_over, else: :playing socket |> assign( brick: response.brick, bottom: response.bottom, score: socket.assigns.score + response.score + bonus, state: state ) |> show end def drop(_not_playing, socket, _dontcare), do: socket def move(direction, socket) do socket |> do_move(direction) |> show end def do_move(%{assigns: %{brick: brick, bottom: bottom}}=socket, :left) do assign(socket, brick: brick |> Tetris.try_left(bottom)) end def do_move(%{assigns: %{brick: brick, bottom: bottom}}=socket, :right) do assign(socket, brick: brick |> Tetris.try_right(bottom)) end def do_move(%{assigns: %{brick: brick, bottom: bottom}}=socket, :turn) do assign(socket, brick: brick |> Tetris.try_spin(bottom)) end def handle_event("keydown", %{"key" => "ArrowLeft"}, socket) do {:noreply, move(:left,socket)} #{:noreply, assign(socket, tetromino: [])} end def handle_event("keydown", %{"key" => "ArrowRight"}, socket) do {:noreply, move(:right,socket)} end def handle_event("keydown", %{"key" => "ArrowUp"}, socket) do {:noreply, move(:turn,socket)} end def handle_event("keydown", %{"key" => "ArrowDown"}, socket) do {:noreply, drop(socket.assigns.state,socket, :true)} end def handle_event("keydown", _other, socket) do {:noreply, socket} end def handle_event("start", _other, socket) do {:noreply, new_game(socket)} end def handle_info(:tick, socket) do {:noreply, drop(socket.assigns.state, socket, :false)} end def debug(assigns), do: debug(assigns, @debug, Mix.env) def debug(assigns, true, :dev) do ~L"""
    Brick : <%= raw( @tetromino |> inspect) %>
    Bottom: <%= raw( @bottom |> inspect) %>
    
""" #"

Debugging

" end def debug(assigns, _, _), do: "" end