teien 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/README.md +11 -6
  2. data/bin/teien +16 -2
  3. data/lib/teien/ai.rb +27 -0
  4. data/lib/teien/animation.rb +34 -0
  5. data/lib/teien/animation_operator.rb +6 -0
  6. data/lib/teien/controller.rb +30 -0
  7. data/lib/teien/dispatcher.rb +22 -0
  8. data/lib/teien/event.rb +60 -0
  9. data/lib/teien/event_router.rb +118 -0
  10. data/lib/teien/garden.rb +60 -172
  11. data/lib/teien/garden_base.rb +117 -0
  12. data/lib/teien/garden_object.rb +119 -136
  13. data/lib/teien/model.rb +34 -0
  14. data/lib/teien/network.rb +108 -0
  15. data/lib/teien/object_info.rb +21 -0
  16. data/lib/teien/physics.rb +47 -39
  17. data/lib/teien/physics_object.rb +57 -0
  18. data/lib/teien/physics_object_factory.rb +170 -0
  19. data/lib/teien/proxy_garden.rb +118 -0
  20. data/lib/teien/remote_info.rb +20 -0
  21. data/lib/teien/sky_dome.rb +15 -0
  22. data/lib/teien/smooth_mover.rb +31 -42
  23. data/lib/teien/synchronizer.rb +26 -0
  24. data/lib/teien/tools.rb +30 -2
  25. data/lib/teien/user_interface.rb +58 -5
  26. data/lib/teien/version.rb +1 -1
  27. data/lib/teien/view.rb +52 -33
  28. data/lib/teien/view_object.rb +67 -0
  29. data/lib/teien/view_object_factory.rb +210 -0
  30. data/lib/teien.rb +62 -14
  31. data/sample/actor/app/ais/actor_ai.rb +112 -0
  32. data/sample/actor/app/controllers/actor_controller.rb +182 -0
  33. data/sample/actor/app/helpers/sinbad/sinbad.rb +176 -0
  34. data/sample/actor/app/helpers/sinbad/sinbad_state.rb +224 -0
  35. data/sample/actor/app/helpers/user_event.rb +75 -0
  36. data/sample/actor/app/models/actor_model.rb +108 -0
  37. data/sample/actor/config/plugins.cfg +19 -0
  38. data/sample/actor/config/resources.cfg +24 -0
  39. data/sample/hello_garden/app/controllers/hello_garden_controller.rb +90 -0
  40. data/sample/hello_garden/app/helpers/user_event.rb +12 -0
  41. data/sample/{standalone/hello_garden/hello_garden.rb → hello_garden/app/models/hello_garden_model.rb} +29 -83
  42. data/sample/{standalone/hello_garden → hello_garden/config}/plugins.cfg +0 -0
  43. data/sample/{standalone/hello_garden → hello_garden/config}/resources.cfg +0 -0
  44. data/sample/hello_garden/run +6 -0
  45. data/teien.gemspec +2 -1
  46. metadata +52 -15
  47. data/lib/teien/light_object.rb +0 -36
  48. data/lib/teien/object_factory.rb +0 -308
  49. data/sample/standalone/hello_garden/run +0 -5
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Teien
2
2
 
3
- Teien will be a platform to make 3D world easily with Ruby.
3
+ Teien will be a platform to make 3D worlds connected by network easily with Ruby.
4
4
 
5
5
  ## Installation
6
6
 
@@ -14,16 +14,21 @@ And then execute:
14
14
 
15
15
  Or install it yourself as:
16
16
 
17
- $ gem install ruby-ogre
18
- $ gem install ruby-bullet
19
- $ gem install teienlib
20
- $ gem install pkg/teien-<version>.gem
17
+ $ gem install eventmachine
18
+ $ gem install ruby-ogre
19
+ $ gem install ruby-bullet
20
+ $ gem install teienlib
21
+ $ rake build
22
+ $ gem install pkg/teien-<version>.gem
21
23
 
22
24
  ## Usage
23
25
 
24
26
  Run a sample application.
25
27
 
26
- $ /var/lib/gems/1.9.1/gems/teien-<version>/sample/standalone/hello_garden/run
28
+ $ mkdir mywork/
29
+ $ cp -r <gems>/teien-<version>/sample/ mywork/
30
+ $ cd mywork/sample/hello_garden/
31
+ $ ./run
27
32
 
28
33
  ## Contributing
29
34
 
data/bin/teien CHANGED
@@ -45,5 +45,19 @@ end
45
45
  $LOAD_PATH.push(libPath)
46
46
  $LOAD_PATH.push("./")
47
47
 
