graphics 1.0.0b1
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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.autotest +26 -0
- data/.gemtest +0 -0
- data/History.rdoc +12 -0
- data/Manifest.txt +37 -0
- data/README.rdoc +71 -0
- data/Rakefile +26 -0
- data/examples/boid.rb +653 -0
- data/examples/bounce.rb +86 -0
- data/examples/collision.rb +74 -0
- data/examples/demo.rb +90 -0
- data/examples/editor.rb +70 -0
- data/examples/fluid.rb +246 -0
- data/examples/fluid2.rb +199 -0
- data/examples/lito.rb +108 -0
- data/examples/lito2.rb +110 -0
- data/examples/logo.rb +73 -0
- data/examples/math.rb +42 -0
- data/examples/radar.rb +31 -0
- data/examples/tank.rb +160 -0
- data/examples/tank2.rb +173 -0
- data/examples/targeting.rb +46 -0
- data/examples/vants.rb +69 -0
- data/examples/walker.rb +116 -0
- data/examples/zenspider1.rb +93 -0
- data/examples/zenspider2.rb +123 -0
- data/examples/zenspider3.rb +104 -0
- data/examples/zenspider4.rb +90 -0
- data/examples/zombies.rb +385 -0
- data/lib/graphics.rb +9 -0
- data/lib/graphics/body.rb +216 -0
- data/lib/graphics/extensions.rb +48 -0
- data/lib/graphics/simulation.rb +377 -0
- data/lib/graphics/trail.rb +69 -0
- data/lib/graphics/v.rb +71 -0
- data/resources/images/body.png +0 -0
- data/resources/images/turret.png +0 -0
- data/rubysdl_setup.sh +34 -0
- data/test/test_graphics.rb +408 -0
- metadata +191 -0
- metadata.gz.sig +2 -0
data/examples/vants.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
srand 42
|
5
|
+
|
6
|
+
require "graphics"
|
7
|
+
|
8
|
+
##
|
9
|
+
# Virtual Ants -- inspired by a model in NetLogo.
|
10
|
+
|
11
|
+
class Vant < Graphics::Body
|
12
|
+
COUNT = 100
|
13
|
+
M = 1
|
14
|
+
|
15
|
+
attr_accessor :white, :black, :red, :s
|
16
|
+
|
17
|
+
def initialize w
|
18
|
+
super
|
19
|
+
self.a = random_angle
|
20
|
+
self.s = w.screen
|
21
|
+
|
22
|
+
self.white = w.color[:white]
|
23
|
+
self.black = w.color[:black]
|
24
|
+
end
|
25
|
+
|
26
|
+
def forward
|
27
|
+
move_by a, M
|
28
|
+
mutate
|
29
|
+
end
|
30
|
+
|
31
|
+
def mutate
|
32
|
+
if s[x, y] == white then
|
33
|
+
s[x, y] = black
|
34
|
+
turn 270
|
35
|
+
else
|
36
|
+
s[x, y] = white
|
37
|
+
turn 90
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class Vants < Graphics::Simulation
|
43
|
+
attr_accessor :vs
|
44
|
+
|
45
|
+
def initialize
|
46
|
+
super 850, 850, 16, self.class.name
|
47
|
+
|
48
|
+
# cheat and reopen screen w/o double buffering
|
49
|
+
self.screen = SDL::Screen.open 850, 850, 16, SDL::HWSURFACE
|
50
|
+
clear :white
|
51
|
+
|
52
|
+
self.vs = populate Vant
|
53
|
+
end
|
54
|
+
|
55
|
+
def update n
|
56
|
+
vs.each(&:forward)
|
57
|
+
end
|
58
|
+
|
59
|
+
def draw_and_flip n
|
60
|
+
self.draw n
|
61
|
+
# no flip
|
62
|
+
end
|
63
|
+
|
64
|
+
def draw n
|
65
|
+
screen.update_rect 0, 0, 0, 0
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
Vants.new.run if $0 == __FILE__
|
data/examples/walker.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
require "graphics"
|
4
|
+
require "graphics/trail"
|
5
|
+
|
6
|
+
class Person < Graphics::Body
|
7
|
+
COUNT = 40
|
8
|
+
|
9
|
+
D_A = 5.0
|
10
|
+
D_M = 0.25
|
11
|
+
M_M = 5.0
|
12
|
+
|
13
|
+
AA = SDL::Surface::TRANSFORM_AA
|
14
|
+
|
15
|
+
attr_accessor :trail, :attack
|
16
|
+
|
17
|
+
def initialize w
|
18
|
+
super
|
19
|
+
|
20
|
+
self.trail = Graphics::Trail.new w, 100, :green
|
21
|
+
|
22
|
+
self.a = random_angle
|
23
|
+
self.ga = random_angle
|
24
|
+
self.attack = false
|
25
|
+
end
|
26
|
+
|
27
|
+
def update
|
28
|
+
turn_towards_goal
|
29
|
+
possibly_change_goal
|
30
|
+
|
31
|
+
accelerate
|
32
|
+
move
|
33
|
+
|
34
|
+
trail << self
|
35
|
+
|
36
|
+
clip_off_wall
|
37
|
+
end
|
38
|
+
|
39
|
+
def accelerate
|
40
|
+
self.m += D_M unless m >= M_M
|
41
|
+
end
|
42
|
+
|
43
|
+
def draw
|
44
|
+
trail.draw
|
45
|
+
|
46
|
+
if attack then
|
47
|
+
w.angle x, y, a-45, 50, :yellow
|
48
|
+
w.angle x, y, a, 60, :red
|
49
|
+
w.angle x, y, a+45, 50, :yellow
|
50
|
+
end
|
51
|
+
|
52
|
+
w.angle x, y, ga, 60, :red
|
53
|
+
|
54
|
+
# the blit looks HORRIBLE when rotated... dunno why
|
55
|
+
w.blit w.body_img, x, y, 0, AA
|
56
|
+
end
|
57
|
+
|
58
|
+
def turn_towards_goal
|
59
|
+
turn a.relative_angle(ga, D_A)
|
60
|
+
end
|
61
|
+
|
62
|
+
def change_goal
|
63
|
+
self.ga = a + random_turn(180)
|
64
|
+
end
|
65
|
+
|
66
|
+
def possibly_change_goal
|
67
|
+
change_goal if ga.close_to?(a) && 1 =~ 25
|
68
|
+
end
|
69
|
+
|
70
|
+
def collide_with? other
|
71
|
+
w.cmap.collision_check(x, y, w.cmap, other.x, other.y) != nil
|
72
|
+
end
|
73
|
+
|
74
|
+
def collide
|
75
|
+
self.a = (a + 180).degrees
|
76
|
+
change_goal
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class WalkerSimulation < Graphics::Simulation
|
81
|
+
attr_accessor :ps, :body_img, :cmap
|
82
|
+
|
83
|
+
def initialize
|
84
|
+
super 850, 850, 16, "Walker"
|
85
|
+
|
86
|
+
self.ps = populate Person
|
87
|
+
|
88
|
+
self.body_img = sprite 20, 20 do
|
89
|
+
circle 10, 10, 5, :white, :filled
|
90
|
+
end
|
91
|
+
|
92
|
+
self.cmap = body_img.make_collision_map
|
93
|
+
end
|
94
|
+
|
95
|
+
def update n
|
96
|
+
ps.each(&:update)
|
97
|
+
detect_collisions(ps).each(&:collide)
|
98
|
+
end
|
99
|
+
|
100
|
+
def draw n
|
101
|
+
clear
|
102
|
+
|
103
|
+
ps.each(&:draw)
|
104
|
+
fps n
|
105
|
+
end
|
106
|
+
|
107
|
+
def detect_collisions sprites
|
108
|
+
collisions = []
|
109
|
+
sprites.combination(2).each do |a, b|
|
110
|
+
collisions << a << b if a.collide_with? b
|
111
|
+
end
|
112
|
+
collisions.uniq
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
WalkerSimulation.new.run
|
@@ -0,0 +1,93 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
|
3
|
+
srand 42
|
4
|
+
|
5
|
+
class GameOfLife
|
6
|
+
attr_accessor :cells
|
7
|
+
attr_accessor :cache
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
self.cells = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def randomize n, m
|
14
|
+
dimensions = n.times.to_a
|
15
|
+
cells.replace dimensions.product(dimensions).sample(m).sort
|
16
|
+
end
|
17
|
+
|
18
|
+
def run max = 1.0 / 0
|
19
|
+
(1..max).each do |n|
|
20
|
+
yield n
|
21
|
+
update
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def update
|
26
|
+
cells.replace considered.select { |(x, y)| alive? x, y }.sort
|
27
|
+
end
|
28
|
+
|
29
|
+
def considered
|
30
|
+
cells.map { |(x, y)| neighbors_for(x, y) }.flatten(1).uniq
|
31
|
+
end
|
32
|
+
|
33
|
+
MIN = { true => 2, false => 3 }
|
34
|
+
|
35
|
+
def alive? x, y
|
36
|
+
count = (neighbors_for(x, y) & cells).size
|
37
|
+
min = MIN[cells.include? [x, y]]
|
38
|
+
count.between? min, 3
|
39
|
+
end
|
40
|
+
|
41
|
+
delta = [-1, 0, 1]
|
42
|
+
same = [0, 0]
|
43
|
+
DELTAS = (delta.product(delta) - [same])
|
44
|
+
|
45
|
+
@@neighbors = Hash.new { |h, k| h[k] = {} }
|
46
|
+
|
47
|
+
def neighbors_for x, y
|
48
|
+
DELTAS.map { |(dx, dy)| [x+dx, y+dy] }.reject { |(m, n)| m < 0 || n < 0 }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
size, width, count = 20, 32, 512
|
53
|
+
|
54
|
+
gol = GameOfLife.new
|
55
|
+
gol.randomize width, count
|
56
|
+
|
57
|
+
if ARGV.first == "prof" then
|
58
|
+
gol.run 50 do |n|
|
59
|
+
$stderr.print "."
|
60
|
+
end
|
61
|
+
warn "done"
|
62
|
+
else
|
63
|
+
require "sdl"
|
64
|
+
|
65
|
+
SDL.init SDL::INIT_VIDEO
|
66
|
+
SDL::WM::set_caption "Conway's Game of Life", "Conway's Game of Life"
|
67
|
+
|
68
|
+
screen = SDL::Screen.open 640, 640, 16, SDL::DOUBLEBUF
|
69
|
+
|
70
|
+
black = screen.format.map_rgb 0, 0, 0
|
71
|
+
white = screen.format.map_rgb 255, 255, 255
|
72
|
+
|
73
|
+
w, h = screen.w, screen.h
|
74
|
+
|
75
|
+
gol.run do
|
76
|
+
screen.fill_rect 0, 0, w, h, black
|
77
|
+
|
78
|
+
gol.cells.each do |(x, y)|
|
79
|
+
screen.fill_rect x*size, y*size, size-1, size-1, white
|
80
|
+
end
|
81
|
+
|
82
|
+
screen.flip
|
83
|
+
|
84
|
+
while event = SDL::Event.poll
|
85
|
+
case event
|
86
|
+
when SDL::Event::KeyDown, SDL::Event::Quit
|
87
|
+
exit
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
gol.update
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
|
3
|
+
srand 42
|
4
|
+
|
5
|
+
class Array
|
6
|
+
include Comparable
|
7
|
+
|
8
|
+
alias old_spaceship <=>
|
9
|
+
|
10
|
+
def <=> other
|
11
|
+
x = first <=> other.first
|
12
|
+
x.zero? ? self[1] <=> other[1] : x
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class GameOfLife
|
17
|
+
delta = [-1, 0, 1]
|
18
|
+
same = [0, 0]
|
19
|
+
|
20
|
+
DELTAS = (delta.product(delta) - [same]).sort
|
21
|
+
MIN = { true => 2, false => 3 }
|
22
|
+
|
23
|
+
@@neighbors = Hash.new { |h, k| h[k] = {} }
|
24
|
+
|
25
|
+
attr_accessor :cells
|
26
|
+
attr_accessor :cache
|
27
|
+
|
28
|
+
def initialize
|
29
|
+
self.cells = []
|
30
|
+
end
|
31
|
+
|
32
|
+
def randomize n, m
|
33
|
+
dimensions = n.times.to_a
|
34
|
+
cells.replace dimensions.product(dimensions).sample(m).sort
|
35
|
+
end
|
36
|
+
|
37
|
+
def run max = 1.0 / 0
|
38
|
+
(1..max).each do |n|
|
39
|
+
yield n
|
40
|
+
update
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def update
|
45
|
+
cells.replace considered.select { |(x, y)| alive? x, y }.sort
|
46
|
+
end
|
47
|
+
|
48
|
+
def considered
|
49
|
+
cells.map { |(x, y)| neighbors_for(x, y) }.flatten(1).uniq
|
50
|
+
end
|
51
|
+
|
52
|
+
def binary_search(container, item)
|
53
|
+
return nil if item.nil?
|
54
|
+
low = 0
|
55
|
+
high = container.size - 1
|
56
|
+
while low <= high do
|
57
|
+
mid = (low + high) / 2
|
58
|
+
val = container[mid]
|
59
|
+
if val > item then
|
60
|
+
high = mid - 1
|
61
|
+
elsif val < item then
|
62
|
+
low = mid + 1
|
63
|
+
else
|
64
|
+
return val
|
65
|
+
end
|
66
|
+
end
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
|
70
|
+
def alive? x, y
|
71
|
+
count = (neighbors_for(x, y) & cells).size
|
72
|
+
min = MIN[!!binary_search(cells, [x, y])] # .include? [x, y]]
|
73
|
+
count.between? min, 3
|
74
|
+
end
|
75
|
+
|
76
|
+
def neighbors_for x, y
|
77
|
+
@@neighbors[x][y] ||=
|
78
|
+
DELTAS.map { |(dx, dy)| [x+dx, y+dy] }.reject { |(m, n)| m < 0 || n < 0 }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
size, width, count = 20, 32, 256
|
83
|
+
|
84
|
+
gol = GameOfLife.new
|
85
|
+
gol.randomize width, count
|
86
|
+
|
87
|
+
if ARGV.first == "prof" then
|
88
|
+
gol.run 50 do |n|
|
89
|
+
$stderr.print "."
|
90
|
+
end
|
91
|
+
warn "done"
|
92
|
+
else
|
93
|
+
require "sdl"
|
94
|
+
|
95
|
+
SDL.init SDL::INIT_VIDEO
|
96
|
+
SDL::WM::set_caption "Conway's Game of Life", "Conway's Game of Life"
|
97
|
+
|
98
|
+
screen = SDL::Screen.open 640, 640, 16, SDL::DOUBLEBUF
|
99
|
+
|
100
|
+
black = screen.format.map_rgb 0, 0, 0
|
101
|
+
white = screen.format.map_rgb 255, 255, 255
|
102
|
+
|
103
|
+
w, h = screen.w, screen.h
|
104
|
+
|
105
|
+
gol.run do
|
106
|
+
screen.fill_rect 0, 0, w, h, black
|
107
|
+
|
108
|
+
gol.cells.each do |(x, y)|
|
109
|
+
screen.fill_rect x*size, y*size, size-1, size-1, white
|
110
|
+
end
|
111
|
+
|
112
|
+
screen.flip
|
113
|
+
|
114
|
+
while event = SDL::Event.poll
|
115
|
+
case event
|
116
|
+
when SDL::Event::KeyDown, SDL::Event::Quit
|
117
|
+
exit
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
gol.update
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
|
3
|
+
srand 42
|
4
|
+
|
5
|
+
class Array
|
6
|
+
def sorted_include? o
|
7
|
+
a, b = o
|
8
|
+
!!bsearch { |(x, y)|
|
9
|
+
c = a - x
|
10
|
+
c.zero? ? b - y : c
|
11
|
+
}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class GameOfLife
|
16
|
+
delta = [-1, 0, 1]
|
17
|
+
same = [0, 0]
|
18
|
+
|
19
|
+
DELTAS = (delta.product(delta) - [same]).sort
|
20
|
+
MIN = { true => 2, false => 3 }
|
21
|
+
|
22
|
+
@@neighbors = Hash.new { |h, k| h[k] = {} }
|
23
|
+
|
24
|
+
attr_accessor :cells
|
25
|
+
attr_accessor :cache
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
self.cells = []
|
29
|
+
end
|
30
|
+
|
31
|
+
def randomize n, m
|
32
|
+
dimensions = n.times.to_a
|
33
|
+
cells.replace dimensions.product(dimensions).sample(m).sort
|
34
|
+
end
|
35
|
+
|
36
|
+
def run max = 1.0 / 0
|
37
|
+
(1..max).each do |n|
|
38
|
+
yield n
|
39
|
+
update
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def update
|
44
|
+
cells.replace considered.select { |(x, y)| alive? x, y }.sort
|
45
|
+
end
|
46
|
+
|
47
|
+
def considered
|
48
|
+
cells.map { |(x, y)| neighbors_for(x, y) }.flatten(1).uniq
|
49
|
+
end
|
50
|
+
|
51
|
+
def alive? x, y
|
52
|
+
count = (neighbors_for(x, y) & cells).size
|
53
|
+
min = MIN[cells.sorted_include? [x, y]]
|
54
|
+
count.between? min, 3
|
55
|
+
end
|
56
|
+
|
57
|
+
def neighbors_for x, y
|
58
|
+
@@neighbors[x][y] ||=
|
59
|
+
DELTAS.map { |(dx, dy)| [x+dx, y+dy] }.reject { |(m, n)| m < 0 || n < 0 }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
size, width, count = 10, 64, 1000
|
64
|
+
|
65
|
+
gol = GameOfLife.new
|
66
|
+
gol.randomize width, count
|
67
|
+
|
68
|
+
if ARGV.first == "prof" then
|
69
|
+
gol.run 50 do |n|
|
70
|
+
$stderr.print "."
|
71
|
+
end
|
72
|
+
warn "done"
|
73
|
+
else
|
74
|
+
require "sdl"
|
75
|
+
|
76
|
+
SDL.init SDL::INIT_VIDEO
|
77
|
+
SDL::WM::set_caption "Conway's Game of Life", "Conway's Game of Life"
|
78
|
+
|
79
|
+
screen = SDL::Screen.open 640, 640, 16, SDL::DOUBLEBUF
|
80
|
+
|
81
|
+
black = screen.format.map_rgb 0, 0, 0
|
82
|
+
white = screen.format.map_rgb 255, 255, 255
|
83
|
+
|
84
|
+
w, h = screen.w, screen.h
|
85
|
+
|
86
|
+
gol.run do
|
87
|
+
screen.fill_rect 0, 0, w, h, black
|
88
|
+
|
89
|
+
gol.cells.each do |(x, y)|
|
90
|
+
screen.fill_rect x*size, y*size, size-1, size-1, white
|
91
|
+
end
|
92
|
+
|
93
|
+
screen.flip
|
94
|
+
|
95
|
+
while event = SDL::Event.poll
|
96
|
+
case event
|
97
|
+
when SDL::Event::KeyDown, SDL::Event::Quit
|
98
|
+
exit
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
gol.update
|
103
|
+
end
|
104
|
+
end
|