physicist 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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?
|