48
- load ARGV[0]
49
-
48
+ require 'teien'
49
+
50
+ case ARGV[0]
51
+ when "server"
52
+ Teien::start_server_garden("0.0.0.0", 11922)
53
+ when "client"
54
+ ip = ARGV[1] ? ARGV[1] : "0.0.0.0"
55
+ port = ARGV[2] ? ARGV[2].to_i : 11922
56
+ Teien::start_client_garden(ip, port)
57
+ when "ai"
58
+ ip = ARGV[1] ? ARGV[1] : "0.0.0.0"
59
+ port = ARGV[2] ? ARGV[2].to_i : 11922
60
+ Teien::start_ai_garden(ip, port)
61
+ when "local"
62
+ Teien::start_local_garden()
63
+ end
data/lib/teien/ai.rb ADDED
@@ -0,0 +1,27 @@
1
+ require 'teien'
2
+
3
+ module Teien
4
+
5
+ class Ai
6
+ @@ais = Array.new
7
+ @@loaded_ais = Array.new
8
+
9
+ @garden = nil
10
+
11
+ def initialize(garden)
12
+ @garden = garden
13
+ @garden.register_receiver(self)
14
+ end
15
+
16
+ def self.inherited(klass)
17
+ @@ais.push(klass)
18
+ end
19
+
20
+ def self.load(garden)
21
+ @@ais.each {|ctl|
22
+ @@loaded_ais.push(ctl.new(garden))
23
+ }
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,34 @@
1
+ module Teien
2
+
3
+ class Animation
4
+ attr_accessor :enable
5
+ attr_accessor :blend_mode
6
+ attr_accessor :operators
7
+
8
+ class Operator
9
+ attr_accessor :name
10
+ attr_accessor :speed
11
+ attr_accessor :loop
12
+
13
+ def initialize(name, speed, loop)
14
+ @name = name
15
+ @speed = speed
16
+ @loop = loop
17
+ end
18
+ end
19
+
20
+ def initialize()
21
+ @enable = false
22
+ @blend_mode = Ogre::ANIMBLEND_CUMULATIVE
23
+ @operators = Hash.new
24
+ end
25
+
26
+ def create_operator(operator_name, animation_name, speed, loop)
27
+ unless @operators[operator_name]
28
+ @operators[operator_name] = Operator.new(animation_name, speed, loop)
29
+ end
30
+ return @operators[operator_name]
31
+ end
32
+ end
33
+
34
+ end
@@ -3,6 +3,9 @@ class AnimationOperator
3
3
  BL_MODE_CONCURRENT = 1 # cross fade, blend current animation out while blending next animation in.
4
4
  BL_MODE_FIRSTFRAME = 2 # blend current animation to first frame of next animation, when done, start next animation.
5
5
 
6
+ attr_accessor :name
7
+ attr_accessor :loop
8
+
6
9
  def initialize(entity)
7
10
  @entity = entity
8
11
  @state = nil
@@ -11,6 +14,8 @@ class AnimationOperator
11
14
  @duration = 0.2
12
15
  @timeLeft = 0
13
16
  @complete = false
17
+
18
+ @name = nil
14
19
  @loop = false
15
20
 
16
21
  # @blender = Ogrelet::AnimationBlender.new(entity)
@@ -43,6 +48,7 @@ class AnimationOperator
43
48
  end
44
49
 
45
50
  def play(name, loop)
51
+ @name = name
46
52
  @loop = loop
47
53
 
48
54
  unless @state
