ippa-movie_maker 0.3.0
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.
- data/History.txt +27 -0
- data/README.rdoc +154 -0
- data/Rakefile +19 -0
- data/examples/axe.rb +24 -0
- data/examples/balls.rb +20 -0
- data/examples/echoes.rb +30 -0
- data/examples/gosu_base.rb +40 -0
- data/examples/gosu_rain.rb +34 -0
- data/examples/gosu_river_of_stars.rb +35 -0
- data/examples/gosu_triangles.rb +34 -0
- data/examples/gosu_wish_upon_a_star.rb +48 -0
- data/examples/ippagaming_intro.rb +23 -0
- data/examples/media/23700__hazure__chop.wav +0 -0
- data/examples/media/Establo.ttf +0 -0
- data/examples/media/FeaturedItem.ttf +0 -0
- data/examples/media/FreeSans.ttf +0 -0
- data/examples/media/Hursheys.ttf +0 -0
- data/examples/media/axe.png +0 -0
- data/examples/media/axe.svg +136 -0
- data/examples/media/ball.png +0 -0
- data/examples/media/ball.svg +182 -0
- data/examples/media/black.bmp +0 -0
- data/examples/media/blue_triangle.png +0 -0
- data/examples/media/blue_triangle.svg +81 -0
- data/examples/media/chop.wav +0 -0
- data/examples/media/cloth_background.png +0 -0
- data/examples/media/drawing.svg +86 -0
- data/examples/media/drip.wav +0 -0
- data/examples/media/green_triangle.png +0 -0
- data/examples/media/green_triangle.svg +104 -0
- data/examples/media/hit.wav +0 -0
- data/examples/media/ippa_gaming.png +0 -0
- data/examples/media/ippa_gaming.svg +463 -0
- data/examples/media/oil_drip.wav +0 -0
- data/examples/media/outdoor_scene.bmp +0 -0
- data/examples/media/outdoor_scene.png +0 -0
- data/examples/media/outdoor_scene.svg +316 -0
- data/examples/media/rain-bak1.wav +0 -0
- data/examples/media/rain.wav +0 -0
- data/examples/media/rain2.wav +0 -0
- data/examples/media/raindrop.png +0 -0
- data/examples/media/raindrop.svg +87 -0
- data/examples/media/raindrop_small.bmp +0 -0
- data/examples/media/raindrop_small.png +0 -0
- data/examples/media/red_triangle.png +0 -0
- data/examples/media/red_triangle.svg +81 -0
- data/examples/media/spaceship_noalpha.png +0 -0
- data/examples/media/star_5.png +0 -0
- data/examples/media/star_5.svg +83 -0
- data/examples/media/star_6.png +0 -0
- data/examples/media/star_6.svg +86 -0
- data/examples/rain.rb +26 -0
- data/examples/rain_advanced.rb +26 -0
- data/examples/rubygame_river_of_stars.rb +28 -0
- data/examples/zoom.rb +27 -0
- data/lib/movie_maker.rb +411 -0
- data/lib/movie_maker/action.rb +389 -0
- data/lib/movie_maker/core_extensions.rb +17 -0
- data/lib/movie_maker/gosu_autoload.rb +38 -0
- data/lib/movie_maker/gosu_clock.rb +139 -0
- data/lib/movie_maker/named_resource.rb +254 -0
- data/lib/movie_maker/sprite.rb +157 -0
- metadata +126 -0
Binary file
|
Binary file
|
@@ -0,0 +1,83 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2
|
+
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
3
|
+
<svg
|
4
|
+
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
5
|
+
xmlns:cc="http://creativecommons.org/ns#"
|
6
|
+
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
7
|
+
xmlns:svg="http://www.w3.org/2000/svg"
|
8
|
+
xmlns="http://www.w3.org/2000/svg"
|
9
|
+
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
10
|
+
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
11
|
+
width="744.09448819"
|
12
|
+
height="1052.3622047"
|
13
|
+
id="svg2"
|
14
|
+
sodipodi:version="0.32"
|
15
|
+
inkscape:version="0.46"
|
16
|
+
sodipodi:docname="star_5.svg"
|
17
|
+
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
18
|
+
<defs
|
19
|
+
id="defs4">
|
20
|
+
<inkscape:perspective
|
21
|
+
sodipodi:type="inkscape:persp3d"
|
22
|
+
inkscape:vp_x="0 : 526.18109 : 1"
|
23
|
+
inkscape:vp_y="0 : 1000 : 0"
|
24
|
+
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
25
|
+
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
26
|
+
id="perspective10" />
|
27
|
+
</defs>
|
28
|
+
<sodipodi:namedview
|
29
|
+
id="base"
|
30
|
+
pagecolor="#ffffff"
|
31
|
+
bordercolor="#666666"
|
32
|
+
borderopacity="1.0"
|
33
|
+
gridtolerance="10000"
|
34
|
+
guidetolerance="10"
|
35
|
+
objecttolerance="10"
|
36
|
+
inkscape:pageopacity="0.0"
|
37
|
+
inkscape:pageshadow="2"
|
38
|
+
inkscape:zoom="0.35"
|
39
|
+
inkscape:cx="375"
|
40
|
+
inkscape:cy="520"
|
41
|
+
inkscape:document-units="px"
|
42
|
+
inkscape:current-layer="layer1"
|
43
|
+
showgrid="false"
|
44
|
+
inkscape:window-width="870"
|
45
|
+
inkscape:window-height="756"
|
46
|
+
inkscape:window-x="1343"
|
47
|
+
inkscape:window-y="141" />
|
48
|
+
<metadata
|
49
|
+
id="metadata7">
|
50
|
+
<rdf:RDF>
|
51
|
+
<cc:Work
|
52
|
+
rdf:about="">
|
53
|
+
<dc:format>image/svg+xml</dc:format>
|
54
|
+
<dc:type
|
55
|
+
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
56
|
+
</cc:Work>
|
57
|
+
</rdf:RDF>
|
58
|
+
</metadata>
|
59
|
+
<g
|
60
|
+
inkscape:label="Layer 1"
|
61
|
+
inkscape:groupmode="layer"
|
62
|
+
id="layer1">
|
63
|
+
<path
|
64
|
+
sodipodi:type="star"
|
65
|
+
style="opacity:0.512;fill:#808080;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:18.17716598999999900;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
66
|
+
id="path2389"
|
67
|
+
sodipodi:sides="5"
|
68
|
+
sodipodi:cx="154.28571"
|
69
|
+
sodipodi:cy="912.36218"
|
70
|
+
sodipodi:r1="133.98331"
|
71
|
+
sodipodi:r2="343.54694"
|
72
|
+
sodipodi:arg1="0.80892323"
|
73
|
+
sodipodi:arg2="1.4372418"
|
74
|
+
inkscape:flatsided="false"
|
75
|
+
inkscape:rounded="0"
|
76
|
+
inkscape:randomized="0"
|
77
|
+
d="M 246.77142,1009.305 L 200.03168,1252.8498 L 90.667225,1030.2783 L -155.40096,1061.0856 L 22.481603,888.2955 L -82.85715,663.79074 L 136.44477,779.57202 L 317.41003,610.01312 L 275.0635,854.36003 L 492.24494,974.07163 L 246.77142,1009.305 z"
|
78
|
+
transform="matrix(0.8660254,-0.5,0.5,0.8660254,-245.83589,-213.84628)"
|
79
|
+
inkscape:export-filename="C:\Dev\projects\rubygame_movie_maker\samples\media\star_5.png"
|
80
|
+
inkscape:export-xdpi="27.559999"
|
81
|
+
inkscape:export-ydpi="27.559999" />
|
82
|
+
</g>
|
83
|
+
</svg>
|
Binary file
|
@@ -0,0 +1,86 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2
|
+
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
3
|
+
<svg
|
4
|
+
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
5
|
+
xmlns:cc="http://creativecommons.org/ns#"
|
6
|
+
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
7
|
+
xmlns:svg="http://www.w3.org/2000/svg"
|
8
|
+
xmlns="http://www.w3.org/2000/svg"
|
9
|
+
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
10
|
+
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
11
|
+
width="744.09448819"
|
12
|
+
height="1052.3622047"
|
13
|
+
id="svg2"
|
14
|
+
sodipodi:version="0.32"
|
15
|
+
inkscape:version="0.46"
|
16
|
+
sodipodi:docname="star_6.svg"
|
17
|
+
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
18
|
+
inkscape:export-filename="C:\dev\projects\rubygame_movie_maker\samples\media\star_6.png"
|
19
|
+
inkscape:export-xdpi="29.873182"
|
20
|
+
inkscape:export-ydpi="29.873182">
|
21
|
+
<defs
|
22
|
+
id="defs4">
|
23
|
+
<inkscape:perspective
|
24
|
+
sodipodi:type="inkscape:persp3d"
|
25
|
+
inkscape:vp_x="0 : 526.18109 : 1"
|
26
|
+
inkscape:vp_y="0 : 1000 : 0"
|
27
|
+
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
28
|
+
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
29
|
+
id="perspective10" />
|
30
|
+
</defs>
|
31
|
+
<sodipodi:namedview
|
32
|
+
id="base"
|
33
|
+
pagecolor="#ffffff"
|
34
|
+
bordercolor="#666666"
|
35
|
+
borderopacity="1.0"
|
36
|
+
gridtolerance="10000"
|
37
|
+
guidetolerance="10"
|
38
|
+
objecttolerance="10"
|
39
|
+
inkscape:pageopacity="0.0"
|
40
|
+
inkscape:pageshadow="2"
|
41
|
+
inkscape:zoom="0.35"
|
42
|
+
inkscape:cx="375"
|
43
|
+
inkscape:cy="520"
|
44
|
+
inkscape:document-units="px"
|
45
|
+
inkscape:current-layer="layer1"
|
46
|
+
showgrid="false"
|
47
|
+
inkscape:window-width="870"
|
48
|
+
inkscape:window-height="756"
|
49
|
+
inkscape:window-x="1343"
|
50
|
+
inkscape:window-y="141" />
|
51
|
+
<metadata
|
52
|
+
id="metadata7">
|
53
|
+
<rdf:RDF>
|
54
|
+
<cc:Work
|
55
|
+
rdf:about="">
|
56
|
+
<dc:format>image/svg+xml</dc:format>
|
57
|
+
<dc:type
|
58
|
+
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
59
|
+
</cc:Work>
|
60
|
+
</rdf:RDF>
|
61
|
+
</metadata>
|
62
|
+
<g
|
63
|
+
inkscape:label="Layer 1"
|
64
|
+
inkscape:groupmode="layer"
|
65
|
+
id="layer1">
|
66
|
+
<path
|
67
|
+
sodipodi:type="star"
|
68
|
+
style="opacity:1;fill:#f2f2f2;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:18.17716598999999900;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
69
|
+
id="path2389"
|
70
|
+
sodipodi:sides="6"
|
71
|
+
sodipodi:cx="154.28571"
|
72
|
+
sodipodi:cy="912.36218"
|
73
|
+
sodipodi:r1="133.98331"
|
74
|
+
sodipodi:r2="343.54694"
|
75
|
+
sodipodi:arg1="0.80892323"
|
76
|
+
sodipodi:arg2="1.332522"
|
77
|
+
inkscape:flatsided="false"
|
78
|
+
inkscape:rounded="0"
|
79
|
+
inkscape:randomized="0"
|
80
|
+
d="M 246.77142,1009.305 L 235.37174,1246.2028 L 116.57358,1040.9286 L -94.285728,1149.505 L 24.087866,943.98573 L -175.37176,815.66444 L 61.799987,815.41932 L 73.199675,578.52157 L 191.99783,783.79577 L 402.85714,675.21932 L 284.48355,880.73863 L 483.94317,1009.0599 L 246.77142,1009.305 z"
|
81
|
+
transform="matrix(0.9659258,0.258819,-0.258819,0.9659258,444.25101,-428.84409)"
|
82
|
+
inkscape:export-filename="C:\dev\projects\rubygame_movie_maker\samples\media\star_6.png"
|
83
|
+
inkscape:export-xdpi="34"
|
84
|
+
inkscape:export-ydpi="34" />
|
85
|
+
</g>
|
86
|
+
</svg>
|
data/examples/rain.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
require File.join("..", "lib", "movie_maker")
|
3
|
+
|
4
|
+
include Rubygame
|
5
|
+
include MovieMaker
|
6
|
+
include MovieMaker::Rubygame
|
7
|
+
|
8
|
+
Rubygame.init()
|
9
|
+
Surface.autoload_dirs = [ "media" ]
|
10
|
+
|
11
|
+
@screen = Screen.set_mode([800, 600], 0)
|
12
|
+
@movie = Movie.new(:screen => @screen, :background => Color[:black], :target_framerate => 200)
|
13
|
+
|
14
|
+
#
|
15
|
+
# generate 5 seconds of rain, each raindrop moving from top to bottom in 1 second (1000ms), 50ms between each drop.
|
16
|
+
#
|
17
|
+
(1..100).each do |nr|
|
18
|
+
x = rand(800)
|
19
|
+
start_at = nr / 20.0
|
20
|
+
stop_at = nr / 20.0 + 1
|
21
|
+
|
22
|
+
@raindrop = Sprite.new("raindrop.png")
|
23
|
+
@movie.resource(@raindrop).move([x,0]).between(start_at, stop_at).move([x,650])
|
24
|
+
end
|
25
|
+
|
26
|
+
@movie.play
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
require File.join("..", "lib", "movie_maker")
|
3
|
+
|
4
|
+
include Rubygame
|
5
|
+
include MovieMaker
|
6
|
+
include MovieMaker::Rubygame
|
7
|
+
|
8
|
+
Rubygame.init()
|
9
|
+
Surface.autoload_dirs = [ "media" ]
|
10
|
+
Sound.autoload_dirs = [ "media" ]
|
11
|
+
|
12
|
+
@screen = Screen.set_mode([800, 600], 0)
|
13
|
+
@movie = Movie.new(:screen => @screen, :background => Color[:black], :target_framerate => 200)
|
14
|
+
|
15
|
+
start_at = stop_at = 0
|
16
|
+
(1..500).each do |nr|
|
17
|
+
x = rand(800)
|
18
|
+
start_at = nr / 50.0
|
19
|
+
stop_at = nr / 50.0 + 1.0
|
20
|
+
|
21
|
+
@raindrop = Sprite.new("raindrop_small.png")
|
22
|
+
# OLD: movie.between(start_at, stop_at).move_facing_direction(@raindrop, :from => [x,0], :to => [x+100+(nr/5)+rand(50),650])
|
23
|
+
@movie.resource(@raindrop).move([x,0]).between(start_at, stop_at).move_facing_direction([x+100+(nr/5)+rand(50),650])
|
24
|
+
end
|
25
|
+
@movie.at(0).play_sound(Sound["rain2.wav"])
|
26
|
+
@movie.play
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
require File.join("..", "lib", "movie_maker")
|
3
|
+
|
4
|
+
include Rubygame
|
5
|
+
include MovieMaker
|
6
|
+
include MovieMaker::Rubygame
|
7
|
+
|
8
|
+
Rubygame.init()
|
9
|
+
Surface.autoload_dirs = [ "media" ]
|
10
|
+
|
11
|
+
@screen = Screen.set_mode([800, 600], 0)
|
12
|
+
@background = Surface.autoload("cloth_background.png")
|
13
|
+
|
14
|
+
@movie = Movie.new(:screen => @screen, :background => Color[:black], :framework => :rubygame)
|
15
|
+
0.upto(20) do |start|
|
16
|
+
@star = Sprite.new("star_5.png") # x,y = 0,0 is default
|
17
|
+
@movie.resource(@star) # all following actions are applied to this resource
|
18
|
+
#@movie.color( Color.new(100 + rand(155),rand(255),rand(255),rand(255)) )
|
19
|
+
@movie.zoom(0.2)
|
20
|
+
@movie.between(start/10.0, start/10.0 + 2)
|
21
|
+
@movie.velocity([10,0])
|
22
|
+
@movie.acceleration([0, 0.05 + rand(0.1)])
|
23
|
+
@movie.rotate(angle = 90 * rand(10))
|
24
|
+
@movie.zoom(1.0 + rand(2.0))
|
25
|
+
@movie.then.color(0x00FFFFFF)
|
26
|
+
end
|
27
|
+
|
28
|
+
@movie.play
|
data/examples/zoom.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
require File.join("..", "lib", "movie_maker")
|
3
|
+
|
4
|
+
include Rubygame
|
5
|
+
include MovieMaker
|
6
|
+
include MovieMaker::Rubygame
|
7
|
+
|
8
|
+
TTF.setup()
|
9
|
+
Rubygame.init()
|
10
|
+
Surface.autoload_dirs = [ "media" ]
|
11
|
+
Sound.autoload_dirs = [ "media" ]
|
12
|
+
|
13
|
+
@screen = Screen.set_mode([800, 600], 0, [HWSURFACE])
|
14
|
+
@font = TTF.new(File.join("media", "FeaturedItem.ttf"), 200)
|
15
|
+
|
16
|
+
@ttf_sprites = []
|
17
|
+
%w{I P P A}.each_with_index do |letter, index|
|
18
|
+
@ttf_sprites << TTFSprite.new(letter, :font => @font, :color => Color[:white], :position => [200+(index*100),100])
|
19
|
+
end
|
20
|
+
|
21
|
+
movie = Movie.new(:screen => @screen, :background => Color[:black])
|
22
|
+
|
23
|
+
@ttf_sprites.each_with_index do |sprite, index|
|
24
|
+
# OLD: movie.between(index, index+1).zoom(sprite, :scale_from => 5, :scale_to => 0.1).rotate(sprite, :angle => 360).then.play_sound(Sound["hit.wav"])
|
25
|
+
movie.resource(sprite).at(index).zoom(5).between(index, index+1).zoom(0.6).rotate(360).then.play_sound(Sound["hit.wav"])
|
26
|
+
end
|
27
|
+
movie.play(:stop_at => 6)
|
data/lib/movie_maker.rb
ADDED
@@ -0,0 +1,411 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$: << File.join(File.dirname(__FILE__), 'lib')
|
3
|
+
['rubygems','gosu','rubygame'].each do |gem|
|
4
|
+
require gem
|
5
|
+
end
|
6
|
+
|
7
|
+
['action','sprite','core_extensions', 'gosu_clock'].each do |lib|
|
8
|
+
require File.join(File.dirname(__FILE__), 'movie_maker', lib)
|
9
|
+
end
|
10
|
+
|
11
|
+
module MovieMaker
|
12
|
+
VERSION = "0.3.0"
|
13
|
+
end
|
14
|
+
|
15
|
+
#
|
16
|
+
# MovieMaker
|
17
|
+
# A class to make simple rubygamemovies (moving around sprites in a timed fashion, playing sounds etc)
|
18
|
+
# Rubygame solves all the heavy lifting for us when it comes to drawing on the screen.
|
19
|
+
# MovieMaker adds makes timing and setup of a scene esay. Use it for intros, ingame animations and simple "demos".
|
20
|
+
# Namingconventions tries to follow Rubygame.
|
21
|
+
#
|
22
|
+
# This class is responsible for:
|
23
|
+
#
|
24
|
+
# - Keeping track of actions (move, hide, show, play a sound etc)
|
25
|
+
# - Playing them according to userspecified timing (2 actions can start at the same time)
|
26
|
+
# - Keeping track of what sprite/surface to paint to, framerate etc
|
27
|
+
#
|
28
|
+
module MovieMaker
|
29
|
+
|
30
|
+
class Movie
|
31
|
+
|
32
|
+
|
33
|
+
attr_accessor :actions
|
34
|
+
attr_reader :screen, :background, :clock, :updated_count, :stop_at
|
35
|
+
|
36
|
+
#
|
37
|
+
# Takes an options-hash as argument:
|
38
|
+
# :screen => the screen to draw on
|
39
|
+
# :target_framerate => what framerate should it aim for, defaults to 60
|
40
|
+
# :background => Color or Imageinstance
|
41
|
+
# :framework => :rubygame (default) or :gosu
|
42
|
+
#
|
43
|
+
|
44
|
+
def initialize(options = {})
|
45
|
+
@screen = options[:screen] || nil
|
46
|
+
@framework = options[:framework] || :rubygame # this can also be :gosu
|
47
|
+
@target_framerate = options[:target_framerate] || 100
|
48
|
+
@background = options[:background] || nil
|
49
|
+
@draw_mode = options[:draw_mode] || nil
|
50
|
+
@loop = options[:loop] || false
|
51
|
+
|
52
|
+
if options[:background].kind_of? ::Rubygame::Color::ColorRGB
|
53
|
+
@background = Surface.new(@screen.size)
|
54
|
+
@background.draw_box_s([0,0],[@screen.width,@screen.height], options[:background])
|
55
|
+
end
|
56
|
+
|
57
|
+
@actions = []
|
58
|
+
@onetime_actions = []
|
59
|
+
@update_actions = []
|
60
|
+
@tick = @start_at = @stop_at = 0
|
61
|
+
@restart_at = nil
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Calculates the length of the movie by checking stop_at-times of all @actions that the movie consists of.
|
66
|
+
#
|
67
|
+
# TODO:
|
68
|
+
# - current the method at() doesn't provide at stop_at, which makes total_playtime fail
|
69
|
+
#
|
70
|
+
def stop_at
|
71
|
+
@movie_stop_at ||= @actions.inject(0) { |time, action| action.stop_at > time ? action.stop_at : time }
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# Is movie still playing?
|
76
|
+
#
|
77
|
+
def playing?(current_time)
|
78
|
+
current_time <= stop_at
|
79
|
+
end
|
80
|
+
|
81
|
+
#
|
82
|
+
# Loops through the movie's full timeline and updates all the @actions
|
83
|
+
# This method blocks until the movie ends
|
84
|
+
#
|
85
|
+
# To play the movie Within your own gameloop, use update()
|
86
|
+
#
|
87
|
+
def play(options = {})
|
88
|
+
@framework ||= options[:framework] || :rubygame # this can also be :gosu
|
89
|
+
@movie_stop_at ||= options[:stop_at] ? options[:stop_at] * 1000.0 : stop_at
|
90
|
+
|
91
|
+
# Convert all start_at's filled with :now to current timestamp (meaning they'll start .. "now")
|
92
|
+
@actions.each do |action|
|
93
|
+
action.start_at = @clock.lifetime if action.start_at.is_a? Symbol and action.start_at == :now
|
94
|
+
end
|
95
|
+
|
96
|
+
setup
|
97
|
+
|
98
|
+
while @clock.lifetime < @movie_stop_at
|
99
|
+
@tick = @clock.tick()
|
100
|
+
|
101
|
+
title = "[framerate: #{@clock.framerate.to_i}] [Spriteupdates last tick: #{@updated_count}]"
|
102
|
+
|
103
|
+
if @framework == :rubygame
|
104
|
+
@screen.title = title
|
105
|
+
rubygame_update(@clock.lifetime)
|
106
|
+
else
|
107
|
+
@screen.caption = title
|
108
|
+
gosu_update(@clock.lifetime)
|
109
|
+
gosu_draw(@clock.lifetime)
|
110
|
+
end
|
111
|
+
|
112
|
+
yield if block_given?
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
#
|
117
|
+
# Starts the clock which time will be sent to all events update()'s
|
118
|
+
# Also paint a background, if any.
|
119
|
+
#
|
120
|
+
def setup
|
121
|
+
@clock = ::Gosu::Clock.new
|
122
|
+
@clock.target_framerate = @target_framerate
|
123
|
+
if @framework == :rubygame
|
124
|
+
@background.blit(@screen, [0, 0]) if @background
|
125
|
+
@screen.update
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
#
|
130
|
+
# rubygame_update() - Rubygame specific update
|
131
|
+
# Rubygame specific include: blit, sprite rects, dirty_rects and update_rects
|
132
|
+
#
|
133
|
+
# - goes through all @actions and calls undraw/update/draw.
|
134
|
+
# - goes through all @onetime_actions and calls play on them once.
|
135
|
+
#
|
136
|
+
# Several optimizations are possible here:
|
137
|
+
# - sort @actions after start_at so update doesn't have to loop through all events each time
|
138
|
+
# only until start_at isn't lower then current_time anymore
|
139
|
+
# - remove "played-out" actions from @actions
|
140
|
+
# - remove "played-out" actions from @onetime_actions
|
141
|
+
#
|
142
|
+
#
|
143
|
+
def rubygame_update(current_time)
|
144
|
+
@updated_count = 0
|
145
|
+
|
146
|
+
#@onetime_actions.select { |action| !action.playing?(current_time) and action.started?(current_time) }.each do |action|
|
147
|
+
@onetime_actions.select { |action| action.started?(current_time) and !action.finalized?}.each do |action|
|
148
|
+
action.finalize
|
149
|
+
end
|
150
|
+
|
151
|
+
dirty_rects = []
|
152
|
+
# Only undraw/update actions that are active on the timeline
|
153
|
+
@update_actions.select { |action| action.playing?(current_time) }.each do |action|
|
154
|
+
dirty_rects << @background.blit(@screen, action.sprite.rect, action.sprite.rect)
|
155
|
+
action.update(current_time - action.start_at)
|
156
|
+
#puts "update(#{current_time}): #{action.start_at} - #{action.stop_at}" + action.class.to_s
|
157
|
+
@updated_count += 1
|
158
|
+
|
159
|
+
#
|
160
|
+
# Rotozoom lies here because of 2 reasons:
|
161
|
+
# - Action can't do the actual imagemanipulation since Gosu does it drawtime
|
162
|
+
# - By moving it out of the action, we can have more then 1 action manipulting rotozoom parameeters
|
163
|
+
#
|
164
|
+
if action.sprite.angle != 0 || action.sprite.width_scaling != 1 || action.sprite.height_scaling != 1
|
165
|
+
|
166
|
+
action.sprite.image = action.image.rotozoom( action.sprite.angle,
|
167
|
+
[action.sprite.width_scaling, action.sprite.height_scaling],
|
168
|
+
true)
|
169
|
+
action.sprite.realign_center
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
@update_actions.select { |action| action.started?(current_time) }.each do |action|
|
174
|
+
dirty_rects << action.sprite.image.blit(@screen, action.sprite.rect)
|
175
|
+
end
|
176
|
+
|
177
|
+
@screen.update_rects(dirty_rects)
|
178
|
+
end
|
179
|
+
|
180
|
+
#
|
181
|
+
# gosu_update - GOSU specific updateloop
|
182
|
+
#
|
183
|
+
def gosu_update(current_time)
|
184
|
+
@updated_count = 0
|
185
|
+
|
186
|
+
# Restart movie cleanly?
|
187
|
+
#if current_time > @restart_at
|
188
|
+
#end
|
189
|
+
|
190
|
+
@onetime_actions.select { |action| action.started?(current_time) and !action.finalized? }.each do |action|
|
191
|
+
#puts "onetime action: #{action.start_at} - #{action.stop_at}" + action.class.to_s
|
192
|
+
action.finalize
|
193
|
+
end
|
194
|
+
|
195
|
+
@update_actions.select { |action| action.playing?(current_time) }.each do |action|
|
196
|
+
#puts "update(#{current_time}): #{action.start_at} - #{action.stop_at}" + action.class.to_s
|
197
|
+
action.update(current_time - action.start_at)
|
198
|
+
@updated_count += 1
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
#
|
203
|
+
# gosu_update - GOSU specific updateloop
|
204
|
+
#
|
205
|
+
def gosu_draw(current_time)
|
206
|
+
@background.draw(0, 0, 0) if @background
|
207
|
+
@update_actions.select { |action| action.started?(current_time) }.each do |action|
|
208
|
+
action.sprite.image.draw_rot( action.sprite.x,
|
209
|
+
action.sprite.y,
|
210
|
+
1,
|
211
|
+
action.sprite.angle, 0.5, 0.5,
|
212
|
+
action.sprite.width_scaling,
|
213
|
+
action.sprite.height_scaling,
|
214
|
+
action.sprite.color,
|
215
|
+
(@draw_mode || action.sprite.draw_mode))
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
|
220
|
+
def restart_at(time)
|
221
|
+
@restart_at = time
|
222
|
+
self
|
223
|
+
end
|
224
|
+
#
|
225
|
+
# Stops/resets the movie- NOT YET IMPLEMENTED
|
226
|
+
#
|
227
|
+
def stop
|
228
|
+
self
|
229
|
+
end
|
230
|
+
|
231
|
+
#
|
232
|
+
# Pauses the movie, which should resume with a call to play() - NOT YET IMPLEMENTED
|
233
|
+
#
|
234
|
+
def pause
|
235
|
+
self
|
236
|
+
end
|
237
|
+
|
238
|
+
|
239
|
+
#
|
240
|
+
# Ripped from rails Inflector
|
241
|
+
# Used to convert move()-calls to a new instance of class Move
|
242
|
+
# and play_sound()-calls to a new instance of PlaySound .. etc.
|
243
|
+
#
|
244
|
+
def classify(table_name)
|
245
|
+
camelize(singularize(table_name.to_s.sub(/.*\./, '')))
|
246
|
+
end
|
247
|
+
def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
|
248
|
+
if first_letter_in_uppercase
|
249
|
+
lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
250
|
+
else
|
251
|
+
lower_case_and_underscored_word.first + camelize(lower_case_and_underscored_word)[1..-1]
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
#
|
256
|
+
# Makes Object-initializing out of incomming missing actions
|
257
|
+
# ie. @movie.rotate(*arg) => Rotate.new(*arg)
|
258
|
+
# This makes for standalone extendable actions, one class per action
|
259
|
+
#
|
260
|
+
# Ex. movie.between(0,2000).move(:ball, :from => [100,100], :to => [500,100])
|
261
|
+
#
|
262
|
+
def method_missing(method, *args)
|
263
|
+
|
264
|
+
## ".move" (the string) ==> Move.new (the class)
|
265
|
+
klass = MovieMaker::Action.const_get(camelize(method))
|
266
|
+
|
267
|
+
options = { :start_at => @start_at,
|
268
|
+
:stop_at => @stop_at,
|
269
|
+
:screen => @screen,
|
270
|
+
:background => @background,
|
271
|
+
:object => @resource,
|
272
|
+
:framework => @framework || :rubygame
|
273
|
+
}
|
274
|
+
|
275
|
+
standard_args = []
|
276
|
+
args.each do |arg|
|
277
|
+
if arg.is_a? Hash
|
278
|
+
options.merge!(arg)
|
279
|
+
else
|
280
|
+
standard_args << arg
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
|
285
|
+
action = klass.new(options, *standard_args)
|
286
|
+
#puts "ACTION: #{action.class}(#{standard_args}) - between(#{@start_at}, #{@stop_at})"
|
287
|
+
|
288
|
+
@actions << action
|
289
|
+
#
|
290
|
+
# Separate actions that needs 1-time trigger
|
291
|
+
#
|
292
|
+
if @resource.kind_of? Sound or @stop_at == @start_at
|
293
|
+
@onetime_actions << action
|
294
|
+
#
|
295
|
+
# And thoose who needs constant update/drawing
|
296
|
+
#
|
297
|
+
else
|
298
|
+
@update_actions << action
|
299
|
+
end
|
300
|
+
|
301
|
+
self
|
302
|
+
end
|
303
|
+
|
304
|
+
#
|
305
|
+
# Bellow are methods to time actions and make them chainable
|
306
|
+
#
|
307
|
+
|
308
|
+
|
309
|
+
#
|
310
|
+
# Start following action start_at millisecs into the movie
|
311
|
+
# .. and stop it stop_at millisecs into the movie.
|
312
|
+
#
|
313
|
+
def between(start_at, stop_at)
|
314
|
+
@start_at = start_at
|
315
|
+
@stop_at = stop_at
|
316
|
+
self
|
317
|
+
end
|
318
|
+
|
319
|
+
#
|
320
|
+
# Starts action at a start_time millisecs into the movie, no specific stop time
|
321
|
+
#
|
322
|
+
# Example:
|
323
|
+
# @movie.at(2000).play_sound(@moo_sound)
|
324
|
+
#
|
325
|
+
def at(start_at)
|
326
|
+
@start_at = start_at
|
327
|
+
@stop_at = start_at
|
328
|
+
self
|
329
|
+
end
|
330
|
+
|
331
|
+
#
|
332
|
+
# Start following action right away and specify how long is should run
|
333
|
+
#
|
334
|
+
def during(length)
|
335
|
+
if @stop_at==0
|
336
|
+
@start_at = :now
|
337
|
+
else
|
338
|
+
@start_at = @stop_at
|
339
|
+
end
|
340
|
+
|
341
|
+
@stop_at = @stop_at + length
|
342
|
+
self
|
343
|
+
end
|
344
|
+
|
345
|
+
#
|
346
|
+
# Start following action after the last one finishes
|
347
|
+
#
|
348
|
+
# Example:
|
349
|
+
# @movie.between(0,1).move(@stone, :from => [0,0], :to => [0,400]).then.play_sound(@crash)
|
350
|
+
#
|
351
|
+
def then
|
352
|
+
@start_at = @stop_at
|
353
|
+
self
|
354
|
+
end
|
355
|
+
|
356
|
+
#
|
357
|
+
# Start following action after the last one finishes + a millisecs delay argument
|
358
|
+
#
|
359
|
+
# Example:
|
360
|
+
#
|
361
|
+
# @movie.at(1).play_sound(@drip).delay(0.1).play_sound(@drip, {:volume => 0.5}).delay(0.1).play_sound(@drip, {:volume => 0.2})
|
362
|
+
#
|
363
|
+
def delay(time)
|
364
|
+
@start_at = @stop_at||@start_at + time
|
365
|
+
self
|
366
|
+
end
|
367
|
+
|
368
|
+
#
|
369
|
+
# Sprite/Sound/Resource selection
|
370
|
+
#
|
371
|
+
def resource(resource)
|
372
|
+
@resource = resource
|
373
|
+
@start_at = 0
|
374
|
+
@stop_at = 0
|
375
|
+
self
|
376
|
+
end
|
377
|
+
alias :sprite :resource
|
378
|
+
alias :sound :resource
|
379
|
+
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
#
|
384
|
+
# Test the MovieMaker class, a first crude spec
|
385
|
+
# This code will change alot as I use it as a quick way of testing various new stuff out.
|
386
|
+
#
|
387
|
+
if $0 == __FILE__
|
388
|
+
include MovieMaker # A must for actions to work
|
389
|
+
include Rubygame # for easy access to rubygame stuff
|
390
|
+
include MovieMaker::Rubygame # for easy access to moviemakers special rubygamesprites
|
391
|
+
|
392
|
+
Surface.autoload_dirs = [ File.join("samples", "media"), "media" ]
|
393
|
+
Sound.autoload_dirs = [ File.join("samples", "media"), "media" ]
|
394
|
+
|
395
|
+
@screen = Screen.set_mode([800, 600], 0)
|
396
|
+
@background = Surface.autoload("outdoor_scene.png")
|
397
|
+
|
398
|
+
movie = Movie.new(:framework => :rubygame,
|
399
|
+
:screen => @screen,
|
400
|
+
:background => @background,
|
401
|
+
:target_framerate => 200)
|
402
|
+
|
403
|
+
(0..2).each do |nr|
|
404
|
+
@spaceship = Sprite.new("spaceship_noalpha.png")
|
405
|
+
|
406
|
+
## New style!
|
407
|
+
movie.resource(@spaceship).between(0,4).move([400+rand(300),rand(350)]).rotate(360).then.play_sound(Sound["hit.wav"])
|
408
|
+
|
409
|
+
end
|
410
|
+
movie.play(:stop_at => 5)
|
411
|
+
end
|