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,69 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Pong in Shoes
4
+ # a clone of http://billmill.org/pong.html
5
+ # and shoes is at http://shoooes.net
6
+ #
7
+ # This is just for kicks -- I'm very fond of NodeBox as well.
8
+ #
9
+ # There's a slightly different approach in Shoes: rather than
10
+ # redrawing the shapes, you can move the shapes around as objects.
11
+ # Yeah, see, notice how @you, @comp and @ball are used.
12
+ #
13
+ Shoes.app width: 400, height: 400, resizable: false do
14
+ paddle_size = 75
15
+ ball_diameter = 20
16
+ vx = 3
17
+ vy = 4
18
+ compuspeed = 10
19
+ bounce = 1.2
20
+
21
+ # set up the playing board
22
+ nostroke && background(white)
23
+ @ball = oval 0, 0, ball_diameter, fill: "#9B7"
24
+ @you, @comp = [app.height - 4, 0].map { |y| rect 0, y, paddle_size, 4, curve: 2 }
25
+
26
+ # animates at 40 frames per second
27
+ @anim = animate 40 do
28
+ # check for game over
29
+ if (@ball.top + ball_diameter).negative? || @ball.top > app.height
30
+ para strong("GAME OVER", size: 32), "\n",
31
+ @ball.top.negative? ? "You win!" : "Computer wins", top: 140, align: 'center'
32
+ @ball.hide && @anim.stop
33
+ end
34
+
35
+ # move the @you paddle, following the mouse
36
+ @you.left = mouse[1] - (paddle_size / 2)
37
+ nx = (@ball.left + vx).to_i
38
+ ny = (@ball.top + vy).to_i
39
+
40
+ # move the @comp paddle, speed based on `compuspeed` variable
41
+ @comp.left +=
42
+ if nx + (ball_diameter / 2) > @comp.left + paddle_size
43
+ compuspeed
44
+ elsif nx < @comp.left
45
+ -compuspeed
46
+ else 0
47
+ end
48
+
49
+ # if the @you paddle hits the ball
50
+ if ny + ball_diameter > app.height && vy.positive? &&
51
+ (0..paddle_size).cover?(nx + (ball_diameter / 2) - @you.left)
52
+ vx = (nx - @you.left - (paddle_size / 2)) * 0.25
53
+ vy = -vy * bounce
54
+ ny = app.height - ball_diameter
55
+ end
56
+
57
+ # if the @comp paddle hits the ball
58
+ if ny.negative? && vy.negative? &&
59
+ (0..paddle_size).cover?(nx + (ball_diameter / 2) - @comp.left)
60
+ vx = (nx - @comp.left - (paddle_size / 2)) * 0.25
61
+ vy = -vy * bounce
62
+ ny = 0
63
+ elsif nx + ball_diameter > app.width || nx.negative?
64
+ vx = -vx
65
+ end
66
+
67
+ @ball.move nx, ny
68
+ end
69
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+ Shoes.app title: 'Snake Game v0.1' do
3
+ def game_start
4
+ @score = para 'Score:', stroke: white
5
+ @pos = {up: [0, -10], down: [0, 10], left: [-10, 0], right: [10, 0]}
6
+ @rx = proc { 20 + 10 * rand(56) }
7
+ @ry = proc { 40 + 10 * rand(44) }
8
+
9
+ create_food
10
+
11
+ create_bricks
12
+
13
+ create_initial_snake
14
+
15
+ dir = :left
16
+ @run = animate 5 do
17
+ check_food
18
+ go dir
19
+ @score.text = "Score: #{@snake.length * 10}"
20
+ brick? @snake[0]
21
+ end
22
+ keypress { |k| dir = k if @pos.keys.include? k }
23
+ end
24
+
25
+ def go(k)
26
+ x, y = @pos[k]
27
+ @snake.unshift @snake.pop
28
+ n = @snake.length > 1 ? 1 : 0
29
+ @snake[0].move @snake[n].left + x, @snake[n].top + y
30
+ @snake[0].style stroke: red
31
+ @snake[1].style stroke: white if n.positive?
32
+ end
33
+
34
+ def check_food
35
+ (@snake << rect(0, 0, 10, 10)) if eat? @snake[0]
36
+ end
37
+
38
+ def eat?(s)
39
+ @foods.each do |f|
40
+ if f.left == s.left && f.top == s.top
41
+ f.move @rx[], @ry[]
42
+ return true
43
+ end
44
+ end
45
+ false
46
+ end
47
+
48
+ def brick?(s)
49
+ @bricks.each do |b|
50
+ if (b.left == s.left) && (b.top == s.top)
51
+ @run.remove
52
+ alert 'Game Over. '
53
+ end
54
+ end
55
+ end
56
+
57
+ def create_food
58
+ @foods = []
59
+ stroke lime
60
+ 50.times { @foods << rect(@rx[], @ry[], 10, 10) }
61
+ end
62
+
63
+ def create_bricks
64
+ @bricks = []
65
+ stroke deepskyblue
66
+ fill blue
67
+
68
+ 50.times { @bricks << rect(@rx[], @ry[], 10, 10) }
69
+
70
+ 20.step(570, 10) { |n| @bricks << rect(n, 40, 10, 10) << rect(n, 470, 10, 10) }
71
+
72
+ 40.step(470, 10) { |n| @bricks << rect(10, n, 10, 10) << rect(570, n, 10, 10) }
73
+ end
74
+
75
+ def create_initial_snake
76
+ @snake = []
77
+ stroke white
78
+ nofill
79
+
80
+ @snake << rect(300, 100, 10, 10)
81
+
82
+ @snake[0].style stroke: red
83
+ end
84
+
85
+ background black
86
+
87
+ game_start
88
+ end
@@ -0,0 +1,425 @@
1
+ # frozen_string_literal: true
2
+ # Tankspank
3
+ # kevin conner
4
+ # connerk@gmail.com
5
+ # version 3, 13 March 2008
6
+ # this code is free, do what you like with it!
7
+
8
+ WIDTH = 700
9
+ HEIGHT = 500
10
+ CAMERA_TIGHTNESS = 0.1
11
+
12
+ module Collisions
13
+ def contains?(x, y)
14
+ !(x < west || x > east || y < north || y > south)
15
+ end
16
+
17
+ def intersects?(other)
18
+ !(other.east < west || other.west > east ||
19
+ other.south < north || other.north > south)
20
+ end
21
+ end
22
+
23
+ class Building
24
+ include Collisions
25
+
26
+ attr_reader :west, :east, :north, :south
27
+
28
+ def initialize(west, east, north, south)
29
+ @west = west
30
+ @east = east
31
+ @north = north
32
+ @south = south
33
+ @top = 1.1 + rand(3) * 0.15
34
+ @bottom = 1.0
35
+
36
+ color = (1..3).collect { 0.2 + 0.4 * rand }
37
+ color << 0.9
38
+ @stroke = Opp.app.rgb(*color)
39
+ color[-1] = 0.3
40
+ @fill = Opp.app.rgb(*color)
41
+ end
42
+
43
+ def draw
44
+ Opp.app.stroke @stroke
45
+ Opp.app.fill @fill
46
+ Opp.draw_opp_box(@west, @east, @north, @south, @top, @bottom)
47
+ end
48
+ end
49
+
50
+ module Guidance
51
+ def guidance_system(x, y, dest_x, dest_y, angle)
52
+ vx = dest_x - x
53
+ vy = dest_y - y
54
+ if vx.abs < 0.1 && (vy.abs <= 0.1)
55
+ yield 0, 0
56
+ else
57
+ length = Math.sqrt(vx * vx + vy * vy)
58
+ vx /= length
59
+ vy /= length
60
+ ax = Math.cos(angle)
61
+ ay = Math.sin(angle)
62
+ cos_between = vx * ax + vy * ay
63
+ sin_between = vx * -ay + vy * ax
64
+ yield sin_between, cos_between
65
+ end
66
+ end
67
+ end
68
+
69
+ module Life
70
+ attr_reader :health
71
+ def dead?
72
+ @health.zero?
73
+ end
74
+
75
+ def hurt(damage)
76
+ @health = [@health - damage, 0].max
77
+ end
78
+ end
79
+
80
+ class Tank
81
+ include Collisions
82
+ include Guidance
83
+ include Life
84
+ # ^ sounds like insurance
85
+
86
+ COLLIDE_SIZE = 15
87
+
88
+ def west
89
+ @x - COLLIDE_SIZE
90
+ end
91
+
92
+ def east
93
+ @x + COLLIDE_SIZE
94
+ end
95
+
96
+ def north
97
+ @y - COLLIDE_SIZE
98
+ end
99
+
100
+ def south
101
+ @y + COLLIDE_SIZE
102
+ end
103
+
104
+ attr_reader :x, :y
105
+
106
+ def initialize
107
+ @x = 0
108
+ @y = -125
109
+ @last_x = @x
110
+ @last_y = @y
111
+ @tank_angle = 0.0
112
+ @dest_x = 0
113
+ @dest_y = 0
114
+ @acceleration = 0.0
115
+ @speed = 0.0
116
+ @moving = false
117
+
118
+ @aim_angle = 0.0
119
+ @target_x = 0
120
+ @target_y = 0
121
+ @aimed = false
122
+
123
+ @health = 100
124
+ end
125
+
126
+ def set_destination
127
+ @dest_x = @target_x
128
+ @dest_y = @target_y
129
+ @moving = true
130
+ end
131
+
132
+ def fire
133
+ Opp.add_shell Shell.new(@x + 30 * Math.cos(@aim_angle),
134
+ @y + 30 * Math.sin(@aim_angle), @aim_angle)
135
+ end
136
+
137
+ def update(_button, mouse_x, mouse_y)
138
+ @target_x = mouse_x
139
+ @target_y = mouse_y
140
+
141
+ if @moving
142
+ guidance_system @x, @y, @dest_x, @dest_y, @tank_angle do |direction, on_target|
143
+ turn direction
144
+ @acceleration = on_target * 0.25
145
+ end
146
+
147
+ distance = Math.sqrt((@dest_x - @x)**2 + (@dest_y - @y)**2)
148
+ @moving = false if distance < 50
149
+ else
150
+ @acceleration = 0.0
151
+ end
152
+
153
+ guidance_system @x, @y, @target_x, @target_y, @aim_angle do |direction, on_target|
154
+ aim direction
155
+ @aimed = on_target > 0.98
156
+ end
157
+
158
+ integrity = @health / 100.0 # the more hurt you are, the slower you go
159
+ @speed = [[@speed + @acceleration, 5.0 * integrity].min, -3.0 * integrity].max
160
+ @speed *= 0.9 unless @moving
161
+
162
+ @last_x = @x
163
+ @last_y = @y
164
+ @x += @speed * Math.cos(@tank_angle)
165
+ @y += @speed * Math.sin(@tank_angle)
166
+ end
167
+
168
+ def collide_and_stop
169
+ @x = @last_x
170
+ @y = @last_y
171
+ hurt @speed.abs * 3 + 5
172
+ @speed = 0
173
+ @moving = false
174
+ end
175
+
176
+ def turn(direction)
177
+ @tank_angle += [[-0.03, direction].max, 0.03].min
178
+ end
179
+
180
+ def aim(direction)
181
+ @aim_angle += [[-0.1, direction].max, 0.1].min
182
+ end
183
+
184
+ def draw
185
+ Opp.app.stroke Opp.app.blue
186
+ Opp.app.fill Opp.app.blue(0.4)
187
+ Opp.draw_opp_rect @x - 20, @x + 20, @y - 15, @y + 15, 1.05, @tank_angle
188
+ # Opp.draw_opp_box @x - 20, @x + 20, @y - 20, @y + 20, 1.03, 1.0
189
+ Opp.draw_opp_rect @x - 10, @x + 10, @y - 7, @y + 7, 1.05, @aim_angle
190
+ x, _unused1, y, _unused2 = Opp.project(@x, 0, @y, 0, 1.05)
191
+ Opp.app.line x, y, x + 25 * Math.cos(@aim_angle), y + 25 * Math.sin(@aim_angle)
192
+
193
+ Opp.app.stroke Opp.app.red
194
+ Opp.app.fill Opp.app.red(@aimed ? 0.4 : 0.1)
195
+ Opp.draw_opp_oval @target_x - 10, @target_x + 10, @target_y - 10, @target_y + 10, 1.00
196
+
197
+ if @moving
198
+ Opp.app.stroke Opp.app.green
199
+ Opp.app.fill Opp.app.green(0.2)
200
+ Opp.draw_opp_oval @dest_x - 20, @dest_x + 20, @dest_y - 20, @dest_y + 20, 1.00
201
+ end
202
+ end
203
+ end
204
+
205
+ class Shell
206
+ attr_reader :x, :y
207
+
208
+ def initialize(x, y, angle)
209
+ @x = x
210
+ @y = y
211
+ @angle = angle
212
+ @speed = 10.0
213
+ end
214
+
215
+ def update
216
+ @x += @speed * Math.cos(@angle)
217
+ @y += @speed * Math.sin(@angle)
218
+ end
219
+
220
+ def draw
221
+ Opp.app.stroke Opp.app.red
222
+ Opp.app.fill Opp.app.red(0.1)
223
+ Opp.draw_opp_box @x - 2, @x + 2, @y - 2, @y + 2, 1.05, 1.04
224
+ end
225
+ end
226
+
227
+ class Opp
228
+ def self.app
229
+ @app
230
+ end
231
+
232
+ def self.app=(app)
233
+ @app = app
234
+ end
235
+
236
+ def self.new_game
237
+ @offset_x = 0
238
+ @offset_y = 0
239
+ @buildings = [
240
+ [-1000, -750, -750, -250],
241
+ [-500, 250, -750, -250],
242
+ [500, 1000, -750, -500],
243
+ [750, 1250, -250, 0],
244
+ [750, 1250, 250, 750],
245
+ [250, 500, 0, 750],
246
+ [-250, 0, 0, 500],
247
+ [-500, 0, 750, 1000],
248
+ [-1000, -500, 0, 500],
249
+ [400, 600, -350, -150]
250
+ ].collect { |p| Building.new(*p) }
251
+ @shells = []
252
+ @boundary = [-1250, 1500, -1250, 1250]
253
+ @tank = Tank.new
254
+ @center_x = Opp.app.width / 2
255
+ @center_y = Opp.app.height / 2
256
+ end
257
+
258
+ def self.tank
259
+ @tank
260
+ end
261
+
262
+ def self.read_input
263
+ @input = Opp.app.mouse
264
+ end
265
+
266
+ def self.update_scene
267
+ button, x, y = @input
268
+ x += @offset_x - @center_x
269
+ y += @offset_y - @center_y
270
+
271
+ @tank.update(button, x, y) unless @tank.dead?
272
+ @buildings.each do |b|
273
+ @tank.collide_and_stop if b.intersects? @tank
274
+ end
275
+
276
+ @shells.each(&:update)
277
+ @buildings.each do |b|
278
+ @shells.reject! do |s|
279
+ b.contains?(s.x, s.y)
280
+ end
281
+ end
282
+ # collide shells with tanks -- don't need this until there are enemy tanks
283
+ # @shells.reject! do |s|
284
+ # @tank.contains?(s.x, s.y)
285
+ # end
286
+
287
+ Opp.app.clear do
288
+ @offset_x += CAMERA_TIGHTNESS * (@tank.x - @offset_x)
289
+ @offset_y += CAMERA_TIGHTNESS * (@tank.y - @offset_y)
290
+
291
+ Opp.app.background Opp.app.black
292
+ @center_x = Opp.app.width / 2
293
+ @center_y = Opp.app.height / 2
294
+
295
+ Opp.app.stroke Opp.app.red(0.9)
296
+ Opp.app.nofill
297
+ draw_opp_box(*(@boundary + [1.1, 1.0, false]))
298
+
299
+ @tank.draw
300
+ @shells.each(&:draw)
301
+ @buildings.each(&:draw)
302
+ end
303
+ end
304
+
305
+ def self.add_shell(shell)
306
+ @shells << shell
307
+ @shells.shift if @shells.size > 10
308
+ end
309
+
310
+ def self.project(left, right, top, bottom, depth)
311
+ [left, right].collect { |x| @center_x + depth * (x - @offset_x) } +
312
+ [top, bottom].collect { |y| @center_y + depth * (y - @offset_y) }
313
+ end
314
+
315
+ # here "front" and "back" push the rect into and out of the window.
316
+ # 1.0 means your x and y units are pixels on the surface.
317
+ # greater than that brings the box closer. less pushes it back. 0.0 => infinity.
318
+ # the front will be filled but the rest is wireframe only.
319
+ def self.draw_opp_box(left, right, top, bottom, front, back, occlude = true)
320
+ near_left, near_right, near_top, near_bottom = project(left, right, top, bottom, front)
321
+ far_left, far_right, far_top, far_bottom = project(left, right, top, bottom, back)
322
+
323
+ # determine which sides of the box are visible
324
+ if occlude
325
+ draw_left = @center_x < near_left
326
+ draw_right = near_right < @center_x
327
+ draw_top = @center_y < near_top
328
+ draw_bottom = near_bottom < @center_y
329
+ else
330
+ draw_left, draw_right, draw_top, draw_bottom = [true] * 4
331
+ end
332
+
333
+ # draw lines for the back edges
334
+ Opp.app.line far_left, far_top, far_right, far_top if draw_top
335
+ Opp.app.line far_left, far_bottom, far_right, far_bottom if draw_bottom
336
+ Opp.app.line far_left, far_top, far_left, far_bottom if draw_left
337
+ Opp.app.line far_right, far_top, far_right, far_bottom if draw_right
338
+
339
+ # draw lines to connect the front and back
340
+ Opp.app.line near_left, near_top, far_left, far_top if draw_left || draw_top
341
+ Opp.app.line near_right, near_top, far_right, far_top if draw_right || draw_top
342
+ Opp.app.line near_left, near_bottom, far_left, far_bottom if draw_left || draw_bottom
343
+ Opp.app.line near_right, near_bottom, far_right, far_bottom if draw_right || draw_bottom
344
+
345
+ # draw the front, filled
346
+ Opp.app.rect near_left, near_top, near_right - near_left, near_bottom - near_top
347
+ end
348
+
349
+ def self.draw_opp_rect(left, right, top, bottom, depth, angle, _with_x = false)
350
+ pl, pr, pt, pb = project(left, right, top, bottom, depth)
351
+ cos = Math.cos(angle)
352
+ sin = Math.sin(angle)
353
+ cx = (pr + pl) / 2.0
354
+ cy = (pb + pt) / 2.0
355
+ points = [[pl, pt], [pr, pt], [pr, pb], [pl, pb]].collect do |x, y|
356
+ [cx + (x - cx) * cos - (y - cy) * sin,
357
+ cy + (x - cx) * sin + (y - cy) * cos]
358
+ end
359
+
360
+ Opp.app.line(*(points[0] + points[1]))
361
+ Opp.app.line(*(points[1] + points[2]))
362
+ Opp.app.line(*(points[2] + points[3]))
363
+ Opp.app.line(*(points[3] + points[0]))
364
+ end
365
+
366
+ def self.draw_opp_oval(left, right, top, bottom, depth)
367
+ pl, pr, pt, pb = project(left, right, top, bottom, depth)
368
+ Opp.app.oval(pl, pt, pr - pl, pb - pt)
369
+ end
370
+
371
+ def self.draw_opp_plane(x1, y1, x2, y2, front, back, stroke_color)
372
+ near_x1, near_x2, near_y1, near_y2 = project(x1, x2, y1, y2, front)
373
+ far_x1, far_x2, far_y1, far_y2 = project(x1, x2, y1, y2, back)
374
+
375
+ Opp.app.stroke stroke_color
376
+
377
+ Opp.app.line far_x1, far_y1, far_x2, far_y2
378
+ Opp.app.line far_x1, far_y1, near_x1, near_y1
379
+ Opp.app.line far_x2, far_y2, near_x2, near_y2
380
+ Opp.app.line near_x1, near_y1, near_x2, near_y2
381
+ end
382
+ end
383
+
384
+ Shoes.app width: WIDTH, height: HEIGHT do
385
+ Opp.app = self
386
+
387
+ Opp.new_game
388
+ @playing = true
389
+
390
+ keypress do |key|
391
+ if @playing
392
+ if (key == "1") || (key == "z")
393
+ Opp.tank.set_destination
394
+ elsif (key == "2") || (key == "x") || (key == " ")
395
+ Opp.tank.fire
396
+ end
397
+ elsif key == "n"
398
+ Opp.new_game
399
+ @playing = true
400
+ end
401
+ end
402
+
403
+ click do |button|
404
+ if @playing
405
+ if button == 1
406
+ Opp.tank.set_destination
407
+ else
408
+ Opp.tank.fire
409
+ end
410
+ end
411
+ end
412
+
413
+ animate(60) do
414
+ Opp.read_input if @playing
415
+ Opp.update_scene
416
+
417
+ @playing = false if Opp.tank.dead?
418
+ unless @playing
419
+ stack do
420
+ banner "Game Over", stroke: white, margin: 10
421
+ caption "learn to drive!", stroke: white, margin: 20
422
+ end
423
+ end
424
+ end
425
+ end