I found the Ruby Quiz solution with Shoes.
Ruby Quiz 197 Midpoint Displacement
Fantastic mountain! So, let me try to write my own Shoes app.
Look at online demo.
# gallery6.rb
# Ruby Quiz 197 Midpoint Displacement
# http://rubyquiz.strd6.com/quizzes/197/
require 'enumerator'
POINTS = [[600, 0], [0, 0], [0, 220]]
Shoes.app :title => 'Midpoint Displacement v0.1'do
def midpoint_displacement
create_stars
points = [[0, 220], [600, 220]]
n = 2
mk_midpoints = proc do
tmp = [points[0]]
n /= 2.0
points.each_cons 2 do |x1, x2|
n_rand = n * 2 * rand - n
n_rand = n_rand.abs if n == 1
y = (x1[1] + x2[1]) / 2.0
tmp << [(x1[0] + x2[0]) / 2.0, y + y * n_rand] << x2
end
points = tmp
end
t = every 1 do |i|
@mt.remove if @mt
mk_midpoints.call
@mt = shape :top => 100 do
(points+POINTS).each_with_index do |e, j|
x, y = e
move_to(x, y) if j == 0
line_to x, 400 - y
end
end
t.stop if i > 7
end
end
def position radius, t
angle = 2 * Math::PI * t / (24 * 60) - Math::PI / 2
x, y = 300 + radius * Math.cos(angle), 250 + radius * Math.sin(angle)
[x.to_i, y.to_i]
end
def create_stars
50.times do
r, t = rand(300), rand(24 * 60)
x, y = position(r, t)
@stars << star(x, y, 5, outer = 1 + rand(10), outer / 2, :fill => white,
:stroke => white, :r => r, :t => t)
end
@a = animate(24){|i| move_stars i}
end
def move_stars i
@stars.each do |s|
x, y = position(s.style[:r], s.style[:t] + i)
s.style :left => x, :top => y
end
end
background teal..white
@stars = []
midpoint_displacement
button 'one more time' do
(@stars + [@a, @mt]).each{|s| s.remove}
midpoint_displacement
end
end
gallery6.png
The Game Snake. It's a very nice tutorial.
Let's Make a Game: Wrap Up
I was really inspired and wrote the following 55 lines Snake in Shoes.
It's a power of Shoes! ;-)
Look at online demo
# gallery7.rb
# 55 lines Snake in Shoes
class SnakeGame < Shoes
url '/', :index
def index
background black
game_start
end
def game_start
@score = para 'Score:', :stroke => white
@pos = {:up => [0, -10], :down => [0, 10], :left => [-10, 0], :right => [10, 0]}
@rx, @ry = proc{20 + 10*rand(56)}, proc{40 + 10*rand(44)}
@foods = []
stroke lime
50.times{@foods << rect(@rx[], @ry[], 10, 10)}
@bricks = []
stroke deepskyblue; fill '#000099'
50.times{@bricks << rect(@rx[], @ry[], 10, 10)}
20.step(570, 10){|n| @bricks << rect(n, 40, 10, 10) << rect(n, 470, 10, 10)}
40.step(470, 10){|n| @bricks << rect(10, n, 10, 10) << rect(570, n, 10, 10)}
@snake = []
stroke white; nofill
@snake << rect(300, 100, 10, 10)
@snake[0].stroke = red
dir = :left
@run = animate 5 do
keypress{|k| dir = k if @pos.keys.include? k}
check_food
go dir
@score.text = "Score: #{@snake.length * 10}"
brick? @snake[0]
end
end
def go k
x, y = @pos[k]
@snake.unshift @snake.pop
n = @snake.length > 1 ? 1 : 0
@snake[0].move @snake[n].left + x, @snake[n].top + y
@snake[0].stroke, @snake[n].stroke = @snake[n].stroke, @snake[0].stroke
end
def check_food
(@snake << rect(0, 0, 10, 10)) if eat? @snake[0]
end
def eat? s
@foods.each_with_index do |f, i|
(f.move @rx[], @ry[]; return true) if f.left == s.left and f.top == s.top
end
return false
end
def brick? s
@bricks.each do |b|
(@run.stop; confirm('Game Over. Play again?') ? visit('/') : exit) \
if b.left == s.left and b.top == s.top
end
end
end
Shoes.app :title => 'Snake Game v0.1'
gallery7.png
Paul Harris introduced the following fancy Shoes app in the Shoes course 4th batch.
- Parallax Scrolling (Shoes ML Archive)
- Parallax Scrolling (Wikipedia)
I was very impressed and then improved to move a bit more smoothly.
Look at online demo
# gallery8.rb
Shoes.app :width=>320, :height=>200 do
str = "../images/Parallax-scroll-example-layer-%s.gif"
imgs = []
4.times do |i|
path = str % i
imgs << [image(path), image(path), imagesize(path).first]
end
animate 24 do |i|
imgs.each_with_index do |e, n|
img1, img2, w = e
x = -(n * i % w)
img1.move x, 0
img2.move x + w, 0
end
end
end
gallery8.png
NOTE
If you have the faster machine than mine. It might be occured this error:
- undefined method
first
for nil:NilClass
If it'll happen, try to modify the code, line 7, like this:
width = imagesize(path).first
fs << [image(path), image(path), width]
This tip was presented by Paul Harris.
The Scatter Pack. This is a swarm of frightened bubbles. They run away from the green circle, the extent of mouse position.
Original Shoes app is this:
The Scatter Pack
Hacked from scratch. :)
Look at the online demo.
# gallery9.rb
# ScatterPack: Scatters like a school of fish
Shoes::Shape.class_eval do
[:v, :flag].each do |m|
define_method(m){style[m]}
define_method(m.to_s + '='){|v| style m => v}
end
end
Shoes.app :width => 300, :height => 300, :title => 'Scatter Pack v0.1' do
nostroke; nofill
colors = []
5.times{colors << rgb(rand(255), rand(255), rand(255), (0.5..1.0).rand)}
discs = []
50.times do
vx = vy = 0
(vx, vy = (-3..3).rand, (-3..3).rand) while [vx, vy] == [0, 0]
r = (5..100).rand
discs << oval(rand(width - r), rand(height - r), (5..100).rand,
:fill => colors[rand(5)], :v => [vx, vy], :flag => true)
end
@area = oval 0, 0, 100, :stroke => green
def disc_move disc
vx, vy = disc.v
nx, ny = disc.left + vx, disc.top + vy
vx = -vx if nx + disc.width > width or nx < 0
vy = -vy if ny + disc.width > height or ny < 0
if near_mouse?(disc)
(vx, vy = -vx * 2, -vy * 2) if disc.flag
disc.flag = false
else
(vx, vy = vx / 2, vy / 2) unless disc.flag
disc.flag = true
end
disc.move nx , ny
disc.v = [vx, vy]
end
def near_mouse? disc
r = disc.width / 2
x, y = disc.left + r, disc.top + r
Math.sqrt((mouse[1] - x)**2 + (mouse[2] - y)**2) < (@area.width / 2 + r)
end
keys = {'+' => 10, '-' => -10}
animate 12 do
discs.each{|disc| disc_move disc}
@area.left = mouse[1] - @area.width / 2
@area.top = mouse[2] - @area.width / 2
keypress do |k|
val = @area.width + keys[k].to_i
@area.width = val if val > 10
end
end
end
gallery9.png
A Very Simple Boids Program.
Paul Harris introduced the following fancy Shoes app in the Shoes course 4th batch.
I read the code and found the link to this web site:
Boids Pseudocode
So simple! Most impressive indeed!
I attempted coding a tiny Shoes app just by following the algorithm.
Look at online demo.
# gallery10.rb
# http://www.vergenet.net/~conrad/boids/pseudocode.html
require 'matrix'
require 'gallery10-image'
require 'gallery10-rules'
Shoes.app :title => 'A Very Simple Boids v0.1' do
extend Rules
@boids = []
N.times do
x, y = rand(200), rand(200)
vx, vy = rand(2), rand(2)
@boids << image('../images/gallery10-kamome.png',
:left => x, :top => y, :pos => Vector[x, y], :vel => Vector[vx, vy])
end
animate 12 do
@boids.each do |boid|
boid.vel = boid.vel + rule1(boid) + rule2(boid) + rule3(boid) + rule4(boid)
boid.pos = boid.pos + boid.vel
boid.move boid.x, boid.y
end
end
end
4 rules:
# gallery10-rules.rb
N = 12
BOUND = 3
module Rules
def rule1 boid
c = @boids.collect{|b| b.pos}.inject{|i, j| i + j} - boid.pos
c *= 1 / (N - 1.0)
(c - boid.pos) * 0.01
end
def rule2 boid
c = Vector[0, 0]
@boids.each do |b|
dist = b.pos - boid.pos
(c -= b.pos - boid.pos) if (b != boid and dist[0].to_i.abs < 5 and dist[1].to_i.abs < 5)
end
c
end
def rule3 boid
c = @boids.collect{|b| b.vel}.inject{|i, j| i + j} - boid.vel
c *= 1 / (N - 1.0)
(c - boid.vel) * (1 / 16.0)
end
def rule4 boid
vx, vy = 0, 0
x, y = boid.pos[0], boid.pos[1]
vx = BOUND if x < 20
vx = -BOUND if x > 580
vy = BOUND if y < 20
vy = -BOUND if y > 480
Vector[vx, vy]
end
end
Helper methods for writing the simple code:
# gallery10-image.rb
Shoes::Image.class_eval do
[:vel, :pos].each do |m|
define_method(m){style[m]}
define_method("#{m}="){|arg| style m => arg}
end
[:x, :y].each_with_index{|m, i| define_method(m){pos[i].to_i}}
end
gallery10.png
Gallery 6, 7 and 8 worked well with Shoes-0.r1263.
Gallery 9 and 10 worked well after replaced class
to class_eval
.