@@ -0,0 +1,30 @@
1
+ require 'teien'
2
+
3
+ module Teien
4
+
5
+ class Controller
6
+ @@controllers = Array.new
7
+ @@loaded_controllers = Array.new
8
+
9
+ @garden = nil
10
+ @ui = nil
11
+
12
+ def initialize(garden, ui)
13
+ @garden = garden
14
+ @garden.register_receiver(self)
15
+ @ui = ui
16
+ @ui.register_receiver(self)
17
+ end
18
+
19
+ def self.inherited(klass)
20
+ @@controllers.push(klass)
21
+ end
22
+
23
+ def self.load(garden, ui)
24
+ @@controllers.each {|ctl|
25
+ @@loaded_controllers.push(ctl.new(garden, ui))
26
+ }
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,22 @@
1
+ module Teien
2
+
3
+ module Dispatcher
4
+ def initialize(*args, &block)
5
+ super
6
+ @receivers = Array.new
7
+ end
8
+
9
+ def register_receiver(recv)
10
+ @receivers.push(recv)
11
+ end
12
+
13
+ def notify(method, *argv)
14
+ @receivers.each {|recv|
15
+ if (recv.respond_to?(method))
16
+ recv.method(method).call(*argv)
17
+ end
18
+ }
19
+ end
20
+ end
21
+
22
+ end
@@ -0,0 +1,60 @@
1
+ module Event
2
+
3
+ # event
4
+
5
+ class ClientConnected
6
+ end
7
+
8
+ class ClientUnbinded
9
+ end
10
+
11
+ class SyncEnv
12
+ attr_accessor :gravity
13
+ attr_accessor :ambient_light_color
14
+ attr_accessor :sky_dome
15
+
16
+ def initialize(gravity, ambient_light_color, sky_dome)
17
+ @gravity = gravity
18
+ @ambient_light_color = ambient_light_color
19
+ @sky_dome = sky_dome
20
+ end
21
+ end
22
+
23
+ class SyncObject
24
+ attr_accessor :id
25
+ attr_accessor :name
26
+ attr_accessor :mode
27
+
28
+ attr_accessor :object_info
29
+ attr_accessor :physics_info
30
+ attr_accessor :animation_info
31
+
32
+ attr_accessor :pos
33
+ attr_accessor :linear_vel
34
+ attr_accessor :angular_vel
35
+ attr_accessor :quat
36
+ attr_accessor :accel
37
+
38
+
39
+ def initialize(obj)
40
+ @id = obj.id
41
+ @name = obj.name
42
+
43
+ @object_info = obj.object_info
44
+ @physics_info = obj.physics_info
45
+ @animation_info = obj.animation_info
46
+
47
+ @pos = Vector3D.to_self(obj.get_position())
48
+ @linear_vel = Vector3D.to_self(obj.get_linear_velocity())
49
+ @angular_vel = Vector3D.to_self(obj.get_angular_velocity())
50
+ @quat = Quaternion.to_self(obj.get_rotation())
51
+ @accel = obj.get_acceleration()
52
+ end
53
+
54
+ def print
55
+ puts @name
56
+ end
57
+ end
58
+
59
+
60
+ end # module Event
@@ -0,0 +1,118 @@
1
+ require "eventmachine"
2
+ require "teien/event"
3
+ require "teien/network"
4
+
5
+ module Teien
6
+
7
+ ##
8
+ # EventRouter routes events in this region and communicate with the other region routers.
9
+ #
10
+ # ====Usage
11
+ # 1. register a new event type name with registerEventType().
12
+ # 2. register a receiver object which receives the eventType with registerReceiver().
13
+ # The receiver object must have action(event) method.
14
+ # 3. call notify(event) which issues the event.
15
+ # The event must have eventType() method which returns event type name.
16
+ #
17
+ class EventRouter
18
+ attr_accessor :connected_regions
19
+
20
+ def initialize()
21
+ @connected_regions = Array.new
22
+
23
+ @event_type_receiver_hash = {} # event_type => receivers
24
+
25
+ @last_time = 0
26
+ @tick_event = Event::Tick.new(0)
27
+ register_event_type(Event::Tick)
28
+ end
29
+
30
+ def finalize()
31
+ end
32
+
33
+ # eventmachine
34
+ def send_all_regions(obj)
35
+ @connected_regions.each { |c|
36
+ c.send_object(obj)
37
+ }
38
+ end
39
+
40
+ # event_type: the class name of a event.
41
+ def register_event_type(event_type)
42
+ @event_type_receiver_hash[event_type] = Array.new
43
+ end
44
+
45
+ ##
46
+ #
47
+ # The event receiver must have action(anEvent) method.
48
+ #
49
+ def register_receiver(event_name, receiver)
50
+ if (@event_type_receiver_hash.has_key?(event_name))
51
+ @event_type_receiver_hash[event_name].push(receiver)
52
+ else
53
+ print "No such event type(#{event_name}) in EventRouter.\n"
54
+ print "Use EventRouter::register_event_type(event_type) at first.\n"
55
+ end
56
+ end
57
+
58
+ ##
59
+ # The event notified by this method must have a event_type attribute and
60
+ # the event_yype must be registered with register_event_type()
61
+ #
62
+ def notify(event)
63
+ if (@event_type_receiver_hash.has_key?(event.class))
64
+ @event_type_receiver_hash[event.class].each {|receiver|
65
+ receiver.receive_event(event)
66
+ }
67
+ else
68
+ print "No such event type(#{event.class}) in EventRouter.\n"
69
+ print "Use EventRouter::register_event_type(event_type) at first.\n"
70
+ end
71
+ end
72
+
73
+ def run()
74
+ EM.run do
75
+ Signal.trap("INT") { EM.stop; self.finalize() }
76
+ Signal.trap("TERM") { EM.stop; self.finalize() }
77
+
78
+ EM.add_periodic_timer(0) do
79
+ notify(@tick_event)
80
+ # update(delta)
81
+ end
82
+
83
+ # EM.start_server("0.0.0.0", 11922, ServerNetwork, @event_router)
84
+ end
85
+ end
86
+
87
+ # ip: string(ex. "0.0.0.0" means to accept all),
88
+ # port: num
89
+ def start_region(ip, port)
90
+ EM.run do
91
+ Signal.trap("INT") { EM.stop; self.finalize() }
92
+ Signal.trap("TERM") { EM.stop; self.finalize() }
93
+
94
+ EM.add_periodic_timer(0) do
95
+ notify(@tick_event)
96
+ end
97
+
98
+ EM.start_server(ip, port, Network, self)
99
+ end
100
+ end
101
+
102
+ def connect_to_region(ip, port)
103
+ EM.run do
104
+ # setting signals
105
+ Signal.trap("INT") { EM.stop; self.finalize() }
106
+ Signal.trap("TERM") { EM.stop; self.finalize() }
107
+
108
+ # main loop
109
+ EM.add_periodic_timer(0) do
110
+ notify(Event::Tick.new(@tick_event))
111
+ end
112
+
113
+ EM.connect('49.212.146.194', 11922, Network, self)
114
+ end
115
+ end
116
+ end
117
+
118
+ end
data/lib/teien/garden.rb CHANGED
@@ -1,203 +1,91 @@
1
- require "teien/garden_object.rb"
2
- require "teien/light_object.rb"
3
- require "teien/object_factory.rb"
4
- require "teien/view.rb"
5
- #require "teien/server_view.rb"
6
- require "teien/physics.rb"
7
- require "teien/user_interface.rb"
8
- #require "teien/server_user_interface.rb"
1
+ require "teien/garden_base.rb"
2
+ require "teien/network.rb"
3
+ require "teien/event.rb"
9
4
 
