Building a Ruby/DHTML Turn Based Strategy Game... in 20 minutes
Topher Cyll
FOSCON II
Okay
Who plays video games?
Okay
Who plays turn based strategy?
Today
Ruby Backend
|
TBS Tuples
|
DHTML Frontend
Tomorrow
Ruby Backend
|
TBS Tuples
|
Native Frontend...?
TBS Tuples
(Message "hello, there!")
TBS Tuples
(Message "hello, there!")
(Choose (Unit 0 0)
(Unit 3 4)
(Done))
TBS Tuples
(Message "hello, there!")
(Choose (Unit 0 0)
(Unit 3 4)
(Done))
(Draw ((Forest Water ...)
(Forest ...))
((Ninja, nil...)
(...)))
JSON TBS Tuples
["Message", "hello, there!"]
JSON TBS Tuples
["Message", "hello, there!"]
["Choose", ["Unit", 0, 0],
["Unit", 3, 4],
["Done"]]
JSON TBS Tuples
["Message", "hello, there!"]
["Choose", ["Unit", 0, 0],
["Unit", 3, 4],
["Done"]]
["Draw", [["Forest", "Water"...],
["Forest" ...]],
[["Ninja", null...]
[...]]]
MIT License
Freely available
Getting Started
# Available at
# http://cyll.org/tbs.shtml
require_gem 'tbs'
First Working Version
class CowboyBattle < TBS::Game
@@name = "Cowboy Battle"
end
First Working Version
def turn(player)
player.new_turn
end
First Working Version
def turn(player)
player.new_turn
draw_all()
end
First Working Version
def turn(player)
player.new_turn
draw_all()
# This next line is *barely* legal
player.choose([["Nevermind"]]) do
end
end
First Working Version
map = TBS::Map.new terrain_key, <<-END
gggppppppp
ggppggwtpt
ggpgggwwtt
END
First Working Version
map = TBS::Map.new terrain_key, <<-END
gggppppppp
ggppggwtpt
ggpgggwwtt
END
game.add_map(map)
First Working Version
terrain_key = {
"p" => TBS::Plains.new,
"g" => TBS::Grass.new,
"w" => TBS::Water.new,
"t" => TBS::Town.new,
}
First Working Version
human = TBS::Players::DHTML.new("cowboy", "Topher")
First Working Version
human = TBS::Players::DHTML.new("cowboy", "Topher")
game = CowboyBattle.new
game.add_player human
First Working Version
TBS::Spawner.new(2002) do
# ...
Thread.new{ game.run }
human.method(:callback)
end.run
What's missing?
Now what?
Adding Units
class Unit < TBS::Unit
end
Adding Units
class Captain < Unit
def initialize(*args)
super(*args)
@hp = 10
@move = 1
@actions.push TBS::Attack
end
end
Adding Units
stanley = Captain.new(human, "Stanley")
Adding Units
stanley = Captain.new(human, "Stanley")
map.place(0, 0, stanley)
What's missing?
Now what?
Moving Units
choices = player.not_done_unit_choices
player.choose_all_or_done(choices) do |choice|
break if choice == TBS::DONE
unit = choice.call
Moving Units
player.choose(unit.move_choices) do |move|
move.call
end
unit.done
What's missing?
Now what?
Attacking
computer = TBS::Players::DumbComputer.new("Computer")
game.add_player computer
Attacking
class EvilCaptain < Captain
end
Attacking
evilcaptain = EvilCaptain.new(computer, "EvilTwin")
map.place(0, 2, evilcaptain)
Attacking
choices = unit.action_choices
player.choose(choices) do |action|
action.call
end
unit.done
HTML
Slots
Mochikit
Extendable
Javascript
<script src="core.js"></script>
<script src="draw.js"></script>
<script src="choices.js"></script>
<!-- Your scripts go here -->
<script src="eventloop.js"></script>
Javascript
choiceRegistry.Move = function(x, y) {
highlight(terrainid(x, y));
$(terrainid(x, y)).onclick = function() {
reply(repr(["Move", x, y]));
};
};
CSS
.Grass {
background-color: #006633;
}
CSS
.Town {
background-color: #CDAA7D;
background-image: url("images/house.png");
}
CSS
.Captain {
background-image: url("images/captain.png");
}
Your Turn
$ wget http://cyll.org/tbs-0.1.gem
Your Turn
$ wget http://cyll.org/tbs-0.1.gem
$ sudo gem install tbs
Your Turn
$ wget http://cyll.org/tbs-0.1.gem
$ sudo gem install tbs
$ wget http://cyll.org/cowboy.tar.gz
Your Turn
$ wget http://cyll.org/tbs-0.1.gem
$ sudo gem install tbs
$ wget http://cyll.org/cowboy.tar.gz
$ tar zxvf cowboy.tar.gz