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