10
5
  module Teien
11
6
 
12
- # This is a top object of 3D world.
13
- class Garden
14
- attr_accessor :view
15
- attr_accessor :physics
16
- attr_accessor :resources_cfg
17
- attr_accessor :plugins_cfg
18
- attr_accessor :objects
19
- attr_accessor :object_factory
20
- attr_accessor :is_server
21
-
22
- #
23
- # _script_klass_:: : set a user define class.
24
- #
25
- def initialize(script_klass)
26
- @view = nil
27
- @physics = nil
28
- @script_klass = script_klass
29
-
30
- @resources_cfg = nil
31
- @plugins_cfg = nil
32
- @objects = {}
33
- @object_num = 0
34
-
35
- @object_factory = ObjectFactory.new(self)
36
-
37
- @is_server = false
38
- @debug_draw = false
39
- @quit = false
40
- end
41
-
42
- #
43
- # set a title name on the window title bar.
44
- #
45
- # _title_ :: : set a name(String).
46
- #
47
- def set_window_title(title)
48
- @view.window_title = title unless @is_server
49
- end
50
-
51
- #
52
- # set the gravity of the world.
53
- #
54
- # _grav_ :: : set a vector(Vector3D) as the gravity.
55
- #
56
- def set_gravity(grav)
57
- @physics.set_gravity(grav)
58
- end
59
-
60
- #
61
- # set the ambient light of the world.
62
- #
63
- # _color_:: : set a color(Color).
64
- #
65
- def set_ambient_light(color)
66
- @view.scene_mgr.set_ambient_light(color)
67
- end
68
-
69
- def set_sky_dome(enable, materialName, curvature = 10, tiling = 8, distance = 4000)
70
- @view.scene_mgr.set_sky_dome(enable, materialName, curvature, tiling, distance)
71
- end
72
-
73
- def set_debug_draw(bl)
74
- if (bl)
75
- @debug_draw = bl
76
- @debug_drawer = Teienlib::DebugDrawer.new(@view.scene_mgr)
77
- @physics.dynamicsWorld.set_debug_drawer(@debug_drawer)
78
- end
7
+ class Garden < GardenBase
8
+ def initialize()
9
+ super
79
10
  end
80
11
 
81
- def create_user_interface()
82
- if @is_server
83
- return ServerUserInterface.new(@view)
84
- else
85
- return UserInterface.new(@view)
86
- end
87
- end
88
-
89
- def create_object(name, objectInfo, physicsInfo)
90
- return @object_factory.create_object(name, objectInfo, physicsInfo)
91
- end
92
-
93
- def create_light(name)
94
- return LightObject.new(self, name)
95
- end
12
+ def run(ip = nil, port = 11922)
13
+ return false unless setup()
96
14
 
