public
Description: Bouncing balls examples for Shoes
Homepage:
Clone URL: git://github.com/alexyoung/shoes-ball.git
shoes-ball / ball-gravity.rb
100644 134 lines (107 sloc) 2.628 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
require 'matrix'
 
class Ball
  attr_accessor :radius, :mass, :position, :velocity, :inverse_mass
 
  def initialize(app, options = {})
    @mass = options[:mass] or 0.0
    @velocity = Vector.[](options[:velocity][0], options[:velocity][1])
    @position = Vector.[](options[:position][0], options[:position][1])
    @radius = options[:radius] || 10
    @fixed = options[:fixed] || false
    @fill = options[:fill] || '#ff0000'
    @fill = '#000000' if @fixed
    @eta = 0.6
    @gravity = 1.0
 
    @inverse_mass = 1.0 / @mass
    @app = app
    @app.fill @fill
    draw
  end
 
  def draw
    @circle = @app.oval :top => @position[0], :left => @position[1], :radius => @radius
  end
 
  def remove
    @circle.hide
    @circle.remove
  end
 
  def fixed?
    @fixed
  end
 
  # Momentum = mass * velocity
  def update_momentum
    return if fixed?
    apply_gravity
    @position += @velocity * @mass
  end
 
  def update_sprite
    @circle.move @position[0], @position[1]
  end
 
  def move
    update_sprite
    update_momentum
  end
 
  def apply_gravity
    @velocity += Vector.[](0, @gravity)
  end
 
  def check_collisions
    wall_collisions
  end
  
  def bounce_off_wall
    @velocity = ((@velocity * -1) * @eta)
  end
 
  def wall_collisions
    if @position[0] <= 0
      @position = Vector.[](0, @position[1])
      bounce_off_wall
    end
 
    if @position[0] >= @app.width - (@radius * 2)
      @position = Vector.[](@app.width - (@radius * 2), @position[1])
      bounce_off_wall
    end
 
    if @position[1] <= 0
      @position = Vector.[](@position[0], 0)
      bounce_off_wall
    end
 
    if @position[1] >= @app.height - (@radius * 2)
      @position = Vector.[](@position[0], @app.height - (@radius * 2))
      bounce_off_wall
    end
  end
end
 
Shoes.app :width => 400, :height => 400 do
  background '#fff'
  balls = []
 
  def random_ball
    Ball.new(self, :mass => rand,
                   :fill => rgb(rand(255), rand(255), rand(255)),
                   :radius => 10,
                   :velocity => [rand - 1.0, rand - 1.0],
                   :fixed => false,
                   :position => [rand(width), rand(50)])
 
  end
 
  def load_balls
    balls = []
    (1..10).each do
      balls << random_ball
    end
 
    balls
  end
 
  def reload(balls)
    balls.each { |ball| ball.remove }
    balls = load_balls
  end
 
  balls = reload(balls)
 
  @anim = animate 30 do
    balls.each do |ball|
      ball.check_collisions
      ball.move
    end
 
    keypress do |k|
      case k
        when 'a':
          balls << random_ball
        when 'r'
          balls = reload(balls)
      end
    end
  end
end