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.
- checksums.yaml +4 -4
- data/bin/shoes-stub +8 -0
- data/lib/shoes/samples.rb +8 -0
- data/samples/README +122 -0
- data/samples/avatar.png +0 -0
- data/samples/blue-box.png +0 -0
- data/samples/class-book.yaml +387 -0
- data/samples/class_book.rb +46 -0
- data/samples/cy.png +0 -0
- data/samples/expert_definr.rb +24 -0
- data/samples/expert_funnies.rb +60 -0
- data/samples/expert_game_of_life.rb +224 -0
- data/samples/expert_irb.rb +109 -0
- data/samples/expert_minesweeper.rb +272 -0
- data/samples/expert_othello.rb +323 -0
- data/samples/expert_pong.rb +69 -0
- data/samples/expert_snake.rb +88 -0
- data/samples/expert_tankspank.rb +425 -0
- data/samples/expert_tetris.rb +322 -0
- data/samples/good_arc.rb +51 -0
- data/samples/good_bounce.rb +34 -0
- data/samples/good_clock.rb +55 -0
- data/samples/good_displace.rb +99 -0
- data/samples/good_follow.rb +27 -0
- data/samples/good_image_dl.rb +13 -0
- data/samples/good_potato_chopping.rb +23 -0
- data/samples/good_psychidelic_circles.rb +73 -0
- data/samples/good_reminder.rb +163 -0
- data/samples/good_vjot.rb +65 -0
- data/samples/lib/require_me.rb +6 -0
- data/samples/loogink.png +0 -0
- data/samples/menu-corner1.png +0 -0
- data/samples/menu-corner2.png +0 -0
- data/samples/menu-gray.png +0 -0
- data/samples/menu-left.png +0 -0
- data/samples/menu-right.png +0 -0
- data/samples/menu-top.png +0 -0
- data/samples/nks_booklist.rb +25 -0
- data/samples/nks_breadsticks.rb +8 -0
- data/samples/nks_dancing_circle.rb +14 -0
- data/samples/nks_dictionary.rb +24 -0
- data/samples/nks_edit_box.rb +5 -0
- data/samples/nks_edit_line.rb +7 -0
- data/samples/nks_notes.rb +16 -0
- data/samples/nks_poem.rb +23 -0
- data/samples/nks_self.rb +7 -0
- data/samples/nks_text_sizes.rb +11 -0
- data/samples/nks_trurl.rb +6 -0
- data/samples/potato_chopping/1258_s001.gif +0 -0
- data/samples/potato_chopping/1258_s002.gif +0 -0
- data/samples/potato_chopping/1258_s003.gif +0 -0
- data/samples/potato_chopping/1258_s004.gif +0 -0
- data/samples/potato_chopping/1258_s005.gif +0 -0
- data/samples/potato_chopping/1258_s006.gif +0 -0
- data/samples/potato_chopping/1258_s007.gif +0 -0
- data/samples/potato_chopping/1258_s008.gif +0 -0
- data/samples/potato_chopping/1258_s009.gif +0 -0
- data/samples/potato_chopping/1258_s010.gif +0 -0
- data/samples/potato_chopping/1258_s011.gif +0 -0
- data/samples/potato_chopping/1258_s012.gif +0 -0
- data/samples/potato_chopping/1258_s013.gif +0 -0
- data/samples/potato_chopping/1258_s014.gif +0 -0
- data/samples/potato_chopping/1258_s015.gif +0 -0
- data/samples/potato_chopping/1258_s016.gif +0 -0
- data/samples/potato_chopping/1258_s017.gif +0 -0
- data/samples/potato_chopping/1258_s018.gif +0 -0
- data/samples/potato_chopping/1258_s019.gif +0 -0
- data/samples/potato_chopping/1258_s020.gif +0 -0
- data/samples/potato_chopping/1258_s021.gif +0 -0
- data/samples/potato_chopping/1258_s022.gif +0 -0
- data/samples/potato_chopping/1258_s023.gif +0 -0
- data/samples/potato_chopping/1258_s024.gif +0 -0
- data/samples/potato_chopping/1258_s025.gif +0 -0
- data/samples/potato_chopping/1258_s026.gif +0 -0
- data/samples/potato_chopping/1258_s027.gif +0 -0
- data/samples/potato_chopping/1258_s028.gif +0 -0
- data/samples/potato_chopping/1258_s029.gif +0 -0
- data/samples/potato_chopping/1258_s030.gif +0 -0
- data/samples/potato_chopping/1258_s031.gif +0 -0
- data/samples/potato_chopping/1258_s032.gif +0 -0
- data/samples/potato_chopping/1258_s033.gif +0 -0
- data/samples/potato_chopping/1258_s034.gif +0 -0
- data/samples/potato_chopping/1258_s035.gif +0 -0
- data/samples/potato_chopping/1258_s036.gif +0 -0
- data/samples/potato_chopping/1258_s037.gif +0 -0
- data/samples/potato_chopping/1258_s038.gif +0 -0
- data/samples/potato_chopping/1258_s039.gif +0 -0
- data/samples/potato_chopping/1258_s040.gif +0 -0
- data/samples/potato_chopping/1258_s041.gif +0 -0
- data/samples/potato_chopping/1258_s042.gif +0 -0
- data/samples/potato_chopping/1258_s043.gif +0 -0
- data/samples/potato_chopping/1258_s044.gif +0 -0
- data/samples/potato_chopping/1258_s045.gif +0 -0
- data/samples/potato_chopping/1258_s046.gif +0 -0
- data/samples/potato_chopping/1258_s047.gif +0 -0
- data/samples/potato_chopping/1258_s048.gif +0 -0
- data/samples/potato_chopping/1258_s049.gif +0 -0
- data/samples/potato_chopping/1258_s050.gif +0 -0
- data/samples/potato_chopping/1258_s051.gif +0 -0
- data/samples/potato_chopping/1258_s052.gif +0 -0
- data/samples/potato_chopping/1258_s053.gif +0 -0
- data/samples/potato_chopping/1258_s054.gif +0 -0
- data/samples/potato_chopping/1258_s055.gif +0 -0
- data/samples/potato_chopping/1258_s056.gif +0 -0
- data/samples/potato_chopping/1258_s057.gif +0 -0
- data/samples/potato_chopping/1258_s058.gif +0 -0
- data/samples/potato_chopping/1258_s059.gif +0 -0
- data/samples/red-box.png +0 -0
- data/samples/shape_arc_to.rb +10 -0
- data/samples/simple-form.shy +0 -0
- data/samples/simple_accordion.rb +98 -0
- data/samples/simple_alert.rb +10 -0
- data/samples/simple_altered_para.rb +11 -0
- data/samples/simple_anim_shapes.rb +18 -0
- data/samples/simple_anim_text.rb +14 -0
- data/samples/simple_animate.rb +12 -0
- data/samples/simple_arc.rb +25 -0
- data/samples/simple_attach.rb +26 -0
- data/samples/simple_border_image.rb +9 -0
- data/samples/simple_borderless.rb +4 -0
- data/samples/simple_bounce.rb +27 -0
- data/samples/simple_breadsticks.rb +11 -0
- data/samples/simple_breadsticks2.rb +11 -0
- data/samples/simple_brightness_transitions.rb +16 -0
- data/samples/simple_button_animate.rb +17 -0
- data/samples/simple_buttons.rb +4 -0
- data/samples/simple_calc.rb +67 -0
- data/samples/simple_calc_2.rb +49 -0
- data/samples/simple_clipboard.rb +17 -0
- data/samples/simple_color_selector.rb +11 -0
- data/samples/simple_color_transitions.rb +12 -0
- data/samples/simple_concentric_circles.rb +9 -0
- data/samples/simple_console.rb +12 -0
- data/samples/simple_control_sizes.rb +25 -0
- data/samples/simple_count_and_draw.rb +19 -0
- data/samples/simple_curve.rb +34 -0
- data/samples/simple_dialogs.rb +33 -0
- data/samples/simple_dialogs_outside.rb +17 -0
- data/samples/simple_displace.rb +16 -0
- data/samples/simple_downloader.rb +29 -0
- data/samples/simple_draw.rb +16 -0
- data/samples/simple_editor.rb +30 -0
- data/samples/simple_face.rb +15 -0
- data/samples/simple_flashing.rb +22 -0
- data/samples/simple_flow_wrap.rb +12 -0
- data/samples/simple_font.rb +18 -0
- data/samples/simple_form.rb +30 -0
- data/samples/simple_fullscreen.rb +5 -0
- data/samples/simple_gradient_shapes.rb +23 -0
- data/samples/simple_guess_game.rb +30 -0
- data/samples/simple_image_as_stroke.rb +22 -0
- data/samples/simple_image_fill.rb +13 -0
- data/samples/simple_image_stroke.rb +13 -0
- data/samples/simple_info.rb +10 -0
- data/samples/simple_iterated_content.rb +8 -0
- data/samples/simple_keypress.rb +15 -0
- data/samples/simple_logo_display.rb +15 -0
- data/samples/simple_loogink_cy.rb +33 -0
- data/samples/simple_lorem_ipsum.rb +19 -0
- data/samples/simple_manual.rb +5 -0
- data/samples/simple_menu.rb +42 -0
- data/samples/simple_mouse_follow.rb +9 -0
- data/samples/simple_oval.rb +6 -0
- data/samples/simple_polygon_line.rb +19 -0
- data/samples/simple_position_as_we_go.rb +10 -0
- data/samples/simple_progress_bar.rb +15 -0
- data/samples/simple_random_bubbles.rb +15 -0
- data/samples/simple_require.rb +9 -0
- data/samples/simple_sample_executor.rb +7 -0
- data/samples/simple_sample_executor_all.rb +14 -0
- data/samples/simple_sesame_street_shoes.rb +6 -0
- data/samples/simple_shoes_intro.rb +22 -0
- data/samples/simple_slide.rb +57 -0
- data/samples/simple_stack_flow_buttons.rb +16 -0
- data/samples/simple_stripes.rb +9 -0
- data/samples/simple_system_background.rb +5 -0
- data/samples/simple_text_movement.rb +8 -0
- data/samples/simple_tictactoe.rb +224 -0
- data/samples/simple_timer.rb +16 -0
- data/samples/simple_translate.rb +10 -0
- data/samples/simple_visibility.rb +20 -0
- 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
|