shoes 4.0.0.pre11 → 4.0.0.pre12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (182) hide show
  1. checksums.yaml +4 -4
  2. data/bin/shoes-stub +8 -0
  3. data/lib/shoes/samples.rb +8 -0
  4. data/samples/README +122 -0
  5. data/samples/avatar.png +0 -0
  6. data/samples/blue-box.png +0 -0
  7. data/samples/class-book.yaml +387 -0
  8. data/samples/class_book.rb +46 -0
  9. data/samples/cy.png +0 -0
  10. data/samples/expert_definr.rb +24 -0
  11. data/samples/expert_funnies.rb +60 -0
  12. data/samples/expert_game_of_life.rb +224 -0
  13. data/samples/expert_irb.rb +109 -0
  14. data/samples/expert_minesweeper.rb +272 -0
  15. data/samples/expert_othello.rb +323 -0
  16. data/samples/expert_pong.rb +69 -0
  17. data/samples/expert_snake.rb +88 -0
  18. data/samples/expert_tankspank.rb +425 -0
  19. data/samples/expert_tetris.rb +322 -0
  20. data/samples/good_arc.rb +51 -0
  21. data/samples/good_bounce.rb +34 -0
  22. data/samples/good_clock.rb +55 -0
  23. data/samples/good_displace.rb +99 -0
  24. data/samples/good_follow.rb +27 -0
  25. data/samples/good_image_dl.rb +13 -0
  26. data/samples/good_potato_chopping.rb +23 -0
  27. data/samples/good_psychidelic_circles.rb +73 -0
  28. data/samples/good_reminder.rb +163 -0
  29. data/samples/good_vjot.rb +65 -0
  30. data/samples/lib/require_me.rb +6 -0
  31. data/samples/loogink.png +0 -0
  32. data/samples/menu-corner1.png +0 -0
  33. data/samples/menu-corner2.png +0 -0
  34. data/samples/menu-gray.png +0 -0
  35. data/samples/menu-left.png +0 -0
  36. data/samples/menu-right.png +0 -0
  37. data/samples/menu-top.png +0 -0
  38. data/samples/nks_booklist.rb +25 -0
  39. data/samples/nks_breadsticks.rb +8 -0
  40. data/samples/nks_dancing_circle.rb +14 -0
  41. data/samples/nks_dictionary.rb +24 -0
  42. data/samples/nks_edit_box.rb +5 -0
  43. data/samples/nks_edit_line.rb +7 -0
  44. data/samples/nks_notes.rb +16 -0
  45. data/samples/nks_poem.rb +23 -0
  46. data/samples/nks_self.rb +7 -0
  47. data/samples/nks_text_sizes.rb +11 -0
  48. data/samples/nks_trurl.rb +6 -0
  49. data/samples/potato_chopping/1258_s001.gif +0 -0
  50. data/samples/potato_chopping/1258_s002.gif +0 -0
  51. data/samples/potato_chopping/1258_s003.gif +0 -0
  52. data/samples/potato_chopping/1258_s004.gif +0 -0
  53. data/samples/potato_chopping/1258_s005.gif +0 -0
  54. data/samples/potato_chopping/1258_s006.gif +0 -0
  55. data/samples/potato_chopping/1258_s007.gif +0 -0
  56. data/samples/potato_chopping/1258_s008.gif +0 -0
  57. data/samples/potato_chopping/1258_s009.gif +0 -0
  58. data/samples/potato_chopping/1258_s010.gif +0 -0
  59. data/samples/potato_chopping/1258_s011.gif +0 -0
  60. data/samples/potato_chopping/1258_s012.gif +0 -0
  61. data/samples/potato_chopping/1258_s013.gif +0 -0
  62. data/samples/potato_chopping/1258_s014.gif +0 -0
  63. data/samples/potato_chopping/1258_s015.gif +0 -0
  64. data/samples/potato_chopping/1258_s016.gif +0 -0
  65. data/samples/potato_chopping/1258_s017.gif +0 -0
  66. data/samples/potato_chopping/1258_s018.gif +0 -0
  67. data/samples/potato_chopping/1258_s019.gif +0 -0
  68. data/samples/potato_chopping/1258_s020.gif +0 -0
  69. data/samples/potato_chopping/1258_s021.gif +0 -0
  70. data/samples/potato_chopping/1258_s022.gif +0 -0
  71. data/samples/potato_chopping/1258_s023.gif +0 -0
  72. data/samples/potato_chopping/1258_s024.gif +0 -0
  73. data/samples/potato_chopping/1258_s025.gif +0 -0
  74. data/samples/potato_chopping/1258_s026.gif +0 -0
  75. data/samples/potato_chopping/1258_s027.gif +0 -0
  76. data/samples/potato_chopping/1258_s028.gif +0 -0
  77. data/samples/potato_chopping/1258_s029.gif +0 -0
  78. data/samples/potato_chopping/1258_s030.gif +0 -0
  79. data/samples/potato_chopping/1258_s031.gif +0 -0
  80. data/samples/potato_chopping/1258_s032.gif +0 -0
  81. data/samples/potato_chopping/1258_s033.gif +0 -0
  82. data/samples/potato_chopping/1258_s034.gif +0 -0
  83. data/samples/potato_chopping/1258_s035.gif +0 -0
  84. data/samples/potato_chopping/1258_s036.gif +0 -0
  85. data/samples/potato_chopping/1258_s037.gif +0 -0
  86. data/samples/potato_chopping/1258_s038.gif +0 -0
  87. data/samples/potato_chopping/1258_s039.gif +0 -0
  88. data/samples/potato_chopping/1258_s040.gif +0 -0
  89. data/samples/potato_chopping/1258_s041.gif +0 -0
  90. data/samples/potato_chopping/1258_s042.gif +0 -0
  91. data/samples/potato_chopping/1258_s043.gif +0 -0
  92. data/samples/potato_chopping/1258_s044.gif +0 -0
  93. data/samples/potato_chopping/1258_s045.gif +0 -0
  94. data/samples/potato_chopping/1258_s046.gif +0 -0
  95. data/samples/potato_chopping/1258_s047.gif +0 -0
  96. data/samples/potato_chopping/1258_s048.gif +0 -0
  97. data/samples/potato_chopping/1258_s049.gif +0 -0
  98. data/samples/potato_chopping/1258_s050.gif +0 -0
  99. data/samples/potato_chopping/1258_s051.gif +0 -0
  100. data/samples/potato_chopping/1258_s052.gif +0 -0
  101. data/samples/potato_chopping/1258_s053.gif +0 -0
  102. data/samples/potato_chopping/1258_s054.gif +0 -0
  103. data/samples/potato_chopping/1258_s055.gif +0 -0
  104. data/samples/potato_chopping/1258_s056.gif +0 -0
  105. data/samples/potato_chopping/1258_s057.gif +0 -0
  106. data/samples/potato_chopping/1258_s058.gif +0 -0
  107. data/samples/potato_chopping/1258_s059.gif +0 -0
  108. data/samples/red-box.png +0 -0
  109. data/samples/shape_arc_to.rb +10 -0
  110. data/samples/simple-form.shy +0 -0
  111. data/samples/simple_accordion.rb +98 -0
  112. data/samples/simple_alert.rb +10 -0
  113. data/samples/simple_altered_para.rb +11 -0
  114. data/samples/simple_anim_shapes.rb +18 -0
  115. data/samples/simple_anim_text.rb +14 -0
  116. data/samples/simple_animate.rb +12 -0
  117. data/samples/simple_arc.rb +25 -0
  118. data/samples/simple_attach.rb +26 -0
  119. data/samples/simple_border_image.rb +9 -0
  120. data/samples/simple_borderless.rb +4 -0
  121. data/samples/simple_bounce.rb +27 -0
  122. data/samples/simple_breadsticks.rb +11 -0
  123. data/samples/simple_breadsticks2.rb +11 -0
  124. data/samples/simple_brightness_transitions.rb +16 -0
  125. data/samples/simple_button_animate.rb +17 -0
  126. data/samples/simple_buttons.rb +4 -0
  127. data/samples/simple_calc.rb +67 -0
  128. data/samples/simple_calc_2.rb +49 -0
  129. data/samples/simple_clipboard.rb +17 -0
  130. data/samples/simple_color_selector.rb +11 -0
  131. data/samples/simple_color_transitions.rb +12 -0
  132. data/samples/simple_concentric_circles.rb +9 -0
  133. data/samples/simple_console.rb +12 -0
  134. data/samples/simple_control_sizes.rb +25 -0
  135. data/samples/simple_count_and_draw.rb +19 -0
  136. data/samples/simple_curve.rb +34 -0
  137. data/samples/simple_dialogs.rb +33 -0
  138. data/samples/simple_dialogs_outside.rb +17 -0
  139. data/samples/simple_displace.rb +16 -0
  140. data/samples/simple_downloader.rb +29 -0
  141. data/samples/simple_draw.rb +16 -0
  142. data/samples/simple_editor.rb +30 -0
  143. data/samples/simple_face.rb +15 -0
  144. data/samples/simple_flashing.rb +22 -0
  145. data/samples/simple_flow_wrap.rb +12 -0
  146. data/samples/simple_font.rb +18 -0
  147. data/samples/simple_form.rb +30 -0
  148. data/samples/simple_fullscreen.rb +5 -0
  149. data/samples/simple_gradient_shapes.rb +23 -0
  150. data/samples/simple_guess_game.rb +30 -0
  151. data/samples/simple_image_as_stroke.rb +22 -0
  152. data/samples/simple_image_fill.rb +13 -0
  153. data/samples/simple_image_stroke.rb +13 -0
  154. data/samples/simple_info.rb +10 -0
  155. data/samples/simple_iterated_content.rb +8 -0
  156. data/samples/simple_keypress.rb +15 -0
  157. data/samples/simple_logo_display.rb +15 -0
  158. data/samples/simple_loogink_cy.rb +33 -0
  159. data/samples/simple_lorem_ipsum.rb +19 -0
  160. data/samples/simple_manual.rb +5 -0
  161. data/samples/simple_menu.rb +42 -0
  162. data/samples/simple_mouse_follow.rb +9 -0
  163. data/samples/simple_oval.rb +6 -0
  164. data/samples/simple_polygon_line.rb +19 -0
  165. data/samples/simple_position_as_we_go.rb +10 -0
  166. data/samples/simple_progress_bar.rb +15 -0
  167. data/samples/simple_random_bubbles.rb +15 -0
  168. data/samples/simple_require.rb +9 -0
  169. data/samples/simple_sample_executor.rb +7 -0
  170. data/samples/simple_sample_executor_all.rb +14 -0
  171. data/samples/simple_sesame_street_shoes.rb +6 -0
  172. data/samples/simple_shoes_intro.rb +22 -0
  173. data/samples/simple_slide.rb +57 -0
  174. data/samples/simple_stack_flow_buttons.rb +16 -0
  175. data/samples/simple_stripes.rb +9 -0
  176. data/samples/simple_system_background.rb +5 -0
  177. data/samples/simple_text_movement.rb +8 -0
  178. data/samples/simple_tictactoe.rb +224 -0
  179. data/samples/simple_timer.rb +16 -0
  180. data/samples/simple_translate.rb +10 -0
  181. data/samples/simple_visibility.rb +20 -0
  182. metadata +186 -7
