Skip to content

Latest commit

 

History

History
411 lines (312 loc) · 10.3 KB

01120_Fancy_Gallery_6-10.mdown

File metadata and controls

411 lines (312 loc) · 10.3 KB

Fancy Gallery 6-10

Gallery No.6

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

gallery6.png

Gallery No.7

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

gallery7.png

Gallery No.8

Paul Harris introduced the following fancy Shoes app in the Shoes course 4th batch.

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

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.

Gallery No.9

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

gallery9.png

Gallery No.10

A Very Simple Boids Program.

Paul Harris introduced the following fancy Shoes app in the Shoes course 4th batch.

Hungry Boids

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

gallery10.png

Policeman

Gallery 6, 7 and 8 worked well with Shoes-0.r1263.

Gallery 9 and 10 worked well after replaced class to class_eval.