dl-tetris 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +41 -0
- data/Rakefile +22 -0
- data/bin/boot.rb +10 -0
- data/bin/boot.rb~ +10 -0
- data/bin/tetris +2 -0
- data/bin/tetris~ +2 -0
- data/lib/tetris.rb +42 -0
- data/lib/tetris/core_ruby_ext.rb +5 -0
- data/lib/tetris/game.rb +79 -0
- data/lib/tetris/map.rb +68 -0
- data/lib/tetris/piece.rb +82 -0
- data/test/game_test.rb +7 -0
- data/test/test_helper.rb +21 -0
- metadata +109 -0
data/README.markdown
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
Dave and Luke's Tetris clone
|
2
|
+
----------------------------
|
3
|
+
|
4
|
+
A quick little tetris clone written in Ruby. It uses the [rubygame](http://rubygame.org/) library and was originally based from [this great template](http://rubygame.org/wiki/Generic_Game_Template).
|
5
|
+
|
6
|
+
It was started by Dave to practice Ruby and Luke has since seperated it out and turned it into a 'proper' project.
|
7
|
+
|
8
|
+
Arrow keys move, up arrow rotates and space drops your piece.
|
9
|
+
|
10
|
+

|
11
|
+
|
12
|
+
Notes
|
13
|
+
-----
|
14
|
+
|
15
|
+
- If you're using a Mac you will need to run this with [RSDL](https://github.com/knu/rsdl) instead of the normal Ruby command.
|
16
|
+
- If you're not using a Mac you will need to change the font path.
|
17
|
+
- You will need to install libsdl, sdl_gfx, sdl_ttf, rubygame, rsdl (see above) and Ruby 1.9 for this to work properly.
|
18
|
+
|
19
|
+
Todo
|
20
|
+
----
|
21
|
+
|
22
|
+
- Music!
|
23
|
+
- End game logic
|
24
|
+
- Special effects?!
|
25
|
+
- [XKCD setting?!](http://xkcd.com/724/)
|
26
|
+
|
27
|
+
Licence
|
28
|
+
-------
|
29
|
+
|
30
|
+
Copyright Dave Barker and Luke Antins 2010
|
31
|
+
|
32
|
+
This program is free software: you can redistribute it and/or modify
|
33
|
+
it under the terms of the GNU General Public License as published by
|
34
|
+
the Free Software Foundation, either version 3 of the License, or
|
35
|
+
(at your option) any later version.
|
36
|
+
This program is distributed in the hope that it will be useful,
|
37
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
38
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
39
|
+
GNU General Public License for more details.
|
40
|
+
You should have received a copy of the GNU General Public License
|
41
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'yard'
|
4
|
+
require 'yard/rake/yardoc_task'
|
5
|
+
|
6
|
+
task :default => :'test'
|
7
|
+
|
8
|
+
# Testing
|
9
|
+
desc 'Run tests'
|
10
|
+
Rake::TestTask.new(:test) do |task|
|
11
|
+
task.test_files = FileList['test/**/*_test.rb']
|
12
|
+
task.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
##
|
16
|
+
# docs task.
|
17
|
+
desc 'Build documentation.'
|
18
|
+
YARD::Rake::YardocTask.new :yardoc do |t|
|
19
|
+
t.files = ['lib/**/*.rb']
|
20
|
+
t.options = ['--output-dir', "doc/",
|
21
|
+
'--title', 'Dave and Luke\'s Tetris Clone - API Documentation']
|
22
|
+
end
|
data/bin/boot.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# hack the path.
|
2
|
+
$CURRENT_DIR = File.dirname(File.expand_path(__FILE__))
|
3
|
+
$LOAD_PATH.unshift $CURRENT_DIR + '/../lib'
|
4
|
+
|
5
|
+
# lets roll.
|
6
|
+
require 'tetris'
|
7
|
+
|
8
|
+
# init the game, and run the main game loop.
|
9
|
+
game = Game.new(10, 20, 1000, "/Library/Fonts/Chalkduster.ttf")
|
10
|
+
game.run
|
data/bin/boot.rb~
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# hack the path.
|
2
|
+
$CURRENT_DIR = File.dirname(File.expand_path(__FILE__))
|
3
|
+
$LOAD_PATH.unshift $CURRENT_DIR + '/../lib'
|
4
|
+
|
5
|
+
# lets roll.
|
6
|
+
require 'tetris'
|
7
|
+
|
8
|
+
# init the game, and run the main game loop.
|
9
|
+
game = Game.new(10, 20, 1000, "/Library/Fonts/Chalkduster.ttf")
|
10
|
+
game.run
|
data/bin/tetris
ADDED
data/bin/tetris~
ADDED
data/lib/tetris.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# Dave's Tetris clone, Dave Barker 2010
|
2
|
+
#
|
3
|
+
# (Requires rubygame, rsdl, sdl, sdl_graphics, sdl_ttf and ruby >= 1.9)
|
4
|
+
# (Make sure you put Chalkduster.ttf if working directory)
|
5
|
+
#
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
#
|
17
|
+
# Code was started from this great rubygame template:
|
18
|
+
# http://rubygame.org/wiki/Generic_Game_Template
|
19
|
+
|
20
|
+
require 'rubygame'
|
21
|
+
|
22
|
+
require 'tetris/core_ruby_ext'
|
23
|
+
require 'tetris/game'
|
24
|
+
require 'tetris/map'
|
25
|
+
require 'tetris/piece'
|
26
|
+
|
27
|
+
$TileSize = 20
|
28
|
+
$Colours = [:blue, :red, :pink, :green, :cyan, :purple, :yellow]
|
29
|
+
|
30
|
+
$Pieces = [[" , # , # , ## ",
|
31
|
+
" , , # , ###",
|
32
|
+
" , ## , # , # ",
|
33
|
+
" , , ###, #"],
|
34
|
+
[" , ## , ## , "],
|
35
|
+
[" , ,####, ",
|
36
|
+
" # , # , # , # "],
|
37
|
+
[" , ##, ## , ",
|
38
|
+
" , # , ## , # "],
|
39
|
+
[" , # , ###, ",
|
40
|
+
" , # , ##, # ",
|
41
|
+
" , , ###, # ",
|
42
|
+
" , # , ## , # "]]
|
data/lib/tetris/game.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
class Game
|
2
|
+
def initialize(w, h, speed, font_file)
|
3
|
+
# Setup rubygame stuff
|
4
|
+
@screen = Rubygame::Screen.new([w * $TileSize, h * $TileSize], 0,
|
5
|
+
[Rubygame::HWSURFACE, Rubygame::DOUBLEBUF])
|
6
|
+
@queue = Rubygame::EventQueue.new
|
7
|
+
@clock = Rubygame::Clock.new
|
8
|
+
@clock.target_framerate = 30
|
9
|
+
Rubygame::TTF.setup
|
10
|
+
@ttf = Rubygame::TTF.new(font_file, 20)
|
11
|
+
|
12
|
+
# Setup the game of tetris
|
13
|
+
@screen.title = "Tetris"
|
14
|
+
@map = Map.new(w, h)
|
15
|
+
@piece = Piece.new
|
16
|
+
@background = :white
|
17
|
+
@speed = speed
|
18
|
+
@step = 0
|
19
|
+
@score = 0
|
20
|
+
end
|
21
|
+
|
22
|
+
def run
|
23
|
+
loop do
|
24
|
+
update(@clock.tick)
|
25
|
+
draw
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def update(time_delta)
|
30
|
+
# Process the event queue
|
31
|
+
@queue.each do |ev|
|
32
|
+
case ev
|
33
|
+
when Rubygame::KeyDownEvent
|
34
|
+
case(ev.key)
|
35
|
+
when Rubygame::K_LEFT
|
36
|
+
@piece.move(-1, 0, @map)
|
37
|
+
when Rubygame::K_RIGHT
|
38
|
+
@piece.move(1, 0, @map)
|
39
|
+
when Rubygame::K_DOWN
|
40
|
+
@piece.move(0, 1, @map)
|
41
|
+
when Rubygame::K_UP
|
42
|
+
@piece.rotate(@map)
|
43
|
+
when Rubygame::K_SPACE
|
44
|
+
@piece.drop(@map)
|
45
|
+
end
|
46
|
+
when Rubygame::QuitEvent
|
47
|
+
Rubygame.quit
|
48
|
+
exit
|
49
|
+
end
|
50
|
+
end
|
51
|
+
# Update the game state
|
52
|
+
@step += time_delta
|
53
|
+
if @step > @speed
|
54
|
+
@step -= @speed
|
55
|
+
@piece.move(0, 1, @map)
|
56
|
+
end
|
57
|
+
@piece.update(@map) {|x, y, colour| @map.set(x, y, colour)}
|
58
|
+
@score += @map.update
|
59
|
+
end
|
60
|
+
|
61
|
+
def draw_square(x, y, colour, border=true)
|
62
|
+
# Setup the points for SDL
|
63
|
+
x_pos = x * $TileSize
|
64
|
+
y_pos = y * $TileSize
|
65
|
+
pt1 = [x_pos, y_pos]
|
66
|
+
pt2 = [x_pos + $TileSize, y_pos + $TileSize]
|
67
|
+
# Draw the square and then the border
|
68
|
+
@screen.draw_box_s(pt1, pt2, colour)
|
69
|
+
@screen.draw_box(pt1, pt2, :black) if border
|
70
|
+
end
|
71
|
+
|
72
|
+
def draw
|
73
|
+
@screen.fill(@background)
|
74
|
+
@piece.squares {|x, y, colour| draw_square(x, y, colour)}
|
75
|
+
@map.draw {|coords, colour| draw_square(coords[0], coords[1], colour)}
|
76
|
+
@ttf.render("Score: " + @score.to_s, true, :black).blit(@screen, [0,0])
|
77
|
+
@screen.flip
|
78
|
+
end
|
79
|
+
end
|
data/lib/tetris/map.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
class Map
|
2
|
+
def initialize(w, h)
|
3
|
+
@w = w
|
4
|
+
@h = h
|
5
|
+
@tiles = Array.new(w, nil)
|
6
|
+
end
|
7
|
+
|
8
|
+
def clear(x, y, w, h)
|
9
|
+
(x..(x + w)).each do |x|
|
10
|
+
(y..(y + h)).each do |y|
|
11
|
+
set(x, y, nil)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def set(x, y, colour)
|
17
|
+
@tiles[pos(x,y)] = colour
|
18
|
+
end
|
19
|
+
|
20
|
+
def draw
|
21
|
+
@tiles.each_with_index do |colour, p|
|
22
|
+
yield(coords(p), colour) if colour
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def free?(x, y)
|
27
|
+
x >= 0 and x < @w and y >= 0 and y < @h and not @tiles[pos(x,y)]
|
28
|
+
end
|
29
|
+
|
30
|
+
def update
|
31
|
+
points = 0
|
32
|
+
shift_lines! do |line|
|
33
|
+
# Enumerable should have an every? method
|
34
|
+
if not line.each.any? {|tile| not tile} then
|
35
|
+
points += 1
|
36
|
+
true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
points
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def coords(p)
|
45
|
+
[p % @w, p / @w]
|
46
|
+
end
|
47
|
+
|
48
|
+
def pos(x, y)
|
49
|
+
x + y * @w
|
50
|
+
end
|
51
|
+
|
52
|
+
def shift_lines!
|
53
|
+
(0..@h).each do |y|
|
54
|
+
row = (0..@w-1).collect {|x| @tiles[pos(x,y-1)] }
|
55
|
+
shift_line(y-1, 1) if yield row
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def shift_line(y, distance)
|
60
|
+
if y < 1 then
|
61
|
+
@tiles[pos(0,y + distance)..pos(@w-1,y + distance)] = [nil] * @w
|
62
|
+
else
|
63
|
+
@tiles[pos(0,y)..pos(@w-1,y)] =
|
64
|
+
@tiles[pos(0,y-distance)..pos(@w-1,y-distance)]
|
65
|
+
shift_line(y-1, distance)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/tetris/piece.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
class Piece
|
2
|
+
@@type_width = 4
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@@types ||= load_pieces($Pieces)
|
6
|
+
|
7
|
+
@type = @@types.rand_item
|
8
|
+
@rotation = 0
|
9
|
+
@x = 0
|
10
|
+
@y = 0
|
11
|
+
@colour = $Colours.rand_item
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse_piece_string(s)
|
15
|
+
s.chars.each_with_object([]) do |c, result|
|
16
|
+
case c
|
17
|
+
when " " then result << false
|
18
|
+
when "," then next
|
19
|
+
else result << true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def load_pieces(pieces)
|
25
|
+
pieces.collect do |piece|
|
26
|
+
piece.collect {|rotation| parse_piece_string rotation}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def squares(piece=current)
|
31
|
+
result = []
|
32
|
+
piece.each_with_index do |tile, i|
|
33
|
+
x, y = coords(i)
|
34
|
+
result << yield(@x+x, @y+y, @colour) if tile
|
35
|
+
end
|
36
|
+
return result
|
37
|
+
end
|
38
|
+
|
39
|
+
def move(x, y, map)
|
40
|
+
unless collision?(map, x, y)
|
41
|
+
@x += x
|
42
|
+
@y += y
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def drop(map)
|
47
|
+
@y += 1 while not collision?(map, 0, 1)
|
48
|
+
end
|
49
|
+
|
50
|
+
def rotate(map)
|
51
|
+
@rotation = next_rotation unless collision?(map, 0, 0, @type[next_rotation])
|
52
|
+
end
|
53
|
+
|
54
|
+
def update(map)
|
55
|
+
if collision?(map, 0, 1)
|
56
|
+
squares {|x, y, colour| map.set(x, y, colour)}
|
57
|
+
initialize
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def current
|
64
|
+
@type[@rotation]
|
65
|
+
end
|
66
|
+
|
67
|
+
def next_rotation
|
68
|
+
if @rotation > @type.count - 2
|
69
|
+
return 0
|
70
|
+
else
|
71
|
+
return @rotation + 1
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def coords(p)
|
76
|
+
[p % @@type_width, p / @@type_width]
|
77
|
+
end
|
78
|
+
|
79
|
+
def collision?(map, x_offset, y_offset, piece=current)
|
80
|
+
squares(piece) {|x, y, c| not map.free?(x + x_offset, y + y_offset)}.any?
|
81
|
+
end
|
82
|
+
end
|
data/test/game_test.rb
ADDED
data/test/test_helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
|
3
|
+
# code coverage, this must be first!
|
4
|
+
SimpleCov.start do
|
5
|
+
add_filter '/test/'
|
6
|
+
end
|
7
|
+
|
8
|
+
$TEST_DIR = File.dirname(File.expand_path(__FILE__))
|
9
|
+
$LOAD_PATH.unshift $TEST_DIR + '/../lib'
|
10
|
+
$TESTING = true
|
11
|
+
|
12
|
+
require 'test/unit'
|
13
|
+
require 'rake'
|
14
|
+
require 'turn'
|
15
|
+
require 'rr'
|
16
|
+
|
17
|
+
require 'tetris'
|
18
|
+
|
19
|
+
class Test::Unit::TestCase
|
20
|
+
include RR::Adapters::TestUnit
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dl-tetris
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Dave Barker
|
13
|
+
- Luke Antins
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-12-21 00:00:00 +00:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rsdl
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
- 1
|
32
|
+
- 4
|
33
|
+
version: 0.1.4
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rubygame
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
segments:
|
45
|
+
- 2
|
46
|
+
- 6
|
47
|
+
- 4
|
48
|
+
version: 2.6.4
|
49
|
+
type: :runtime
|
50
|
+
version_requirements: *id002
|
51
|
+
description: Simple tetris clone written using the rubygame library. Arrow keys to move, up arrow to rotate. Space drops your piece to the ground.
|
52
|
+
email:
|
53
|
+
- kzar@kzar.co.uk
|
54
|
+
executables:
|
55
|
+
- tetris
|
56
|
+
extensions: []
|
57
|
+
|
58
|
+
extra_rdoc_files: []
|
59
|
+
|
60
|
+
files:
|
61
|
+
- bin/boot.rb
|
62
|
+
- bin/boot.rb~
|
63
|
+
- bin/tetris
|
64
|
+
- bin/tetris~
|
65
|
+
- lib/tetris/core_ruby_ext.rb
|
66
|
+
- lib/tetris/game.rb
|
67
|
+
- lib/tetris/map.rb
|
68
|
+
- lib/tetris/piece.rb
|
69
|
+
- lib/tetris.rb
|
70
|
+
- test/game_test.rb
|
71
|
+
- test/test_helper.rb
|
72
|
+
- README.markdown
|
73
|
+
- Rakefile
|
74
|
+
has_rdoc: true
|
75
|
+
homepage: https://github.com/lantins/tetris
|
76
|
+
licenses: []
|
77
|
+
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
segments:
|
89
|
+
- 0
|
90
|
+
version: "0"
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
none: false
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
segments:
|
97
|
+
- 1
|
98
|
+
- 3
|
99
|
+
- 7
|
100
|
+
version: 1.3.7
|
101
|
+
requirements: []
|
102
|
+
|
103
|
+
rubyforge_project:
|
104
|
+
rubygems_version: 1.3.7
|
105
|
+
signing_key:
|
106
|
+
specification_version: 3
|
107
|
+
summary: Simple tetris clone written using the rubygame library
|
108
|
+
test_files: []
|
109
|
+
|