@@ -0,0 +1,322 @@
1
+ # frozen_string_literal: true
2
+ #==================================================================================================
3
+ #
4
+ # A Tetris game for Ruby Shoes
5
+ #
6
+ # Controls:
7
+ #
8
+ # left/right - slide the piece horizontally
9
+ # up - rotate the piece 90 degrees clockwise
10
+ # down - drop the piece faster
11
+ # esc - quit the game
12
+ #
13
+ # For more details see http://codeincomplete.com/posts/2014/11/7/tetris_shoes/
14
+ #
15
+
16
+ #==================================================================================================
17
+ # Game Constants
18
+ #==================================================================================================
19
+
20
+ WIDTH = 300 # width of tetris court (in pixels)
21
+ HEIGHT = 600 # height of tetris court (in pixels)
22
+ NX = 10 # width of tetris court (in blocks)
23
+ NY = 20 # height of tetris court (in blocks)
24
+ DX = WIDTH / NX # pixel width of a single tetris block
25
+ DY = HEIGHT / NY # pixel height of a single tetris block
26
+ FPS = 60 # game animation frame rate (fps)
27
+
28
+ PACE = { start: 0.5, step: 0.005, min: 0.1 }.freeze # how long before a piece drops by 1 row (seconds)
29
+ SCORE = { line: 100, multiplier: 2 }.freeze # score per line removed (100) and bonus multiplier when multiple lines cleared in a the same drop
30
+
31
+ #==================================================================================================
32
+ # The 7 Tetromino Types
33
+ #==================================================================================================
34
+ #
35
+ # blocks: each element represents a rotation of the piece (0, 90, 180, 270)
36
+ # each element is a 16 bit integer where the 16 bits represent
37
+ # a 4x4 set of blocks, e.g. j.blocks[0] = 0x44C0
38
+ #
39
+ # 0100 = 0x4 << 3 = 0x4000
40
+ # 0100 = 0x4 << 2 = 0x0400
41
+ # 1100 = 0xC << 1 = 0x00C0
42
+ # 0000 = 0x0 << 0 = 0x0000
43
+ # ------
44
+ # 0x44C0
45
+ #
46
+ # (see http://codeincomplete.com/posts/2011/10/10/javascript_tetris/)
47
+ #
48
+
49
+ I = { blocks: {up: 0x0F00, right: 0x2222, down: 0x00F0, left: 0x4444}, color: '#00FFFF', size: 4 }.freeze
50
+ J = { blocks: {up: 0x44C0, right: 0x8E00, down: 0x6440, left: 0x0E20}, color: '#0000FF', size: 3 }.freeze
51
+ L = { blocks: {up: 0x4460, right: 0x0E80, down: 0xC440, left: 0x2E00}, color: '#FF8000', size: 3 }.freeze
52
+ O = { blocks: {up: 0xCC00, right: 0xCC00, down: 0xCC00, left: 0xCC00}, color: '#FFFF00', size: 2 }.freeze
53
+ S = { blocks: {up: 0x06C0, right: 0x8C40, down: 0x6C00, left: 0x4620}, color: '#00FF00', size: 3 }.freeze
54
+ T = { blocks: {up: 0x0E40, right: 0x4C40, down: 0x4E00, left: 0x4640}, color: '#8040FF', size: 3 }.freeze
55
+ Z = { blocks: {up: 0x0C60, right: 0x4C80, down: 0xC600, left: 0x2640}, color: '#FF0000', size: 3 }.freeze
56
+
57
+ #==================================================================================================
58
+ # The Game Runner
59
+ #==================================================================================================
60
+
61
+ class Tetris
62
+ attr_reader :dt, # time since the current active piece last dropped a row
63
+ :score, # the current score
64
+ :lost, # bool to indicate when the game is lost
65
+ :pace, # current game pace - how long until the current piece drops a single row
66
+ :blocks, # 2 dimensional array (NX*NY) represeting the tetris court - either empty block or occupied by a piece
67
+ :actions, # queue of user inputs collected by the game loop
68
+ :bag, # a collection of random pieces to be used
69
+ :current # the current active piece
70
+
71
+ #----------------------------------------------------------------------------
72
+
73
+ def initialize
74
+ @dt = 0
75
+ @score = 0
76
+ @pace = PACE[:start]
77
+ @blocks = Array.new(NX) { Array.new(NY) } # awkward way to initialize an already sized 2 dimensional array
78
+ @actions = []
79
+ @bag = new_bag
80
+ @current = random_piece
81
+ end
82
+
83
+ #----------------------------------------------------------------------------
84
+
85
+ def update(seconds)
86
+ action = actions.shift
87
+ case action
88
+ when :left then move(:left)
89
+ when :right then move(:right)
90
+ when :rotate then rotate
91
+ when :drop then drop
92
+ end
93
+
94
+ @dt += seconds
95
+ if dt > pace
96
+ @dt = dt - pace
97
+ drop
98
+ end
99
+ end
100
+
101
+ #----------------------------------------------------------------------------
102
+
103
+ def move(direction)
104
+ nextup = current.move(direction)
105
+ if unoccupied(nextup)
106
+ choose_new_piece(nextup)
107
+ true
108
+ end
109
+ end
110
+
111
+ def rotate
112
+ nextup = current.rotate
113
+ if unoccupied(nextup)
114
+ choose_new_piece(nextup)
115
+ true
116
+ end
117
+ end
118
+
119
+ def drop
120
+ unless move(:down)
121
+ finalize_piece
122
+ reward_for_piece
123
+ remove_any_completed_lines
124
+ clear_pending_actions
125
+ choose_new_piece
126
+ lose if occupied(current)
127
+ end
128
+ end
129
+
130
+ #----------------------------------------------------------------------------
131
+
132
+ def unoccupied(piece)
133
+ !occupied(piece)
134
+ end
135
+
136
+ def occupied(piece)
137
+ piece.each_occupied_block do |x, y|
138
+ if x.negative? || (x >= NX) || y.negative? || (y >= NY) || blocks[x][y]
139
+ return true
140
+ end
141
+ end
142
+ false
143
+ end
144
+
145
+ #----------------------------------------------------------------------------
146
+
147
+ def finalize_piece
148
+ current.each_occupied_block { |x, y| blocks[x][y] = current.tetromino }
149
+ end
150
+
151
+ def choose_new_piece(piece = nil)
152
+ @current = piece || random_piece
153
+ end
154
+
155
+ def reward_for_piece
156
+ @score = score + 10
157
+ end
158
+
159
+ def reward_lines(lines)
160
+ @score = score + (SCORE[:line] * SCORE[:multiplier]**(lines - 1)) # e.g. 1: 100, 2: 200, 3: 400, 4: 800
161
+ @pace = [pace - lines * PACE[:step], PACE[:min]].max
162
+ end
163
+
164
+ def clear_pending_actions
165
+ actions.clear
166
+ end
167
+
168
+ def lose
169
+ @lost = true
170
+ end
171
+
172
+ def lost?
173
+ @lost
174
+ end
175
+
176
+ def new_bag
177
+ [I, I, I, I, J, J, J, J, L, L, L, L, O, O, O, O, S, S, S, S, T, T, T, T, Z, Z, Z, Z].shuffle
178
+ end
179
+
180
+ def random_piece
181
+ @bag = new_bag if bag.empty?
182
+ Piece.new(bag.pop)
183
+ end
184
+
185
+ #----------------------------------------------------------------------------
186
+
187
+ def remove_any_completed_lines
188
+ lines = 0
189
+ NY.times do |y|
190
+ unless NX.times.any? { |x| blocks[x][y].nil? }
191
+ remove_line(y)
192
+ lines += 1
193
+ end
194
+ end
195
+ reward_lines(lines) unless lines.zero?
196
+ end
197
+
198
+ def remove_line(n)
199
+ n.downto(0) do |y|
200
+ NX.times do |x|
201
+ blocks[x][y] = y.zero? ? nil : blocks[x][y - 1]
202
+ end
203
+ end
204
+ end
205
+
206
+ #----------------------------------------------------------------------------
207
+
208
+ def each_occupied_block
209
+ NY.times do |y|
210
+ NX.times do |x|
211
+ yield x, y, blocks[x][y][:color] unless blocks[x][y].nil?
212
+ end
213
+ end
214
+ end
215
+ end # class Tetris
216
+
217
+ #==================================================================================================
218
+ # A Game Piece
219
+ #==================================================================================================
220
+
221
+ class Piece
222
+ attr_reader :tetromino, # the tetromino type
223
+ :direction, # the rotation direction (:up, :down, :left, :right)
224
+ :x, :y # the (x,y) position on the board
225
+
226
+ #----------------------------------------------------------------------------
227
+
228
+ def initialize(tetromino, x = nil, y = nil, direction = nil)
229
+ @tetromino = tetromino
230
+ @direction = direction || :up
231
+ @x = x || rand(NX - tetromino[:size]) # default to a random horizontal position (that fits)
232
+ @y = y || 0
233
+ end
234
+
235
+ #----------------------------------------------------------------------------
236
+
237
+ def rotate
238
+ newdir = case direction
239
+ when :left then :up
240
+ when :up then :right
241
+ when :right then :down
242
+ when :down then :left
243
+ end
244
+ Piece.new(tetromino, x, y, newdir)
245
+ end
246
+
247
+ def move(direction)
248
+ case direction
249
+ when :right then Piece.new(tetromino, x + 1, y, @direction)
250
+ when :left then Piece.new(tetromino, x - 1, y, @direction)
251
+ when :down then Piece.new(tetromino, x, y + 1, @direction)
252
+ end
253
+ end
254
+
255
+ #----------------------------------------------------------------------------
256
+
257
+ def each_occupied_block # a bit complex, for more details see - http://codeincomplete.com/posts/2011/10/10/javascript_tetris/
258
+ bit = 0b1000000000000000
259
+ row = 0
260
+ col = 0
261
+ blocks = tetromino[:blocks][direction]
262
+ until bit.zero?
263
+ yield x + col, y + row if (blocks & bit) == bit
264
+ col += 1
265
+ if col == 4
266
+ col = 0
267
+ row += 1
268
+ end
269
+ bit = bit >> 1
270
+ end
271
+ end
272
+ end # class Piece
273
+
274
+ #==================================================================================================
275
+ # The SHOES application
276
+ #==================================================================================================
277
+
278
+ Shoes.app title: 'Tetris', width: WIDTH, height: HEIGHT do
279
+ game = Tetris.new
280
+
281
+ keypress do |k|
282
+ case k
283
+ when :left then game.actions << :left
284
+ when :right then game.actions << :right
285
+ when :down then game.actions << :drop
286
+ when :up then game.actions << :rotate
287
+ when :escape then quit
288
+ end
289
+ end
290
+
291
+ def block(x, y, color)
292
+ fill color
293
+ rect(x * DX, y * DY, DX, DY)
294
+ end
295
+
296
+ last = Time.now
297
+ animate = animate FPS do
298
+ now = Time.now
299
+
300
+ game.update(now - last)
301
+ clear
302
+
303
+ game.each_occupied_block do |x, y, color|
304
+ block(x, y, color)
305
+ end
306
+
307
+ game.current.each_occupied_block do |x, y|
308
+ block(x, y, game.current.tetromino[:color])
309
+ end
310
+
311
+ if game.lost?
312
+ banner "Game Over", align: 'center', stroke: black
313
+ animate.stop
314
+ else
315
+ subtitle "Score: #{format('%6.6d', game.score)}", stroke: green, align: 'right'
316
+ end
317
+
318
+ last = now
319
+ end
320
+ end
321
+
322
+ #==================================================================================================
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # a translation from a processing example
4
+ # http://vormplus.be/weging/an-introduction-to-processing/
5
+ #
6
+ Shoes.app width: 420, height: 420, resizable: false do
7
+ stage = 0
8
+ wide = 3
9
+ sw = 1.0
10
+ basesize = 600
11
+ step = 60
12
+ stroke white(100)
13
+ nofill
14
+
15
+ animate 40 do |i|
16
+ stage = rand(1...8) if (i % 40).zero?
17
+ if wide.abs < 0.1
18
+ wide = if stage == 6
19
+ -0.1
20
+ else
21
+ 0.1
22
+ end
23
+ end
24
+ rotation = -(Shoes::HALF_PI / wide)
25
+ clear do
26
+ background gray(240)
27
+ 10.times do |j|
28
+ strokewidth sw * j
29
+ size = (basesize + step * j) / 3
30
+ top = (height - size) / 2
31
+ left = (width - size) / 2
32
+ arc top, left,
33
+ size, size,
34
+ rotation * j,
35
+ rotation * j + Shoes::TWO_PI - Shoes::HALF_PI
36
+ end
37
+ end
38
+
39
+ case stage
40
+ when 1 then wide -= 0.1
41
+ when 2 then wide += 0.1
42
+ when 3 then basesize -= 1
43
+ when 4 then basesize += 2
44
+ when 5 then sw += 0.1
45
+ when 6 then sw = [sw - 0.1, 0.1].max
46
+ when 7 then step += 2
47
+ else
48
+ step -= 1
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+ # The Shoes logo/icon bounces on the screen. The logo/icon responds to menu options and if clicked on.
3
+ xspeed = 10
4
+ yspeed = 6
5
+ xdir = 1
6
+ ydir = 1
7
+
8
+ Shoes.app width: 300, height: 300 do
9
+ a = nil
10
+ button('toggle') { a.toggle }
11
+ button('stop') { a.stop }
12
+ button('start') { a.start }
13
+ button('remove') { a.remove }
14
+ img = image File.join(Shoes::DIR, 'static/shoes-icon.png'),
15
+ click: ->() { alert "You're soooo quick!" }
16
+
17
+ x = 150
18
+ y = 150
19
+ size = [128, 128]
20
+ pause = 0
21
+
22
+ a = animate 24 do |n|
23
+ unless pause == n
24
+ x += xspeed * xdir
25
+ y += yspeed * ydir
26
+
27
+ xdir *= -1 if x > 300 - size[0] || x.negative?
28
+ ydir *= -1 if y > 300 - size[1] || y.negative?
29
+
30
+ img.move x.to_i, y.to_i
31
+ end
32
+ pause = n
33
+ end
34
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Shoes Clock by Thomas Bell
4
+ # posted to the Shoes mailing list on 04 Dec 2007
5
+ #
6
+ Shoes.app height: 260, width: 250 do
7
+ @radius = 90
8
+ @centerx = 126
9
+ @centery = 140
10
+ animate(8) do
11
+ @time = Time.now
12
+ clear do
13
+ draw_background
14
+ stack do
15
+ background black
16
+ para @time.strftime("%a"),
17
+ span(@time.strftime(" %b %d, %Y "), stroke: "#ccc"),
18
+ strong(@time.strftime("%I:%M"), stroke: white),
19
+ @time.strftime(".%S"), align: "center", stroke: "#666",
20
+ margin: 4
21
+ end
22
+ clock_hand @time.sec + (@time.usec * 0.000001), 2, 30, red
23
+ clock_hand @time.min + (@time.sec / 60.0), 5
24
+ clock_hand @time.hour + (@time.min / 60.0), 8, 6
25
+ end
26
+ end
27
+ def draw_background
28
+ background rgb(230, 240, 200)
29
+
30
+ fill white
31
+ stroke black
32
+ strokewidth 4
33
+ oval @centerx - 102, @centery - 102, 204, 204
34
+
35
+ fill black
36
+ nostroke
37
+ oval @centerx - 5, @centery - 5, 10, 10
38
+
39
+ stroke black
40
+ strokewidth 1
41
+ line(@centerx, @centery - 102, @centerx, @centery - 95)
42
+ line(@centerx - 102, @centery, @centerx - 95, @centery)
43
+ line(@centerx + 95, @centery, @centerx + 102, @centery)
44
+ line(@centerx, @centery + 95, @centerx, @centery + 102)
45
+ end
46
+
47
+ def clock_hand(time, sw, unit = 30, color = black)
48
+ radius_local = unit == 30 ? @radius : @radius - 15
49
+ x = radius_local * Math.sin(time * Math::PI / unit)
50
+ y = radius_local * Math.cos(time * Math::PI / unit)
51
+ stroke color
52
+ strokewidth sw
53
+ line(@centerx, @centery, @centerx + x, @centery - y)
54
+ end
55
+ end