-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
basic multiplayer engine -- pacmans moving on the grid -- mix compiles #2
Open
zampino
wants to merge
10
commits into
elixir-berlin:master
Choose a base branch
from
zampino:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
5ec822c
basic multiplayer engine -- pacmans moving on the grid -- mix compiles
zampino 04c99e0
update code to Elixir 0.12.2
zampino be8d3ca
refactor out shared events
zampino c0e13f5
adding JSON serializer for grid
zampino 54f1e72
engine keeps state of a list of outputs it streams the grid represent…
zampino ef99d62
cleanup
zampino 78f1722
mixed and tested with elixir v1.0.2
zampino 8795569
remove output and pacman implemented
zampino 26ea256
simplify code
zampino 889080e
README updated
zampino File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,5 @@ deps | |
*.beam | ||
*.plt | ||
erl_crash.dump | ||
_build | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,54 @@ | ||
require Pacman.SharedEvents # ? just the first is required to mix | ||
# require Pacman.Engine | ||
|
||
defmodule Pacman do | ||
@moduledoc """ | ||
|
||
## Pacman Module | ||
|
||
home of Pacmans. Works as parent process for | ||
the Engine and Shared Events. | ||
|
||
## Run | ||
|
||
$> iex -S mix | ||
|
||
## Usage | ||
|
||
Pacman.boot # starts the engine | ||
|
||
Pacman.turn :up # changes direction of (default) pacman | ||
|
||
Pacman.add :name # adds a player to the grid | ||
|
||
Pacman.turn :down, :name # changes direction of :name Pacman | ||
""" | ||
|
||
def boot do | ||
event_loop_pid = spawn_link(Pacman.SharedEvents, :events_loop, []) | ||
Process.register event_loop_pid, :events | ||
engine_pid = spawn_link(Pacman.Engine, :main, []) | ||
Process.register engine_pid, :engine | ||
add :default | ||
IO.puts "started" | ||
end | ||
|
||
def event(event) do | ||
:events <- {:queue_event, event} | ||
end | ||
|
||
def turn(direction, pacman // :default) do | ||
pacman <- {:turn, direction} | ||
end | ||
|
||
def add(name) do | ||
event [type: :register_pacman, name: name] | ||
end | ||
|
||
# NOTE: what happens to linked children if parent crashes/is killed? | ||
# could we just kill the parent? | ||
def exit do | ||
:engine <- :quit | ||
:events <- :quit | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
defmodule Pacman.Engine do | ||
|
||
@doc "the main animation loop changes states of the pacman's world" | ||
def main(world // Pacman.World.new) do | ||
catch_exit | ||
event = fetch_event | ||
IO.puts "received: #{inspect(event)}" | ||
world = react_on_event(world, event) | ||
world = Pacman.World.move_pacmans(world) | ||
# TODO: | ||
# world = World.eat_food(world) | ||
Pacman.World.represent(world) | ||
# NOTE: should be rather run on 24/frames sec | ||
:timer.sleep 200 | ||
main(world) | ||
end | ||
|
||
def catch_exit do | ||
receive do | ||
:quit -> Process.exit(self, :kill) | ||
after | ||
0 -> "no exit signal" | ||
end | ||
end | ||
|
||
@doc "this ensures we process just | ||
one shared event per cycle in a non-blocking fashion" | ||
def fetch_event do | ||
:events <- :pop_event | ||
receive do | ||
{:event, event} -> event | ||
after | ||
# NOTE: we could even use this as sleep time... | ||
0 -> nil | ||
end | ||
end | ||
|
||
@doc "changes the world's state based on incoming shared event" | ||
def react_on_event(world, [type: :register_pacman, name: name]) do | ||
Pacman.World.register_pacman(world, name) | ||
end | ||
|
||
def react_on_event(world, _) do | ||
world | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
defmodule Pacman.SharedEvents do | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not sure if we need this module, I just wanted to experiment "sharing states" ... |
||
|
||
# NOTE: not sure we want to rebuild a mailbox | ||
# might solve synchronization issues (?) | ||
|
||
def events_loop(events_queue // []) do | ||
receive do | ||
:quit -> Process.exit(self, :kill) | ||
|
||
{:queue_event, event} -> | ||
# NOTE: couldn't find better push for List | ||
events_queue = List.flatten(events_queue, [event]) | ||
events_loop(events_queue) | ||
|
||
:pop_event when length(events_queue) > 0 -> | ||
[event | rest] = events_queue | ||
:engine <- {:event, event} | ||
events_loop(rest) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
defmodule Pacman.UserEvents do | ||
|
||
# NOTE: maybe move data from the grid's pacmans to this state | ||
# there might be synchronization issues | ||
defrecord State, direction: :right | ||
|
||
def events_loop(name, state // State.new) do | ||
receive do | ||
:fetch_direction -> | ||
:engine <- {:new_direction, state.direction} | ||
events_loop name, state | ||
{:turn, direction} -> | ||
events_loop name, state.update(direction: direction) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
defmodule Pacman.World do | ||
@size 20 | ||
@directions [right: {1,0}, up: {0, -1}, left: {-1, 0}, down: {0, 1}] | ||
|
||
@moduledoc """ | ||
Keeps track of instant state of the Grid | ||
has two record definitions: | ||
Grid and Pacman. | ||
|
||
Grid#pacmans is a hash of :name => Pacman records | ||
|
||
Stores 'Class instance variables': | ||
|
||
- @size (of the grid) | ||
|
||
- @directions human -> vector translations | ||
|
||
### NOTE | ||
|
||
World should rather implement a protocol for the Grid | ||
in the sense of http://elixir-lang.org/getting_started/4.html | ||
or maybe something like @impl | ||
""" | ||
|
||
defrecord Grid, pacmans: HashDict.new, food: [], phantoms: [] | ||
defrecord Pacman, direction: {1,0}, position: {div(@size, 2), div(@size, 2)}, score: 0 | ||
|
||
def new do | ||
Grid.new | ||
end | ||
|
||
def spawn_user_events(name) do | ||
# FIXME: why do I need to namespace from root? | ||
pid = spawn_link(Elixir.Pacman.UserEvents, :events_loop, [name]) | ||
Process.register pid, name | ||
end | ||
|
||
@doc "register a new pacman user process under its name and updates the grid" | ||
def register_pacman(Grid[] = grid, name) do | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this could be abstracted to move also monsters in the grid.... |
||
pacmans = grid.pacmans | ||
pacmans = HashDict.put_new pacmans, name, Pacman.new | ||
spawn_user_events(name) | ||
grid.update(pacmans: pacmans) | ||
end | ||
|
||
def move_pacmans(Grid[] = grid) do | ||
grid.update_pacmans fn(pacmans) -> HashDict.new(Enum.map(pacmans, displace)) end | ||
end | ||
|
||
def displace do | ||
fn({name, pcm}) -> | ||
{dx, dy} = ask_direction(name, pcm.direction) | ||
{x, y} = pcm.position | ||
new_x = wrap_position(x, dx) | ||
new_y = wrap_position(y, dy) | ||
new_position = {new_x, new_y} | ||
new_pcm = pcm.update(position: new_position) | ||
{name, new_pcm} | ||
end | ||
end | ||
|
||
@doc "again a 'synchronous call' to ask the direction to the user's process which falls back to the old direction" | ||
def ask_direction(name, old_dir) do | ||
name <- :fetch_direction | ||
receive do | ||
{:new_direction, dir} -> translate_direction(dir) | ||
after | ||
0 -> | ||
IO.puts "missed!" | ||
old_dir | ||
end | ||
end | ||
|
||
def translate_direction(name) do | ||
@directions[name] | ||
end | ||
|
||
def wrap_position(value, delta) do | ||
rem(@size + value + delta, @size) | ||
end | ||
|
||
@doc "a Grid's instantaneous representation" | ||
def represent(Grid[] = grid) do | ||
represent_one = fn({name, pcm}) -> | ||
"#{name}: #{inspect(pcm.position)} -- score: #{pcm.score}" | ||
end | ||
IO.puts(Enum.map_join(grid.pacmans, "\n", represent_one)) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe discuss this next meetup...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zampino Definitely! Looks interesting.