97
- def add_object(obj, collision_filter = nil)
98
- if (@objects[obj.name] == nil)
99
- if (obj.rigid_body != nil)
100
- if (collision_filter)
101
- @physics.add_rigid_body(obj.rigid_body, collision_filter)
15
+ @last_time = 0
16
+ EM.run do
17
+ EM.add_periodic_timer(0.01) do
18
+ if @last_time == 0
19
+ @last_time = Time.now.to_f
102
20
  else
103
- @physics.add_rigid_body(obj.rigid_body)
21
+ now = Time.now.to_f
22
+ delta = now - @last_time
23
+ @last_time = now
24
+
25
+ unless update(delta)
26
+ EM.stop
27
+ self.finalize()
28
+ end
104
29
  end
105
30
  end
106
- @objects[obj.name] = obj
107
- obj.id = @object_num
108
- @object_num += 1
109
- else
110
- raise RuntimeError, "There is a object with the same name (#{obj.name})"
111
- end
112
- end
113
-
114
- def check_collision(objectA, objectB)
115
- result = @physics.contact_pair_test(objectA.rigid_body, objectB.rigid_body)
116
- return result.isCollided
117
- end
118
31
 
119
- def setup()
120
- if @is_server
121
- @view = ServerView.new(self)
122
- else
123
- @view = View.new(self)
124
- end
125
-
126
- @physics = Physics.new(self)
127
- @script = @script_klass.new(self)
128
-
129
- if @view.setup()
130
- @view.start(@script)
131
- @view.prepare_render_loop()
132
-
133
- @physics.setup()
134
- @script.setup()
135
-
136
- return true
137
- else
138
- return false
139
- end
140
- end
32
+ Signal.trap("INT") { EM.stop; self.finalize() }
33
+ Signal.trap("TERM") { EM.stop; self.finalize() }
141
34
 
142
- #
143
- # mainloop
144
- #
145
- def run()
146
- return false unless setup()
147
-
148
- last_time = Time.now.to_f
149
- while !@quit
150
- now_time = Time.now.to_f
151
- delta = now_time - last_time
152
- last_time = now_time
153
- break unless update(delta)
35
+ if (ip)
36
+ EM.start_server(ip, port, Network, self)
37
+ end
154
38
  end
155
-
156
- finalize()
39
+ end
157
40
 
41
+ def setup()
42
+ @physics.setup(self)
43
+ notify(:setup, self)
158
44
  return true
159
45
  end
160
46
 
161
-
162
47
  def update(delta)
163
- @physics.dynamics_world.debug_draw_world() if @debug_draw
164
-
165
- return @view.update(delta)
48
+ @physics.update(delta)
49
+ @actors.each_value {|actor|
50
+ actor.update(delta)
51
+ }
52
+ notify(:update, delta)
53
+ return !@quit
166
54
  end
167
55
 
168
- # called from view.update()
169
- # This function is divided from update() by the purpose of an optimization,
170
- # which archives to run in parallel with GPU process.
171
- def update_in_frame_rendering_queued(delta)
172
- return false unless @physics.update(delta)
173
-
174
- @objects.each_value {|obj|
175
- obj.update(delta)
176
- }
56
+ # receive handler of Network.
57
+ def receive_event(event, from)
58
+ case event
59
+ when Event::ClientConnected
60
+ from.send_object(Event::SyncEnv.new(@gravity, @ambient_light_color, @sky_dome))
61
+ notify_objects(from)
62
+ end
63
+ notify(:receive_event, event, from)
64
+ end
177
65
 
178
- return @script.update(delta)
66
+ def send_event(event, to = nil)
67
+ if (to)
68
+ to.send_object(event)
69
+ else
70
+ Network::send_all(event)
71
+ end
179
72
  end
180
73
 
181
- def clean_up()
182
- @physics.finalize()
183
- @objects = {}
184
- @view.stop()
74
+ def notify_objects(to = nil)
75
+ @objects.each_value { |obj|
76
+ if to == nil
77
+ Network::send_all(Event::SyncObject.new(obj))
78
+ else
79
+ to.send_object(Event::SyncObject.new(obj))
80
+ end
81
+ }
185
82
  end
186
83
 
187
- # called by Garden class.
188
- # clear all managers.
189
84
  def finalize()
190
85
  @physics.finalize()
191
- @view.root.save_config()
192
- @view.finalize()
193
86
  @objects = {}
194
87
  end
195
-
196
88
 
197
- # quit the current running garden.
198
- def quit()
199
- @quit = true
200
- end
201
89
  end
202
90
 
203
- end # module
91
+ end