From 1aeae75bc953e264962c4d9c826d2fe7f6c89acd Mon Sep 17 00:00:00 2001 From: Jeremy Pierre Date: Sun, 3 Mar 2013 19:17:38 -0800 Subject: [PATCH] Some documentation and cleanup of warnings. --- src/movement.erl | 10 ++++++++- src/player.erl | 6 ------ src/score_board.erl | 8 ++++++- src/space.erl | 49 ++++++++++++++++++++++++++++--------------- src/spacewar1_app.erl | 1 - src/test_handler.erl | 14 ------------- src/torps.erl | 10 +++++++-- src/ws_handler.erl | 6 +++--- 8 files changed, 59 insertions(+), 45 deletions(-) delete mode 100644 src/test_handler.erl diff --git a/src/movement.erl b/src/movement.erl index 1972231..a24089c 100644 --- a/src/movement.erl +++ b/src/movement.erl @@ -8,11 +8,19 @@ -include_lib("eunit/include/eunit.hrl"). -endif. +%%%---------------------------------------------------------------------- +%%% +%%% "movement" is one of the earliest modules in this project and it +%%% probably shows. Functions here assist in calculating vectors based +%%% on current player attitude, assist with upper bounds on vectors and +%%% simple 2x2 matrix addition. +%%% +%%%---------------------------------------------------------------------- + radians(Degrees) -> 3.14159 * Degrees / 180. degrees(Radians) -> - %Radians * 0.017453292519. Radians * 180 / 3.14159. startMatrix(X, Y) -> diff --git a/src/player.erl b/src/player.erl index adfb68f..1274397 100644 --- a/src/player.erl +++ b/src/player.erl @@ -48,15 +48,10 @@ player(Master, {X, Y, Heading}, Vector, UpdateVector, LiveTorps, Xsize, Ysize) - {{_, _}, {NvX, NvY}} = movement:addMatrix(Vector, movement:nextMatrix(scaled, Heading, 1, X, Y)), Vec = {{X, Y}, {NvX, NvY}}, gen_server:cast(play_space, {self(), X, Y, Heading, Vec}), - %player(Master, {X, Y, Heading}, {{X, Y}, - % {movement:clampVector(NvX), - % movement:clampVector(NvY)}}, done, LiveTorps, Xsize, Ysize); player(Master, {X, Y, Heading}, Vector, done, LiveTorps, Xsize, Ysize); torp when LiveTorps < 3 -> Torp = spawn(torps, torp, [self()]), TorpVec = movement:nextMatrix(torp, Heading, 8, X, Y), - % this is a gross way to place the torp, needs fixing - %Tv = movement:addMatrix(movement:addMatrix(movement:addMatrix(Vector, TorpVec), TorpVec), TorpVec), {Tx1, Ty1} = move(X, Y, TorpVec, 4), gen_server:cast(play_space, {torp, {Torp, Tx1, Ty1, 0, TorpVec}}), @@ -102,7 +97,6 @@ entity_struct(X, Y, Z) -> group_struct(Group) -> Compacted = [{X, Y, Z} || {_, X, Y, Z, _} <- Group], - %{struct, lists:map(fun({X, Y, Z}) -> entity_struct(X, Y, Z) end, Compacted)}. lists:map(fun({X, Y, Z}) -> entity_struct(X, Y, Z) end, Compacted). % used when a player is dead/inactive: diff --git a/src/score_board.erl b/src/score_board.erl index 58118cd..34b6c7d 100644 --- a/src/score_board.erl +++ b/src/score_board.erl @@ -3,6 +3,12 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, code_change/3, terminate/2]). -compile([{parse_transform, lager_transform}]). +%%%---------------------------------------------------------------------- +%%% +%%% "score_board" is just what the name suggests, in addition to being +%%% the central player registry. +%%% +%%%---------------------------------------------------------------------- init([]) -> {ok, []}. @@ -75,7 +81,7 @@ broadcast_score(State) -> attempt_join(WsPid, NewName, State) -> Existing = [N || {N, _, _} <- State, N =:= NewName], case Existing of - [H | T] when H == NewName -> + [H | _] when H == NewName -> {not_available, State}; _ -> NewPid = spawn(player, player, [WsPid, 500, 800]), diff --git a/src/space.erl b/src/space.erl index 52fd7c1..75c0d37 100644 --- a/src/space.erl +++ b/src/space.erl @@ -3,6 +3,14 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, code_change/3, terminate/2]). -compile([{parse_transform, lager_transform}]). +%%%---------------------------------------------------------------------- +%%% +%%% "space" module is where the core movement and collision logic all +%%% takes place. It is responsible for enforcing the basic game physics +%%% and ultimately governs combat/kill resolution. +%%% +%%%---------------------------------------------------------------------- + init([Xsize, Ysize]) -> timer:send_after(50, update), {ok, {Xsize, Ysize, [], []}}. @@ -15,7 +23,10 @@ handle_cast({dead_torp, Pid}, {Xsize, Ysize, Players, Torps}) -> {noreply, {Xsize, Ysize, Players, LiveTorps}}; handle_cast({dead, Pid}, {Xsize, Ysize, Players, Torps}) -> + % heavier logging here to track down phantom player bug + lager:info("space will remove pid ~w as dead, pre-filter player length is ~w", [Pid, length(Players)]), Filtered = [{P, XX, YY, ZZ, V} || {P, XX, YY, ZZ, V} <- Players, P /= Pid], + lager:info("post-filter player length is ~w", [length(Filtered)]), {noreply, {Xsize, Ysize, Filtered, Torps}}; handle_cast({Pid, X, Y, Z, Vec}, {Xsize, Ysize, Players, Torps}) -> @@ -61,12 +72,12 @@ handle_info(update, {Xsize, Ysize, Players, Torps}) -> code_change(PrevVersion, State, Extra) -> {ok, State}. -terminate(Reason, State) -> +terminate(Reason, _) -> ok. -%returns {moved and live players, players who collided with other players} +%% returns {moved and live players, players who collided with other players} moved_and_suicides(Players, Xsize, Ysize) -> - Move = fun({P, X, Y, Z, V}) -> move_entity(P, X, Y, Z, planet_influence(X, Y, V, 8, Xsize, Ysize), Xsize, Ysize) end, + Move = fun({P, X, Y, Z, V}) -> move_entity(P, X, Y, Z, planet_influence(X, Y, V, 8), Xsize, Ysize) end, MovedPlayers = lists:map(Move, Players), % now check collisions: @@ -76,25 +87,27 @@ moved_and_suicides(Players, Xsize, Ysize) -> NotSuicided = filter_dead(Suicided, MovedPlayers), {NotSuicided, Suicided}. +%% figures out which torpedoes are still live, which have hit players and planet, +%% which players have been killed. torping_and_torped(Torps, Players, Xsize, Ysize) -> - Move = fun({P, X, Y, Z, V}) -> move_entity(P, X, Y, Z, planet_influence(X, Y, V, 20, Xsize, Ysize), Xsize, Ysize) end, + Move = fun({P, X, Y, Z, V}) -> move_entity(P, X, Y, Z, planet_influence(X, Y, V, 20), Xsize, Ysize) end, MovedTorps = lists:map(Move, Torps), {Torped, HitTorps} = collisions(Players, MovedTorps, [], []), {StillTorping, PlanetTorps} = planet_impacts(20, filter_dead(HitTorps, MovedTorps), [], []), {StillTorping, HitTorps, PlanetTorps, Torped}. -% change an entities vector based on planetary gravity. -planet_influence(X, Y, Vec, Mass, SpaceW, SpaceH) -> +%% change an entities vector based on planetary gravity. +planet_influence(X, Y, Vec, Mass) -> Distance = math:sqrt((X * X) + (Y * Y)), PlanetEffect = ((Mass * 1) / (Distance * Distance)), {FullX, FullY} = {0 - X, 0 - Y}, PlanetVector = {{X, Y}, {PlanetEffect * FullX, PlanetEffect * FullY}}, movement:addMatrix(Vec, PlanetVector). -% takes a list of entities (ships/torps) and recursively checks to see which -% ones are OK and which ones hit the planet. -planet_impacts(PlanetSize, [], Ok, Dead) -> +%% takes a list of entities (ships/torps) and recursively checks to see which +%% ones are OK and which ones hit the planet. +planet_impacts(_, [], Ok, Dead) -> {Ok, Dead}; planet_impacts(PlanetSize, [Entity | Rest], Ok, Dead) -> case planet_impact(Entity, PlanetSize) of @@ -113,8 +126,8 @@ planet_impact(Entity, PSize) -> ok end. -% finds all ships involved in collisions, sub-optimal, runs in O(n^2) at best: -collisions([], Players, Dead, ToRemove) -> +%% finds all entities involved in collisions, sub-optimal, runs in O(n^2) at best: +collisions([], _, Dead, ToRemove) -> {Dead, ToRemove}; collisions([Ship | Rest], Players, Dead, ToRemove) -> NewDead = collision_check(Ship, [P || P <- Players, P /= Ship]), @@ -125,19 +138,19 @@ collisions([Ship | Rest], Players, Dead, ToRemove) -> collisions(Rest, Players, [Ship | Dead], [Remove | ToRemove]) end. -% checks an individual ship for collisions against the others: +%% checks an individual entity for collisions against the others: collision_check(Ship, Others) -> - {Pid, X, Y, _, _} = Ship, + {_, X, Y, _, _} = Ship, Hits = [{P, X2, Y2 ,Z2, V} || {P, X2, Y2, Z2, V} <- Others, abs(X - X2) =< 5, abs(Y - Y2) =< 5], case Hits of - [H | T] -> + [H | _] -> io:format("Impacting object ~w~n", [H]), {Ship, H}; _ -> {none, []} end. -% filters the list of dead players out of active ones +%% filters the list of dead entities out of active ones filter_dead([], Players) -> Players; filter_dead([FirstDead | Rest], Players) -> @@ -145,7 +158,7 @@ filter_dead([FirstDead | Rest], Players) -> Filtered = [{Pid, X, Y, Z, V} || {Pid, X, Y, Z, V} <- Players, Pid /= DeadPid], filter_dead(Rest, Filtered). -% recurses through player list to broadcast enemy locations: +%% recurses through player list to broadcast enemy and torpedo locations: msg_players([], _, _) -> []; msg_players([P | Rest], Players, Torps) -> @@ -155,11 +168,13 @@ msg_players([P | Rest], Players, Torps) -> Pid ! Msg, msg_players(Rest, Players, Torps). +%% moves an entity, obviously. Declared here to avoid anonymous functions +%% being constantly re-declared. move_entity(Pid, X, Y, Z, V, Xsize, Ysize) -> {X2, Y2} = movement:move({X, Y}, V), {Pid, valid_space(X2, Xsize), valid_space(Y2, Ysize), Z, V}. -% clamps space coordinates FIXME: magic numbers +%% clamps space coordinates, does wrap-around. valid_space(C, Size) -> case C of C when C >= (Size / 2) -> diff --git a/src/spacewar1_app.erl b/src/spacewar1_app.erl index 7e3b209..acdaade 100644 --- a/src/spacewar1_app.erl +++ b/src/spacewar1_app.erl @@ -12,7 +12,6 @@ start(_StartType, _StartArgs) -> Dispatch = cowboy_router:compile([ {'_', [ - {"/", test_handler, []}, {"/ws", ws_handler, []}, {"/[...]", cowboy_static, [ {directory, {priv_dir, spacewar1, []}}, diff --git a/src/test_handler.erl b/src/test_handler.erl deleted file mode 100644 index 5fa6734..0000000 --- a/src/test_handler.erl +++ /dev/null @@ -1,14 +0,0 @@ --module(test_handler). --behaviour(cowboy_http_handler). - --export([init/3, handle/2, terminate/3]). - -init({tcp, http}, Req, Opts) -> - {ok, Req, undefined_state}. - -handle(Req, State) -> - {ok, Req2} = cowboy_req:reply(200, [], <<"Hello World!">>, Req), - {ok, Req2, State}. - -terminate(Reason, Req, State) -> - ok. diff --git a/src/torps.erl b/src/torps.erl index de2068c..8aa7c40 100644 --- a/src/torps.erl +++ b/src/torps.erl @@ -1,6 +1,12 @@ -module(torps). -export([torp/1]). +%%%---------------------------------------------------------------------- +%%% +%%% Each live torpedo is tracked by an instance of this module/process. +%%% +%%%---------------------------------------------------------------------- + torp(Player) -> torp(Player, 100). @@ -17,12 +23,12 @@ torp(Player, TicksRemaining) -> io:format("Torp killed by space~n", []), torp(Player, 0); {hit, Player} -> - %% this is a suicide + %% if a player hits themself with their own torpedo, + %% it's considered a suicide. gen_server:cast(space_score, {Player, -1}), torp(Player, 0); {hit, WhoDidWeHit} -> io:format("Torp hit~n", []), - %whereis(space_score) ! {Player, 1}, gen_server:cast(space_score, {Player, 1}), torp(Player, 0); _ -> diff --git a/src/ws_handler.erl b/src/ws_handler.erl index a361856..a889489 100644 --- a/src/ws_handler.erl +++ b/src/ws_handler.erl @@ -26,19 +26,19 @@ websocket_handle({text, Msg}, Req, State) -> State ! {attitude, -1}; <<_, "1", _, _>> -> State ! {attitude, 1}; - _ -> 0 + _ -> Msg end, case Msg of <<_, _, "1", _>> -> State ! thrust; - _ -> 0 + _ -> Msg end, case Msg of <<_, _, _, "1">> -> State ! torp; - _ -> 0 + _ -> Msg end, {ok, Req, State};