graphics 1.0.0b1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|