defmodule table do@state_accept 0 #準備接入玩家
@state_ready 1 #開局準備?defdelegate [fetch(t, key), get_and_update(t, key, list)], to: map
defstruct [:config, :seats, :state]
defnew(config) do
%table,
state: @state_accept
}end
defis_full?(table) do
cur_count =enum.count(table.seats)
cur_count >=table.config.allow_count
enddefhas_player?(table, player_id) do
table.seats[player_id]
enddefcheck_in(table, player) do
update_in(table.seats, &(map.put(&1, player.base_info.id, player)))
enddefcheck_out(table, player_id) do
update_in(table.seats, &(map.delete(&1, player_id)))
endend
我們需要相關的配置table_config.txt
id, allow_count, base_gold, need_gold, descint, int, int, int, string
1, 4, 10, 480, 新手場
2, 4, 100, 4800, 中級場
3, 4, 1000, 48000, 高階場
這個txt可以由excel通過xslx2csv工具生成。然後我們利用table_config.txt 生成**配置table_config.ex.
我們當然可以在tableconfig裡經由excel檔案直接生成,那樣會更方便。
defmodule tableconfig domodule.register_attribute
__module__
, :column_names,
module.register_attribute
__module__
, :column_types,
module.register_attribute
__module__
, :config,
line_with_index = file.stream!(path.join([__dir__, "
table_config.txt
"]) , , :line)
|>stream.with_index
for <-line_with_index do
items = line |> string.split("
,") |> stream.map(&string.strip(&1))
case index do
0 ->@column_names items |> enum.map(&string.to_atom(&1))
1 ->@column_types items
|>stream.with_index
|> enum.map(fn -> end)
|>io.inspect
|> enum.into(%{})
_ ->new_items =items
|>stream.with_index
|> stream.map( &( typeconverter.convert(&1, @column_types) ) )
zip =enum.zip(@column_names, new_items)
@config enum.into(zip, %{})
io.inspect @config
# 以下函式花了我點時間,最後不得不通過模組屬性完成,我不知道有沒有其他方法
# 早期的版本是者這樣的
# config = enum.into(zip, %{})
# def get(unquote(config.id)) do
# unquote(config) # 這裡會報錯,百思不得其解,在errormsg裡我是這樣用的,沒有問題。不知2者區別在哪
# end
defget(unquote(@config.id)) do
@config
endend
endend
最後上點測試**table_test.exs
defmodule tabeltest douse exunit.case #
import pipehere
setup do
config = tableconfig.get(1)
table =table.new(config)
endtest
"table is full
", % do
new_table =
1..table.config.allow_count
|> stream.map(&player.new/1)
|> enum.reduce(table, fn p, acc ->table.check_in(acc, p) end)
assert new_table |>table.is_full?
endtest
"table has player
", % do
p1 = player.new(1)
p2 = player.new(2)
new_table =table.check_in(table, p1)
assert
table.has_player?(new_table, p1.base_info.id)
refute table.has_player?(table, p2.base_info.id)
endtest
"table check_in_and_out
", % do
p1 = player.new(1)
new_table =table.check_in(table, p1)
check_out_table =table.check_out(new_table, p1.base_info.id)
refute table.has_player?(check_out_table, p1.base_info.id)
endend
下一小節會從牌局開始吧,然後tableserver,然後讓它跑起來。
Elixir遊戲服設計五
現在想想也沒那麼難。保證原子性,無非就是需要某個單點去完成操作。那麼選擇玩家程序去做原子性工作就可以了。比如要重置某個任務,需要花費金幣和揹包裡某個物品,那麼大概的邏輯是這樣的。在玩家程序裡 def reset task task id do task.reset need with ok gold...
Elixir遊戲服設計一
在erlang遊戲服設計總結裡,我提到我想要的遊戲服設計方法,希望以應用做為基礎構建塊。最近我在學習elixir,它有很多 方便的語法糖以及很好用的庫,能夠解決我在遊戲中開發中碰到的很多繁瑣工作。因此我決定用它來做 練手,並期望下個專案中使用它。遊戲服的設計通常涉及如下東東 我將以乙個簡單的打牌遊戲...
簡單Elixir遊戲伺服器開篇
以前的elixir遊戲服設計系列種種原因沒有完成。後來雖然用elixir riak 完成了乙個麻將的初始版本,可惜公司也掛了。現在到新公司,比較空閒,想著像完成乙個心願一樣,還是重啟下吧 希望不要又爛尾 改頭換面叫簡單elixir遊戲伺服器系列。一些說明 0.沒怎麼寫過部落格,也懶得去研究了,說到哪...