physicist 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +6 -0
- data/bin/physicist +4 -1
- data/lib/physicist/body.rb +222 -0
- data/lib/physicist/laboratory/app.rb +104 -0
- data/lib/physicist/laboratory/commands/create_scientist.rb +7 -0
- data/lib/physicist/laboratory/commands/jump_scientist.rb +7 -0
- data/lib/physicist/laboratory/commands/move_scientist.rb +7 -0
- data/lib/physicist/laboratory/events/scientist_created_event.rb +7 -0
- data/lib/physicist/laboratory/events/scientist_updated_event.rb +7 -0
- data/lib/physicist/laboratory/events/space_created_event.rb +7 -0
- data/lib/physicist/laboratory/handlers/create_scientist_handler.rb +34 -0
- data/lib/physicist/laboratory/handlers/jump_scientist_handler.rb +10 -0
- data/lib/physicist/laboratory/handlers/move_scientist_handler.rb +10 -0
- data/lib/physicist/laboratory/listeners/scientist_created_event_listener.rb +15 -0
- data/lib/physicist/laboratory/listeners/scientist_updated_event_listener.rb +15 -0
- data/lib/physicist/laboratory/listeners/space_created_event_listener.rb +9 -0
- data/lib/physicist/laboratory/models/scientist.rb +84 -0
- data/lib/physicist/laboratory/models/space.rb +14 -0
- data/lib/physicist/laboratory/screen.rb +52 -0
- data/lib/physicist/laboratory/view.rb +27 -0
- data/lib/physicist/laboratory/views/scientist_view.rb +57 -0
- data/lib/physicist/laboratory/views/workspace_view.rb +18 -0
- data/lib/physicist/simple_body.rb +26 -0
- data/lib/physicist/version.rb +1 -1
- data/lib/physicist.rb +5 -119
- data/media/images/cosmos.jpg +0 -0
- data/media/images/tiles.png +0 -0
- data/media/images/walk.png +0 -0
- data/spec/physicist_spec.rb +5 -5
- metadata +26 -3
- data/lib/physicist/laboratory.rb +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a8e6b5748e0166acbf9e69a28946931999a82817
|
4
|
+
data.tar.gz: f1abc35f92cf0157ffcd366602d0b5d722438930
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6aab3cf912156901fa5051c0b2259feedc77bb960bedc59c049fadc4744e799d6d2c2e6ce7bc6222d0be2e80b6368eead4d9c8bf34d471d3c4c2710d90576f7e
|
7
|
+
data.tar.gz: 74b51b92552615d50c7d7ab5f9f44ee43f3139a9fe897ca92913562285efb2976d68a2be5b07c65551d6cbf5dab9d7bb10d080be7054a229bc870efebdcb0c73
|
data/Gemfile
CHANGED
data/bin/physicist
CHANGED
@@ -5,10 +5,13 @@ if File.directory?(File.join(root,'.git'))
|
|
5
5
|
Dir.chdir(root) do
|
6
6
|
begin
|
7
7
|
require 'bundler/setup'
|
8
|
+
require 'physicist'
|
9
|
+
require 'physicist/laboratory/app'
|
10
|
+
Physicist::Laboratory::App.kickstart!
|
8
11
|
rescue LoadError => e
|
9
12
|
warn e.message
|
10
13
|
warn "Run `gem install bundler` to install Bundler"
|
11
|
-
exit
|
14
|
+
exit(-1)
|
12
15
|
end
|
13
16
|
end
|
14
17
|
end
|
@@ -0,0 +1,222 @@
|
|
1
|
+
module Physicist
|
2
|
+
class Body
|
3
|
+
attr_reader :position, :velocity, :t0, :dimensions
|
4
|
+
|
5
|
+
def initialize(position:, velocity:, t0:, dimensions:)
|
6
|
+
@position = position
|
7
|
+
@velocity = velocity
|
8
|
+
@dimensions = dimensions
|
9
|
+
@t0 = t0
|
10
|
+
end
|
11
|
+
|
12
|
+
def width
|
13
|
+
dimensions[0]
|
14
|
+
end
|
15
|
+
|
16
|
+
def height
|
17
|
+
dimensions[1]
|
18
|
+
end
|
19
|
+
|
20
|
+
def gravity
|
21
|
+
50.0
|
22
|
+
end
|
23
|
+
|
24
|
+
def friction
|
25
|
+
10.0
|
26
|
+
end
|
27
|
+
|
28
|
+
def at(t, obstacles:[])
|
29
|
+
# p [ :body, at: t, pos: position, vel: velocity ]
|
30
|
+
x0, _ = *position
|
31
|
+
vx0,vy0 = *velocity
|
32
|
+
|
33
|
+
x_speed = vx0.abs
|
34
|
+
sign_x = vx0 > 0.0 ? 1.0 : (vx0 < -0.0 ? -1.0 : 0.0)
|
35
|
+
|
36
|
+
dt = t - t0
|
37
|
+
|
38
|
+
vy = vy0 + (gravity * dt)
|
39
|
+
|
40
|
+
fric = friction * dt
|
41
|
+
x_halted = false
|
42
|
+
|
43
|
+
vx = if (3*fric) < x_speed
|
44
|
+
vx0 + (fric * -sign_x)
|
45
|
+
else
|
46
|
+
x_halted = true
|
47
|
+
x_stopping_distance = (vx0 ** 2) / (3 * friction)
|
48
|
+
0
|
49
|
+
end
|
50
|
+
|
51
|
+
xt,yt,vxt,vyt = deduce_y_coordinate(vy,t,obstacles:obstacles) do |y,_vyt|
|
52
|
+
if x_halted
|
53
|
+
[x0 + (x_stopping_distance * sign_x), y, vx, _vyt]
|
54
|
+
else
|
55
|
+
deduce_x_coordinate(y,vx,t,obstacles:obstacles) do |x,_vxt|
|
56
|
+
[x, y, _vxt, _vyt]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
vxt = 0 if -0.05 < vx && vx < 0.05
|
62
|
+
vyt = 0 if -0.05 < vy && vy < 0.05
|
63
|
+
|
64
|
+
Body.new(
|
65
|
+
position: [xt,yt],
|
66
|
+
velocity: [vxt,vyt],
|
67
|
+
dimensions: dimensions,
|
68
|
+
t0: t
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
def deduce_x_coordinate(y,vx,t,obstacles:,&blk)
|
74
|
+
x0,_ = *position
|
75
|
+
dt = t - t0
|
76
|
+
|
77
|
+
next_x_obstacle = next_obstacle_on_x_axis(y,vx,t,obstacles:obstacles)
|
78
|
+
if next_x_obstacle
|
79
|
+
ox,_ = *next_x_obstacle.position
|
80
|
+
ow,_ = *next_x_obstacle.dimensions
|
81
|
+
|
82
|
+
distance_to_next_x_obstacle =
|
83
|
+
if vx > 0
|
84
|
+
((x0+width) - ox).abs
|
85
|
+
elsif vx < 0
|
86
|
+
((x0) - (ox+ow)).abs
|
87
|
+
end
|
88
|
+
|
89
|
+
distance_travelled_in_x_axis_if_no_obstacles = vx * dt
|
90
|
+
p [ :next_x_obs, at: ox, distance: distance_to_next_x_obstacle, distance_without_obs: distance_travelled_in_x_axis_if_no_obstacles ]
|
91
|
+
# require 'pry'
|
92
|
+
# binding.pry
|
93
|
+
|
94
|
+
if distance_travelled_in_x_axis_if_no_obstacles.abs < distance_to_next_x_obstacle
|
95
|
+
p [ :travel_x_less_than_obs_x ]
|
96
|
+
yield [x0 + (vx*dt), vx]
|
97
|
+
else
|
98
|
+
p [ :travel_x_more_than_obs_x ]
|
99
|
+
if vx > 0
|
100
|
+
yield [next_x_obstacle.position[0]-width, 0]
|
101
|
+
else
|
102
|
+
yield [next_x_obstacle.position[0]+next_x_obstacle.dimensions[0], 0]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
else
|
106
|
+
yield [x0 + (vx*dt), vx]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def deduce_y_coordinate(vy,t,obstacles:,&blk)
|
111
|
+
_,y0 = *position
|
112
|
+
dt = t - t0
|
113
|
+
|
114
|
+
next_y_obstacle = next_obstacle_on_y_axis(vy,t,obstacles:obstacles)
|
115
|
+
|
116
|
+
if next_y_obstacle
|
117
|
+
distance_to_next_y_obstacle =
|
118
|
+
if vy > 0
|
119
|
+
((y0+height) - next_y_obstacle.position[1]).abs
|
120
|
+
else
|
121
|
+
(y0 - (next_y_obstacle.position[1] + next_y_obstacle.dimensions[1])).abs
|
122
|
+
end
|
123
|
+
distance_travelled_in_y_axis_if_no_obstacles = (vy * dt)
|
124
|
+
|
125
|
+
if distance_travelled_in_y_axis_if_no_obstacles.abs < distance_to_next_y_obstacle
|
126
|
+
yield [y0 + (vy * dt), vy ]
|
127
|
+
else
|
128
|
+
if vy > 0
|
129
|
+
yield [next_y_obstacle.position[1] - 1.01, 0] # (height + 0.1), 0]
|
130
|
+
else
|
131
|
+
yield [next_y_obstacle.position[1] + next_y_obstacle.dimensions[1] + 0.1, 0]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
else
|
135
|
+
yield [y0 + (vy * dt), vy]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def next_obstacle_on_x_axis(y,vx,t,obstacles:)
|
140
|
+
x0,_ = *position
|
141
|
+
|
142
|
+
obstacles_along_axis = obstacles.select do |obstacle|
|
143
|
+
_,oy = *obstacle.position
|
144
|
+
_,oh = *obstacle.dimensions
|
145
|
+
|
146
|
+
oy <= y + height && y <= oy + oh
|
147
|
+
end
|
148
|
+
|
149
|
+
obstacles_in_direction_of_movement =
|
150
|
+
if vx > 0
|
151
|
+
obstacles_along_axis.select do |obstacle|
|
152
|
+
ox,_ = *obstacle.position
|
153
|
+
# ow,oh = *obstacle.dimensions
|
154
|
+
|
155
|
+
ox >= x0 + width
|
156
|
+
end
|
157
|
+
elsif vx < 0
|
158
|
+
# require 'pry'
|
159
|
+
# binding.pry
|
160
|
+
obstacles_along_axis.select do |obstacle|
|
161
|
+
ox,_ = *obstacle.position
|
162
|
+
ow,_ = *obstacle.dimensions
|
163
|
+
x0 >= ox + ow
|
164
|
+
# ox + ow >= x0
|
165
|
+
end
|
166
|
+
else
|
167
|
+
[]
|
168
|
+
end
|
169
|
+
|
170
|
+
if obstacles_in_direction_of_movement.any?
|
171
|
+
obstacles_in_direction_of_movement.min_by do |obstacle|
|
172
|
+
ox,_ = *obstacle.position
|
173
|
+
(x0 - ox).abs
|
174
|
+
end
|
175
|
+
else
|
176
|
+
nil
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def next_obstacle_on_y_axis(vy,t,obstacles:)
|
181
|
+
x0,y0 = *position
|
182
|
+
|
183
|
+
# x0 += width/4
|
184
|
+
w = width #/2
|
185
|
+
|
186
|
+
obstacles_along_axis = obstacles.select do |obstacle|
|
187
|
+
ox,_ = *obstacle.position
|
188
|
+
ow,_ = *obstacle.dimensions
|
189
|
+
ox <= x0 + w && x0 <= ox + ow
|
190
|
+
end
|
191
|
+
|
192
|
+
obstacles_in_direction_of_movement =
|
193
|
+
if vy > 0
|
194
|
+
obstacles_along_axis.select do |obstacle|
|
195
|
+
_,oy = *obstacle.position
|
196
|
+
|
197
|
+
oy >= y0 + height
|
198
|
+
end
|
199
|
+
elsif vy < 0
|
200
|
+
obstacles_along_axis.select do |obstacle|
|
201
|
+
_,oy = *obstacle.position
|
202
|
+
_,oh = *obstacle.dimensions
|
203
|
+
|
204
|
+
oy + oh <= y0
|
205
|
+
end
|
206
|
+
else
|
207
|
+
[]
|
208
|
+
end
|
209
|
+
|
210
|
+
if obstacles_in_direction_of_movement
|
211
|
+
obstacles_in_direction_of_movement.min_by do |obstacle|
|
212
|
+
_,oy = *obstacle.position
|
213
|
+
|
214
|
+
# distance to me
|
215
|
+
(y0 - oy).abs
|
216
|
+
end
|
217
|
+
else
|
218
|
+
nil
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require_relative 'screen'
|
2
|
+
require_relative 'view'
|
3
|
+
|
4
|
+
require_relative 'commands/create_scientist'
|
5
|
+
require_relative 'commands/move_scientist'
|
6
|
+
require_relative 'commands/jump_scientist'
|
7
|
+
|
8
|
+
require_relative 'handlers/create_scientist_handler'
|
9
|
+
require_relative 'handlers/move_scientist_handler'
|
10
|
+
require_relative 'handlers/jump_scientist_handler'
|
11
|
+
|
12
|
+
require_relative 'events/scientist_created_event'
|
13
|
+
require_relative 'events/scientist_updated_event'
|
14
|
+
require_relative 'events/space_created_event'
|
15
|
+
|
16
|
+
require_relative 'listeners/scientist_created_event_listener'
|
17
|
+
require_relative 'listeners/scientist_updated_event_listener'
|
18
|
+
require_relative 'listeners/space_created_event_listener'
|
19
|
+
|
20
|
+
require_relative 'models/scientist'
|
21
|
+
require_relative 'models/space'
|
22
|
+
|
23
|
+
require_relative 'views/scientist_view'
|
24
|
+
require_relative 'views/workspace_view'
|
25
|
+
|
26
|
+
module Physicist
|
27
|
+
module Laboratory
|
28
|
+
class App < Joyce::Application
|
29
|
+
viewed_with Physicist::Laboratory::View
|
30
|
+
|
31
|
+
attr_accessor :scientist
|
32
|
+
|
33
|
+
def setup(*)
|
34
|
+
p [ :lab_setup! ]
|
35
|
+
fire(
|
36
|
+
create_scientist(
|
37
|
+
scientist_id: scientist_id,
|
38
|
+
name: "Bill Bye",
|
39
|
+
title: "Science Guy",
|
40
|
+
position: [0,2],
|
41
|
+
velocity: [0,0]
|
42
|
+
)
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
def tick
|
47
|
+
Scientist.all.each(&:tick)
|
48
|
+
|
49
|
+
|
50
|
+
# poll for movement keys...
|
51
|
+
if window.button_down?(Gosu::KbLeft)
|
52
|
+
fire(move_scientist(:left))
|
53
|
+
elsif window.button_down?(Gosu::KbRight)
|
54
|
+
fire(move_scientist(:right))
|
55
|
+
end
|
56
|
+
|
57
|
+
# TODO
|
58
|
+
p [ :check_jump ]
|
59
|
+
if window.button_down?(Gosu::KbUp)
|
60
|
+
p [ :jump! ]
|
61
|
+
fire(jump)
|
62
|
+
else
|
63
|
+
p [ :no_jump! ]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def press(key)
|
68
|
+
if key == Gosu::KbLeft
|
69
|
+
fire(move_scientist(:left))
|
70
|
+
elsif key == Gosu::KbRight
|
71
|
+
fire(move_scientist(:right))
|
72
|
+
end
|
73
|
+
|
74
|
+
if key == Gosu::KbUp
|
75
|
+
fire(jump)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def scientist_view
|
80
|
+
ScientistView.where(scientist_id: scientist_id).first || NullScientistView.new
|
81
|
+
end
|
82
|
+
|
83
|
+
def workspace_view
|
84
|
+
WorkspaceView.where(space_id: scientist_view.space_id).first || NullWorkspaceView.new
|
85
|
+
end
|
86
|
+
|
87
|
+
def create_scientist(*args)
|
88
|
+
CreateScientist.create(*args)
|
89
|
+
end
|
90
|
+
|
91
|
+
def move_scientist(direction)
|
92
|
+
MoveScientist.create(scientist_id: scientist_id, direction: direction)
|
93
|
+
end
|
94
|
+
|
95
|
+
def jump
|
96
|
+
JumpScientist.create(scientist_id: scientist_id)
|
97
|
+
end
|
98
|
+
|
99
|
+
def scientist_id
|
100
|
+
@scientist_id ||= SecureRandom.uuid
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Physicist
|
2
|
+
module Laboratory
|
3
|
+
class CreateScientistHandler
|
4
|
+
def handle(scientist_id:, name:, title:, position:, velocity:)
|
5
|
+
p [ :creating_space ]
|
6
|
+
|
7
|
+
map_data = (
|
8
|
+
[
|
9
|
+
[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ],
|
10
|
+
[ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil ],
|
11
|
+
[ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil ],
|
12
|
+
[ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil ],
|
13
|
+
[ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil ],
|
14
|
+
[ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil ],
|
15
|
+
[ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil ],
|
16
|
+
[ 1, nil, nil, nil, nil, 2, nil, nil, nil, nil, 1 ],
|
17
|
+
[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ]
|
18
|
+
]
|
19
|
+
)
|
20
|
+
|
21
|
+
space = Space.create(grid_map: map_data)
|
22
|
+
|
23
|
+
p [ :creating_scientist, name: name ]
|
24
|
+
space.create_scientist(
|
25
|
+
id: scientist_id,
|
26
|
+
name: name,
|
27
|
+
title: title,
|
28
|
+
position: position,
|
29
|
+
velocity: velocity
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Physicist
|
2
|
+
module Laboratory
|
3
|
+
class ScientistCreatedEventListener < Metacosm::EventListener
|
4
|
+
def receive(scientist_id:, space_id:, name:, title:, position:, velocity:)
|
5
|
+
ScientistView.create(
|
6
|
+
scientist_id: scientist_id,
|
7
|
+
space_id: space_id,
|
8
|
+
display_name: "#{name} the #{title}",
|
9
|
+
position: position,
|
10
|
+
velocity: velocity
|
11
|
+
)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Physicist
|
2
|
+
module Laboratory
|
3
|
+
class ScientistUpdatedEventListener < Metacosm::EventListener
|
4
|
+
def receive(scientist_id:, position:, velocity:, updated_at:)
|
5
|
+
p [ :scientist_updated, pos: position, vel: velocity ]
|
6
|
+
scientist_view = ScientistView.find_by(scientist_id: scientist_id)
|
7
|
+
scientist_view.update(
|
8
|
+
position: position,
|
9
|
+
velocity: velocity,
|
10
|
+
t0: updated_at
|
11
|
+
)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Physicist
|
2
|
+
module Laboratory
|
3
|
+
# user avatars are 'scientists'
|
4
|
+
class Scientist < Metacosm::Model
|
5
|
+
belongs_to :space
|
6
|
+
|
7
|
+
# attr_accessor :space_id #??
|
8
|
+
attr_accessor :name, :title
|
9
|
+
attr_accessor :position, :velocity
|
10
|
+
attr_accessor :updated_at
|
11
|
+
|
12
|
+
def tick
|
13
|
+
update(
|
14
|
+
position: current.position,
|
15
|
+
velocity: current.velocity,
|
16
|
+
updated_at: Time.now
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
def ground_speed
|
21
|
+
5
|
22
|
+
end
|
23
|
+
|
24
|
+
def max_ground_speed
|
25
|
+
10
|
26
|
+
end
|
27
|
+
|
28
|
+
def leg_strength # ??
|
29
|
+
-12
|
30
|
+
end
|
31
|
+
|
32
|
+
def max_jump_velocity
|
33
|
+
-30
|
34
|
+
end
|
35
|
+
|
36
|
+
def move(direction:)
|
37
|
+
vx,vy = *current.velocity
|
38
|
+
speed = ground_speed
|
39
|
+
dvx = direction == :left ? -speed : speed
|
40
|
+
vxt = vx + dvx
|
41
|
+
return unless vxt.abs < max_ground_speed
|
42
|
+
p [ :move, dir: direction, current: current, dvx: dvx, vxt: vxt ]
|
43
|
+
|
44
|
+
# TODO more specific event?
|
45
|
+
update(
|
46
|
+
position: current.position,
|
47
|
+
velocity: [vxt, vy],
|
48
|
+
updated_at: Time.now
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def jump
|
53
|
+
p [ :jump, current: current ]
|
54
|
+
vx, vy = *current.velocity
|
55
|
+
return if vy.abs > 0.0
|
56
|
+
|
57
|
+
dvy = leg_strength
|
58
|
+
update(
|
59
|
+
position: current.position,
|
60
|
+
velocity: [vx, vy + dvy],
|
61
|
+
updated_at: Time.now
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
def current
|
66
|
+
@body = body.at(Time.now, obstacles: space.obstacles)
|
67
|
+
end
|
68
|
+
|
69
|
+
def body
|
70
|
+
construct_body
|
71
|
+
end
|
72
|
+
|
73
|
+
def construct_body
|
74
|
+
# ...integrate physicist bodies...
|
75
|
+
Physicist::Body.new(
|
76
|
+
position: position,
|
77
|
+
velocity: velocity,
|
78
|
+
t0: updated_at || Time.now,
|
79
|
+
dimensions: [1,1]
|
80
|
+
)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Physicist
|
2
|
+
module Laboratory
|
3
|
+
class Screen < Dedalus::Screen
|
4
|
+
include Dedalus::Elements
|
5
|
+
attr_accessor :scientist, :map_grid, :camera
|
6
|
+
|
7
|
+
def show
|
8
|
+
[
|
9
|
+
Paragraph.new(text: "Welcome to the lab, #{scientist.display_name}!"),
|
10
|
+
Paragraph.new(text: "Pos: #{scientist.current.position}"),
|
11
|
+
Paragraph.new(text: "Vel: #{scientist.current.velocity}"),
|
12
|
+
field
|
13
|
+
]
|
14
|
+
end
|
15
|
+
|
16
|
+
def field
|
17
|
+
SpriteField.new(
|
18
|
+
grid: map_grid,
|
19
|
+
scale: 1.0,
|
20
|
+
camera_location: camera,
|
21
|
+
tiles_path: "media/images/tiles.png",
|
22
|
+
tile_width: 64,
|
23
|
+
tile_height: 64,
|
24
|
+
tile_class: "Dedalus::Elements::MapTile",
|
25
|
+
sprite_map: sprite_map
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
def sprite_map
|
30
|
+
{ scientist.current.position => [avatar_for(scientist)] }
|
31
|
+
end
|
32
|
+
|
33
|
+
def avatar_for(scientist)
|
34
|
+
Dedalus::Elements::Sprite.new(
|
35
|
+
path: 'media/images/walk.png',
|
36
|
+
frame: 0,
|
37
|
+
invert_x: false,
|
38
|
+
asset_width: 64,
|
39
|
+
asset_height: 64,
|
40
|
+
scale: 1.0
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
def heading
|
45
|
+
[
|
46
|
+
Heading.new(text: "[Physics Laboratory]"),
|
47
|
+
Paragraph.new(text: "Hello, #{scientist.name_with_title}")
|
48
|
+
]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Physicist
|
2
|
+
module Laboratory
|
3
|
+
class View < Dedalus::ApplicationView
|
4
|
+
def app_screen
|
5
|
+
Screen.new(
|
6
|
+
scientist: scientist_view,
|
7
|
+
map_grid: application.workspace_view.grid_map,
|
8
|
+
camera: camera_location
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
def scientist_view
|
13
|
+
application.scientist_view
|
14
|
+
end
|
15
|
+
|
16
|
+
def tile_size
|
17
|
+
64
|
18
|
+
end
|
19
|
+
|
20
|
+
def camera_location
|
21
|
+
cx, cy = *scientist_view.current.position
|
22
|
+
mx, my = (window.width / 2) / tile_size, (window.height / 2) / tile_size
|
23
|
+
[ cx - mx, cy - my ]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
module Physicist
|
3
|
+
module Laboratory
|
4
|
+
class ScientistView < Metacosm::View
|
5
|
+
attr_accessor :scientist_id, :space_id
|
6
|
+
attr_accessor :display_name, :position, :velocity, :t0
|
7
|
+
|
8
|
+
after_update {
|
9
|
+
@body = construct_body
|
10
|
+
}
|
11
|
+
|
12
|
+
def current # at(t)
|
13
|
+
@body = body.at(Time.now, obstacles: workspace_view.obstacles)
|
14
|
+
end
|
15
|
+
|
16
|
+
def workspace_view
|
17
|
+
WorkspaceView.find_by(space_id: space_id)
|
18
|
+
end
|
19
|
+
|
20
|
+
def body
|
21
|
+
# ... integrate physicist bodies ...
|
22
|
+
@body ||= construct_body
|
23
|
+
end
|
24
|
+
|
25
|
+
def construct_body
|
26
|
+
Physicist::Body.new(
|
27
|
+
position: position,
|
28
|
+
velocity: velocity,
|
29
|
+
t0: t0 || Time.now,
|
30
|
+
dimensions: [1,1]
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class NullScientistView
|
36
|
+
def display_name
|
37
|
+
'Nohbdy'
|
38
|
+
end
|
39
|
+
|
40
|
+
def position
|
41
|
+
[0,0]
|
42
|
+
end
|
43
|
+
|
44
|
+
def velocity
|
45
|
+
[0,0]
|
46
|
+
end
|
47
|
+
|
48
|
+
def space_id
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def current
|
53
|
+
OpenStruct.new(position: position, velocity: velocity)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Physicist
|
2
|
+
module Laboratory
|
3
|
+
class WorkspaceView < Metacosm::View
|
4
|
+
# has_many :scientist_views
|
5
|
+
attr_accessor :space_id, :grid_map
|
6
|
+
|
7
|
+
def obstacles
|
8
|
+
SimpleBody.collection_from_tiles(grid_map)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class NullWorkspaceView
|
13
|
+
def grid_map
|
14
|
+
[[1,2],[3,4]]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Physicist
|
2
|
+
class SimpleBody
|
3
|
+
attr_reader :position, :dimensions
|
4
|
+
|
5
|
+
def initialize(position:,dimensions:)
|
6
|
+
@position = position
|
7
|
+
@dimensions = dimensions
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.collection_from_tiles(tile_grid)
|
11
|
+
# p [ :assembling_bodies_from_tiles, grid: tile_grid ]
|
12
|
+
simple_bodies = []
|
13
|
+
|
14
|
+
tile_grid.each_with_index do |row, y|
|
15
|
+
row.each_with_index do |cell, x|
|
16
|
+
if cell
|
17
|
+
simple_bodies << new(position: [x,y], dimensions: [1,1])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# p [ bodies: simple_bodies ]
|
23
|
+
simple_bodies
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/physicist/version.rb
CHANGED
data/lib/physicist.rb
CHANGED
@@ -1,120 +1,6 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
module Physicist
|
4
|
-
class SimpleBody
|
5
|
-
attr_reader :position, :dimensions
|
6
|
-
|
7
|
-
def initialize(position:,dimensions:)
|
8
|
-
@position = position
|
9
|
-
@dimensions = dimensions
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
class Body
|
14
|
-
attr_reader :position, :velocity, :t0, :dimensions
|
15
|
-
|
16
|
-
def initialize(position:, velocity:, t0:, dimensions:)
|
17
|
-
@position = position
|
18
|
-
@velocity = velocity
|
19
|
-
@dimensions = dimensions
|
20
|
-
@t0 = t0
|
21
|
-
end
|
22
|
-
|
23
|
-
def width
|
24
|
-
dimensions[0]
|
25
|
-
end
|
26
|
-
|
27
|
-
def height
|
28
|
-
dimensions[1]
|
29
|
-
end
|
30
|
-
|
31
|
-
def at(t, obstacles:[])
|
32
|
-
x0,y0 = *position
|
33
|
-
vx0,vy0 = *velocity
|
34
|
-
|
35
|
-
dt = t - t0
|
36
|
-
|
37
|
-
vx = vx0 # - dry friction ?
|
38
|
-
vy = vy0 + (gravity * dt)
|
39
|
-
|
40
|
-
next_y_obstacle = next_obstacle_on_y_axis(vy,t,obstacles:obstacles)
|
41
|
-
|
42
|
-
if next_y_obstacle
|
43
|
-
distance_to_next_y_obstacle =
|
44
|
-
if vy > 0
|
45
|
-
((y0+height) - next_y_obstacle.position[1]).abs
|
46
|
-
else
|
47
|
-
(y0 - next_y_obstacle.position[1]).abs
|
48
|
-
end
|
49
|
-
# if vy > 0
|
50
|
-
# distance_to_next_y_obstacle -= height
|
51
|
-
# end
|
52
|
-
|
53
|
-
distance_travelled_in_y_axis_if_no_obstacles = (vy * dt)
|
1
|
+
require 'gosu' # note: must require gosu *first*
|
2
|
+
require 'dedalus'
|
54
3
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
if distance_travelled_in_y_axis_if_no_obstacles < distance_to_next_y_obstacle
|
59
|
-
# the no-obstacles within relevant distance case
|
60
|
-
# # TODO handle other coordinate (x)
|
61
|
-
x = x0 + (vx * dt)
|
62
|
-
y = y0 + (vy * dt)
|
63
|
-
|
64
|
-
else
|
65
|
-
# TODO handle other coordinate here too...
|
66
|
-
x = x0 + (vx * dt)
|
67
|
-
y = y0 + distance_to_next_y_obstacle # - height
|
68
|
-
vy = 0
|
69
|
-
end
|
70
|
-
else
|
71
|
-
x = x0 + (vx * dt)
|
72
|
-
y = y0 + (vy * dt)
|
73
|
-
end
|
74
|
-
|
75
|
-
Body.new(
|
76
|
-
position: [x,y],
|
77
|
-
velocity: [vx,vy],
|
78
|
-
dimensions: dimensions,
|
79
|
-
t0: t
|
80
|
-
)
|
81
|
-
end
|
82
|
-
|
83
|
-
def next_obstacle_on_y_axis(vy,t,obstacles:)
|
84
|
-
x0,y0 = *position
|
85
|
-
|
86
|
-
obstacles_along_axis = obstacles.select do |obstacle|
|
87
|
-
ox,_ = *obstacle.position
|
88
|
-
ow,_ = *obstacle.dimensions
|
89
|
-
ox <= x0 + width && x0 <= ox + ow
|
90
|
-
end
|
91
|
-
|
92
|
-
obstacles_in_direction_of_movement = if vy > 0
|
93
|
-
obstacles_along_axis.select do |obstacle|
|
94
|
-
_,oy = *obstacle.position
|
95
|
-
# _,oh = *obstacle.dimensions
|
96
|
-
|
97
|
-
oy >= y0 + height # && y0 < oy + oh
|
98
|
-
end
|
99
|
-
elsif vy < 0
|
100
|
-
obstacles_along_axis.select do |obstacle|
|
101
|
-
_,oy = *obstacle.position
|
102
|
-
_,oh = *obstacle.dimensions
|
103
|
-
|
104
|
-
oy + oh <= y0 # + height # && y0 > oy + oh
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
|
109
|
-
obstacles_in_direction_of_movement.min_by do |obstacle|
|
110
|
-
_,oy = *obstacle.position
|
111
|
-
# distance to me
|
112
|
-
(y0 - oy).abs
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def gravity
|
117
|
-
9.8
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
4
|
+
require 'physicist/version'
|
5
|
+
require 'physicist/simple_body'
|
6
|
+
require 'physicist/body'
|
Binary file
|
Binary file
|
Binary file
|
data/spec/physicist_spec.rb
CHANGED
@@ -88,7 +88,7 @@ describe Body do
|
|
88
88
|
context "with an obstacle directly beneath the body" do
|
89
89
|
let(:obstacles) do
|
90
90
|
[
|
91
|
-
SimpleBody.new(position: [ x0, y0 + height ], dimensions: [ width, height ])
|
91
|
+
SimpleBody.new(position: [ x0, y0 + height ], dimensions: [ width, height ])
|
92
92
|
]
|
93
93
|
end
|
94
94
|
|
@@ -96,7 +96,7 @@ describe Body do
|
|
96
96
|
_,vy = *body_at_t.velocity
|
97
97
|
_,y = *body_at_t.position
|
98
98
|
expect(vy).to eq(0)
|
99
|
-
expect(y0).to eq(y)
|
99
|
+
expect(y0 + 0.99).to eq(y)
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
@@ -113,7 +113,7 @@ describe Body do
|
|
113
113
|
it 'should stop vertical movement after 1s' do
|
114
114
|
_,vy = *body_at_t.velocity
|
115
115
|
_,y = *body_at_t.position
|
116
|
-
expect(y0 +
|
116
|
+
expect(y0 + 10.79).to eq(y)
|
117
117
|
expect(vy).to eq(0)
|
118
118
|
end
|
119
119
|
end
|
@@ -124,8 +124,8 @@ describe Body do
|
|
124
124
|
it 'should be in freefall' do
|
125
125
|
_,vy = *body_at_t.velocity
|
126
126
|
_,y = *body_at_t.position
|
127
|
-
expect(y0 +
|
128
|
-
expect(vy).to eq(
|
127
|
+
expect(y0 + 50.0).to eq(y)
|
128
|
+
expect(vy).to eq(50.0)
|
129
129
|
end
|
130
130
|
end
|
131
131
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: physicist
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joseph Weissman
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-06-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -134,8 +134,31 @@ files:
|
|
134
134
|
- features/step_definitions/physicist_steps.rb
|
135
135
|
- gemspec.yml
|
136
136
|
- lib/physicist.rb
|
137
|
-
- lib/physicist/
|
137
|
+
- lib/physicist/body.rb
|
138
|
+
- lib/physicist/laboratory/app.rb
|
139
|
+
- lib/physicist/laboratory/commands/create_scientist.rb
|
140
|
+
- lib/physicist/laboratory/commands/jump_scientist.rb
|
141
|
+
- lib/physicist/laboratory/commands/move_scientist.rb
|
142
|
+
- lib/physicist/laboratory/events/scientist_created_event.rb
|
143
|
+
- lib/physicist/laboratory/events/scientist_updated_event.rb
|
144
|
+
- lib/physicist/laboratory/events/space_created_event.rb
|
145
|
+
- lib/physicist/laboratory/handlers/create_scientist_handler.rb
|
146
|
+
- lib/physicist/laboratory/handlers/jump_scientist_handler.rb
|
147
|
+
- lib/physicist/laboratory/handlers/move_scientist_handler.rb
|
148
|
+
- lib/physicist/laboratory/listeners/scientist_created_event_listener.rb
|
149
|
+
- lib/physicist/laboratory/listeners/scientist_updated_event_listener.rb
|
150
|
+
- lib/physicist/laboratory/listeners/space_created_event_listener.rb
|
151
|
+
- lib/physicist/laboratory/models/scientist.rb
|
152
|
+
- lib/physicist/laboratory/models/space.rb
|
153
|
+
- lib/physicist/laboratory/screen.rb
|
154
|
+
- lib/physicist/laboratory/view.rb
|
155
|
+
- lib/physicist/laboratory/views/scientist_view.rb
|
156
|
+
- lib/physicist/laboratory/views/workspace_view.rb
|
157
|
+
- lib/physicist/simple_body.rb
|
138
158
|
- lib/physicist/version.rb
|
159
|
+
- media/images/cosmos.jpg
|
160
|
+
- media/images/tiles.png
|
161
|
+
- media/images/walk.png
|
139
162
|
- physicist.gemspec
|
140
163
|
- spec/physicist_spec.rb
|
141
164
|
- spec/spec_helper.rb
|
data/lib/physicist/laboratory.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
# a tiny dedalus app for visually checking physicist flow?
|