lib/ray/scene.rb in ray-0.0.1 vs lib/ray/scene.rb in ray-0.1.0.pre1

- old
+ new

@@ -24,16 +24,10 @@ # Or you can override render: # def render(win) # # Do drawing here # end # - # Notice win is not filled with an empty color when render is called, i.e. - # it still contains the frame which appears to the user. - # - # Also, scenes are rendered lazily: only once when the scene is created, - # and then every time need_render! is called. - # # Once your scene is loaded, you'll probably want to clean it up (set some # instance variables to nil so they can be garbaged collected for instance). # You can do that by passing a block to clean_up: # clean_up do # @some_big_resource = nil @@ -67,11 +61,18 @@ # end # # == Limiting the loop rate # You can prevent a scene from always running by using #loops_per_second=: # self.loops_per_second = 30 # will sleep some time after each loop + # This defaults to 60. # + # == Lazy rendering + # By default, the scene is always rendered. You can enable lazy rendering: + # self.lazy_rendering = true + # In this case, the scene will render in its own Image when requested (using + # #need_render!), and that image will be drawn in every loop. + # # @see Ray::DSL::EventTranslator class Scene include Ray::Helper class << self @@ -92,26 +93,24 @@ scene_name :scene # Creates a new scene. block will be instance evaluated when # this scene becomes the current one. def initialize(&block) - @scene_register_block = block - end + @scene_register_block = block + @scene_always_block = nil + @scene_render_block = nil + @scene_clean_block = nil - def register_events - @scene_held_keys = [] + @scene_need_render = true + @scene_loops_per_second = 60 - on :key_press do |key, mod| - @scene_held_keys << key - end + @scene_shader = nil + end - on :key_release do |key, mod| - @scene_held_keys.reject! { |i| i == key } - end - + def register_events if @scene_register_block - instance_eval(&@scene_register_block) + instance_exec(@scene_arguments, &@scene_register_block) else register end @scene_exit = false @@ -124,47 +123,54 @@ # Override this method in subclasses to register your own events def register end - # @param [Symbol, Integer] val A symbol to find the key (its name) - # or an integer (Ray::Event::KEY_*) - # - # @return [true, false] True if the user is holding key. - def holding?(val) - if val.is_a? Symbol - val = key(val) - @scene_held_keys.any? { |o| val === o } - elsif val.is_a? DSL::Matcher - @scene_held_keys.any? { |o| val === o } - else - @scene_held_keys.include? val - end - end - # Runs until you exit the scene. # This will also raise events if the mouse moves, ... allowing you # to directly listen to a such event. def run until @scene_exit loop_start = Time.now - DSL::EventTranslator.translate_event(Ray::Event.new).each do |args| - raise_event(*args) + ev = Ray::Event.new + until ev.type == Ray::Event::TYPE_NOEVENT + DSL::EventTranslator.translate_event(ev).each do |args| + raise_event(*args) + end + + ev.poll! end @scene_always_block.call if @scene_always_block listener_runner.run - if @scene_need_render - @scene_need_render = false + @scene_window.fill(Ray::Color.none) - render(@scene_window) - @scene_window.flip + if lazy_rendering? + unless @scene_lazy_cache + @scene_lazy_cache = Ray::Image.new(:w => @scene_window.w, + :h => @scene_window.h) + end + + if @scene_need_render + @scene_lazy_cache.fill Ray::Color.none + + render @scene_lazy_cache + @scene_lazy_cache.update + + @scene_need_render = false + end + + @scene_lazy_cache.draw(:on => @scene_window, :shader => @scene_shader) + else + render @scene_window end + @scene_window.update + if @scene_loops_per_second ellapsed_time = Time.now - loop_start time_per_loop = 1.0 / @scene_loops_per_second sleep(time_per_loop - ellapsed_time) if ellapsed_time < time_per_loop @@ -172,10 +178,32 @@ end clean_up end + # Runs another scene over the current one. + # This method will return when the scene is done running. + def run_scene(name, *args) + scene_list = SceneList.new(game) + scene_list.push(name, *args) + + event_runner = DSL::EventRunner.new + + old_event_runner = game.event_runner + old_scene_list = game.scenes + + game.event_runner = event_runner + game.scenes = scene_list + + begin + game.run + ensure + game.event_runner = old_event_runner + game.scenes = old_scene_list + end + end + # Exits the scene, but does not pop the scene. # # You may want to call this if you pushed a new scene, to switch to # the new scene. def exit @@ -199,13 +227,12 @@ @scene_need_render = true end # Registers the block to draw the scene. # - # Does nothing if no block is given, this method being called if you - # didn't register any render block. You can thus override it in subclasses - # instead of providing a block to it. + # If no block is given, renders the scen on the image passed as + # an argument. # # @yield [window] Block to render this scene. # @yieldparam [Ray::Image] window The window you should draw on def render(win = nil, &block) if block_given? @@ -218,11 +245,11 @@ # Pushes a scene in the stack, and exits that one def push_scene(scene, *args) game.push_scene(scene, *args) exit end - + # @see Ray::Game#resize_window def resize_window(w, h) game.resize_window(w, h) end @@ -263,9 +290,38 @@ def loops_per_second=(val) @scene_loops_per_second = val end + alias :frames_per_second :loops_per_second + alias :frames_per_second= :loops_per_second= + + def lazy_rendering + @scene_lazy_rendering ||= false + end + + alias :lazy_rendering? :lazy_rendering + + def lazy_rendering=(val) + @scene_lazy_rendering = val + + unless lazy_rendering? + @scene_lazy_cache = nil + end + end + # The arguments passed to the scene with push_scene attr_accessor :scene_arguments + + # @return [Ray::Shader] The shader used for this scene. + # It will be used when drawing the scene on the window. + # This won't do anything unless lazy_rendering is enabled. + def shader + @scene_shader + end + + # Sets the shader used for this scene + def shader=(value) + @scene_shader = value + end end end