shattered_pack 0.3.3
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/lib/shattered_controller.rb +3 -0
- data/lib/shattered_controller/actor/actor.rb +107 -0
- data/lib/shattered_controller/base.rb +108 -0
- data/lib/shattered_controller/keyboard_input/key_converter.rb +43 -0
- data/lib/shattered_controller/keyboard_input/keyboard_input.rb +106 -0
- data/lib/shattered_controller/mock_camera.rb +9 -0
- data/lib/shattered_controller/runner.rb +33 -0
- data/lib/shattered_controller/state.rb +59 -0
- data/lib/shattered_model.rb +3 -0
- data/lib/shattered_model/base.rb +24 -0
- data/lib/shattered_model/fuzzy_logic.rb +188 -0
- data/lib/shattered_model/linear_interpolator.rb +29 -0
- data/lib/shattered_pack.rb +11 -0
- data/lib/shattered_pack/base.rb +127 -0
- data/lib/shattered_pack/pre_initialize/pre_initialize.rb +105 -0
- data/lib/shattered_pack/runner.rb +11 -0
- data/lib/shattered_pack/timer/timed_event.rb +77 -0
- data/lib/shattered_pack/timer/timer.rb +75 -0
- data/lib/shattered_view.rb +7 -0
- data/lib/shattered_view/base.rb +151 -0
- data/lib/shattered_view/camera.rb +7 -0
- data/lib/shattered_view/extensions.rb +10 -0
- data/lib/shattered_view/light.rb +28 -0
- data/lib/shattered_view/mesh/animation.rb +20 -0
- data/lib/shattered_view/mesh/mesh.rb +135 -0
- data/lib/shattered_view/node.rb +113 -0
- data/lib/shattered_view/resources.rb +47 -0
- data/lib/shattered_view/rmaterial.rb +43 -0
- data/lib/shattered_view/runner.rb +48 -0
- data/lib/shattered_view/utilities.rb +7 -0
- data/lib/shattered_view/vector.rb +242 -0
- metadata +75 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
module ShatteredPack
|
2
|
+
module Timer #:nodoc:all
|
3
|
+
|
4
|
+
class Timer
|
5
|
+
attr_reader :events_remaining
|
6
|
+
def initialize
|
7
|
+
@events_remaining = []
|
8
|
+
end
|
9
|
+
def in(seconds, &block)
|
10
|
+
@events_remaining << TimedEvent.new(seconds, &block)
|
11
|
+
end
|
12
|
+
def every(seconds, &block)
|
13
|
+
@events_remaining << ContinuousTimedEvent.new(seconds,&block)
|
14
|
+
end
|
15
|
+
def update(time_elapsed)
|
16
|
+
events_for_update = @events_remaining.dup
|
17
|
+
events_for_update.each do |event|
|
18
|
+
event.update(time_elapsed)
|
19
|
+
@events_remaining.delete(event) if event.processed?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class TimedEvent
|
25
|
+
attr_accessor :time_remaining
|
26
|
+
def initialize(seconds, &block)
|
27
|
+
@event = block
|
28
|
+
if(seconds != :frame)
|
29
|
+
@time_remaining = seconds
|
30
|
+
@initial_time = @time_remaining
|
31
|
+
else
|
32
|
+
@time_remaining = 0
|
33
|
+
@initial_time = 0
|
34
|
+
end
|
35
|
+
end
|
36
|
+
def update(time_elapsed)
|
37
|
+
return if processed?
|
38
|
+
@time_remaining -= time_elapsed
|
39
|
+
if time_up?
|
40
|
+
process_event
|
41
|
+
@processed=true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
def processed?
|
45
|
+
return @processed == true
|
46
|
+
end
|
47
|
+
def reset
|
48
|
+
@time_remaining = @initial_time
|
49
|
+
end
|
50
|
+
private
|
51
|
+
def process_event
|
52
|
+
@event.call(@initial_time - @time_remaining)
|
53
|
+
end
|
54
|
+
def time_up?
|
55
|
+
return @time_remaining <= 0
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class ContinuousTimedEvent < TimedEvent
|
60
|
+
def update(time_elapsed)
|
61
|
+
@time_remaining -= time_elapsed
|
62
|
+
if(time_up?)
|
63
|
+
process_event
|
64
|
+
reset
|
65
|
+
end
|
66
|
+
end
|
67
|
+
def reset
|
68
|
+
@time_remaining += @initial_time
|
69
|
+
@time_remaining = 0 if @time_remaining < 0
|
70
|
+
end
|
71
|
+
def processed?
|
72
|
+
false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require File.dirname(__FILE__)+'/timed_event'
|
2
|
+
|
3
|
+
module ShatteredPack
|
4
|
+
module Timer #:nodoc:
|
5
|
+
def self.append_features(base)
|
6
|
+
super
|
7
|
+
base.extend(ClassMethods)
|
8
|
+
base.send(:include, InstanceMethods)
|
9
|
+
end
|
10
|
+
module ClassMethods
|
11
|
+
# Timers are controller events that occur after a specified period of time.
|
12
|
+
# The time values are seconds by default.
|
13
|
+
#
|
14
|
+
# timer :in
|
15
|
+
# If you want an event to occur once after a specified amount of time, use
|
16
|
+
# timer :in => 3.seconds, :action => :method_to_call
|
17
|
+
#
|
18
|
+
# timer :every
|
19
|
+
# If you want an event to occur once every specified amount of time, use
|
20
|
+
# timer :every => 3.seconds, :action => :method_to_call
|
21
|
+
# If you want to be notified of every frame update, use
|
22
|
+
# timer :every => :frame, :action => :method_to_call
|
23
|
+
#
|
24
|
+
# Inside the instance, you can still create timer events, using the timer object:
|
25
|
+
# timer.in( 3.seconds ) { ... }
|
26
|
+
# timer.every( 3.seconds ) { ... }
|
27
|
+
def timer(options = {})
|
28
|
+
if options[:action].nil?
|
29
|
+
throw ShatteredPack::Error,
|
30
|
+
"Timer event must specify an :action => :method"
|
31
|
+
end
|
32
|
+
if options[:in].nil? && options[:every].nil?
|
33
|
+
throw ShatteredPack::Error,
|
34
|
+
"Timer event must specify a time. (timer :in or timer :every)"
|
35
|
+
end
|
36
|
+
time = options[:in] || options[:every]
|
37
|
+
action = options[:action]
|
38
|
+
before_init_call(:timer_in, time, action) unless options[:in].nil?
|
39
|
+
before_init_call(:timer_every, time, action) unless options[:every].nil?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
module InstanceMethods
|
43
|
+
def timer
|
44
|
+
@timer ||= Timer.new
|
45
|
+
end
|
46
|
+
private
|
47
|
+
def timer_in(time, action)
|
48
|
+
timer.in(time) do |time_elapsed|
|
49
|
+
timer_enactment(action, time_elapsed)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
def timer_every(time, action)
|
53
|
+
timer.every(time) do |time_elapsed|
|
54
|
+
timer_enactment(action, time_elapsed)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
def timer_enactment(action, time_elapsed)
|
58
|
+
begin
|
59
|
+
if(action.is_a? Hash)
|
60
|
+
if(action.values[0].is_a?(Array))
|
61
|
+
send(action.keys[0], *(action.values[0]))
|
62
|
+
else
|
63
|
+
send(action.keys[0], action.values[0])
|
64
|
+
end
|
65
|
+
else
|
66
|
+
send(action.to_sym)
|
67
|
+
end
|
68
|
+
rescue ArgumentError => argument_error
|
69
|
+
raise argument_error unless argument_error.message.to_sym == :"wrong number of arguments (0 for 1)"
|
70
|
+
send(action.to_sym,time_elapsed)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
require 'shattered_ogre'
|
2
|
+
require 'shattered_pack'
|
3
|
+
raise( ShatteredPack::Error, "Could not find ShatteredOgre (a ShatteredView dependency)" ) unless defined? ShatteredOgre
|
4
|
+
|
5
|
+
%w(vector utilities node camera extensions runner rmaterial base resources).each do |dependency|
|
6
|
+
require "shattered_view/#{dependency}"
|
7
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
|
2
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
3
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
4
|
+
|
5
|
+
require 'mesh/mesh'
|
6
|
+
|
7
|
+
module ShatteredView #:nodoc:
|
8
|
+
|
9
|
+
class Error < StandardError; end
|
10
|
+
|
11
|
+
def self.append_features(base)
|
12
|
+
super
|
13
|
+
base.extend(ClassMethods)
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
# Materials are parsed through erb as .rmaterials and parsed when a material
|
18
|
+
# metafunction is called.
|
19
|
+
#
|
20
|
+
# Example:
|
21
|
+
# material :wall_material, :template => 'normal_map', :texture => 'wall.png', :normal => 'brick_normals.png', :tangent_space => true
|
22
|
+
# mesh :wall, :material => :wall_material
|
23
|
+
#
|
24
|
+
# You must make sure that your material name is unique, or Ogre will fail.
|
25
|
+
#
|
26
|
+
# All rmaterial files are included within media/templates, you can add your own there.
|
27
|
+
# TODO: ruby script/generate material (?)
|
28
|
+
def material(name, options = {})
|
29
|
+
before_init_set "self", {:new_material => [name]}
|
30
|
+
before_init_set name, options
|
31
|
+
before_init_set name, {:create_ogre_material => []}
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
# Any view can create a light.
|
37
|
+
# There are 4 types of possible lights.
|
38
|
+
# Ambient Light - this type of light lights everything in the scene equally.
|
39
|
+
# Example: light :sun, :ambient => [1,1,1]
|
40
|
+
#
|
41
|
+
# Point Light - this type of light emanates from a point in space and lights all
|
42
|
+
# directions equally.
|
43
|
+
# Example: light :fireplace, :position => [0,-5,20], :diffuse => [1,0.5,0.5], :specular => [1,0,0], :attenuation => [8000,0,4,0.3]
|
44
|
+
# Parameters:
|
45
|
+
# :position: the x,y,z position or vector position
|
46
|
+
# :diffuse: the r,g,b value of the diffuse color
|
47
|
+
# :specular: the r,g,b value of the specular color
|
48
|
+
# :attenuation: arguments are range, constant, linear, quadratic
|
49
|
+
# range is how far the light will extend
|
50
|
+
# constant The constant factor in the attenuation formula: 1.0 means never attenuate, 0.0 is complete attenuation
|
51
|
+
# linear The linear factor in the attenuation formula: 1 means attenuate evenly over the distance
|
52
|
+
# quadratic The quadratic factor in the attenuation formula: adds a curvature to the attenuation formula.
|
53
|
+
#
|
54
|
+
# Directional Light - this light is like the positional light, except instead of position it has only direction
|
55
|
+
# Example: light :sun, :direction => [0,-1,-1], :diffuse => [1,1,1], :specular => [1,1,1]
|
56
|
+
# :direction: the direction light emanates from
|
57
|
+
# : other : same as point light above.
|
58
|
+
#
|
59
|
+
# Spotlight - this light has both a direction and a position, as well as other factors.
|
60
|
+
# Example: light :flashlight...
|
61
|
+
# TODO: This type of light is not currently implemented in shattered.
|
62
|
+
|
63
|
+
def light(name, options = {})
|
64
|
+
before_init_set "self", {:new_light => [name]}
|
65
|
+
before_init_set name, options
|
66
|
+
end
|
67
|
+
|
68
|
+
# Particle systems are defined in .particle files
|
69
|
+
# - This works for first order particle systems --
|
70
|
+
# - We need to look into second and third order particle systems
|
71
|
+
#
|
72
|
+
def particle_system(name, options = {})
|
73
|
+
raise Error, "Must supply a template for your particle system." if options[:template].nil?
|
74
|
+
before_init_set "self", {:new_particle_system, [name, options[:template]]}
|
75
|
+
options.delete :template
|
76
|
+
before_init_set name, options
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class Base < ShatteredPack::Base
|
81
|
+
attr_reader :meshes
|
82
|
+
attr_accessor :model
|
83
|
+
|
84
|
+
def rotate(vector, amount)
|
85
|
+
node.rotate(vector, amount)
|
86
|
+
end
|
87
|
+
|
88
|
+
def new_material=(name)
|
89
|
+
@materials ||= {}
|
90
|
+
name = name.to_sym
|
91
|
+
@materials[name] = RMaterial.new
|
92
|
+
@materials[name].name=name
|
93
|
+
self.class.send(:define_method, name) do
|
94
|
+
@materials[name]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def define_accessor(array, new_obj, name)
|
99
|
+
instance_eval("#{array} ||= {}")
|
100
|
+
instance_eval("#{array}[\"#{name}\"] = new_obj")
|
101
|
+
|
102
|
+
self.class.class_eval <<-EOF
|
103
|
+
define_method(:#{name}) do
|
104
|
+
#{array}[\"#{name}\"]
|
105
|
+
end
|
106
|
+
EOF
|
107
|
+
end
|
108
|
+
|
109
|
+
def new_light=(name)
|
110
|
+
define_accessor("@lights", ShatteredView::Light.new, name)
|
111
|
+
end
|
112
|
+
|
113
|
+
def new_particle_system=(name, template)
|
114
|
+
define_accessor("@particle_systems", ShatteredView::ParticleSystem.new(template), name)
|
115
|
+
end
|
116
|
+
|
117
|
|
118
|
+
#Return all of the children attached to this view's scene node
|
119
|
+
def children
|
120
|
+
node.children
|
121
|
+
end
|
122
|
+
|
123
|
+
def position
|
124
|
+
node.position
|
125
|
+
end
|
126
|
+
|
127
|
+
def position=(val)
|
128
|
+
node.position = val
|
129
|
+
end
|
130
|
+
|
131
|
+
def translate(v)
|
132
|
+
node.translate(v)
|
133
|
+
end
|
134
|
+
|
135
|
+
def node
|
136
|
+
@scene_node ||= Node.new(Node.root)
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
#This is called when a view is removed from the scene
|
141
|
+
def unload!
|
142
|
+
children.each { |child| child.remove_from_scene }
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
ShatteredView::Base.class_eval do
|
150
|
+
include ShatteredView::Mesh
|
151
|
+
end
|
152
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module ShatteredView
|
2
|
+
class Light
|
3
|
+
def light
|
4
|
+
@light ||= Scene.getSingleton().createLight
|
5
|
+
end
|
6
|
+
def direction=(*direction)
|
7
|
+
light.setType(ShatteredOgre::Light::LT_DIRECTIONAL)
|
8
|
+
light.setDirection(direction.to_v)
|
9
|
+
end
|
10
|
+
def diffuse=(r,g,b)
|
11
|
+
light.setDiffuseColour(r,g,b)
|
12
|
+
end
|
13
|
+
def specular=(r,g,b)
|
14
|
+
light.setSpecularColour(r,g,b)
|
15
|
+
end
|
16
|
+
def position=(pos)
|
17
|
+
light.setType(ShatteredOgre::Light::LT_POINT)
|
18
|
+
light.setPosition(pos.to_v)
|
19
|
+
end
|
20
|
+
def ambient=(r,g,b)
|
21
|
+
Scene.getSingleton().setAmbientLight(r,g,b);
|
22
|
+
end
|
23
|
+
def attenuation=(range, const, linear, quad)
|
24
|
+
light.setType(ShatteredOgre::Light::LT_POINT)
|
25
|
+
light.setAttenuation(range, const, linear, quad)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ShatteredView
|
2
|
+
class Animation
|
3
|
+
def initialize(mesh, name)
|
4
|
+
@animation = mesh.getAnimation name
|
5
|
+
@animation.addAsFrameListener
|
6
|
+
end
|
7
|
+
def play
|
8
|
+
@animation.play
|
9
|
+
end
|
10
|
+
def stop
|
11
|
+
@animation.stop
|
12
|
+
end
|
13
|
+
def loop=(looping)
|
14
|
+
@animation.setLoop(looping);
|
15
|
+
end
|
16
|
+
def time_scale=(scale)
|
17
|
+
@animation.setTimeScale(scale);
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require 'animation'
|
5
|
+
module ShatteredView
|
6
|
+
module Mesh
|
7
|
+
def self.included(base)
|
8
|
+
base.extend(ClassMethods)
|
9
|
+
base.send(:include, InstanceMethods)
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
# Meshes are the foundation for your world.
|
14
|
+
#
|
15
|
+
# They tie in to Ogre's .mesh file format, and display a 3d object onto the screen.
|
16
|
+
#
|
17
|
+
# Shattered has support for loading meshes, creating materials for those meshes (using RMaterials)
|
18
|
+
# and skeletal animation support.
|
19
|
+
#
|
20
|
+
# class DirtyRubyView
|
21
|
+
# mesh "dirty_ruby", :position => v(0,0,1)
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# When a Mesh is created, all animations found in that mesh are loaded, and added
|
25
|
+
# as functions to that mesh.
|
26
|
+
#
|
27
|
+
# example: Tim.mesh has animations kick and punch
|
28
|
+
#
|
29
|
+
# after loading Tim.mesh, View has the Mesh object tim
|
30
|
+
# tim.kick.play
|
31
|
+
# tim.animation(:kick).play
|
32
|
+
#
|
33
|
+
# See Rmaterials and Animation for more details.
|
34
|
+
def mesh(file, options = {})
|
35
|
+
before_init_call( :mesh, file, options )
|
36
|
+
end
|
37
|
+
|
38
|
+
# Animations declare helper functions for mesh animations.
|
39
|
+
#
|
40
|
+
# class AnimatedRubyView < ...
|
41
|
+
# mesh :animated_ruby, ...
|
42
|
+
# animation "shatter"
|
43
|
+
#
|
44
|
+
# def initialize
|
45
|
+
# shatter # same as animated_ruby.shatter
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# options can include any function in animation.rb
|
50
|
+
# and :alias => :alias_name
|
51
|
+
def animation(name, options = {})
|
52
|
+
play_alias = options.delete(:alias)
|
53
|
+
before_init_call(:animation, name, options)
|
54
|
+
unless play_alias.nil?
|
55
|
+
before_init_call(:animation_alias, name, play_alias)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
module InstanceMethods
|
61
|
+
|
62
|
+
private
|
63
|
+
def mesh(file, options={})
|
64
|
+
mesh = Mesh.new(file)
|
65
|
+
name = mesh.name
|
66
|
+
attr_reader name.to_sym, mesh
|
67
|
+
|
68
|
+
call_object_function_for_each_key(name, options)
|
69
|
+
#keep track of the meshes we create
|
70
|
+
mesh.attach_to(node)
|
71
|
+
end
|
72
|
+
|
73
|
+
def meshes
|
74
|
+
children.collect { |child| child.is_a? Mesh }
|
75
|
+
end
|
76
|
+
|
77
|
+
def animation(name, options={})
|
78
|
+
meshes.each do |mesh|
|
79
|
+
mesh.instance_eval <<-EOF
|
80
|
+
class << self
|
81
|
+
define_method(:#{name}) do
|
82
|
+
animation(:#{name})
|
83
|
+
end
|
84
|
+
end
|
85
|
+
EOF
|
86
|
+
call_object_function_for_each_key(:"#{mesh.name}.#{name}", options)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def animation_alias(name, renamed)
|
91
|
+
define_method(renamed.to_sym) do
|
92
|
+
meshes.each do |mesh|
|
93
|
+
mesh.animation(name.to_sym).play
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# This Mesh class corresponds (almost 1 to 1) with ShatteredOgre's mesh class
|
100
|
+
class Mesh < ShatteredView::Node
|
101
|
+
attr_reader :name
|
102
|
+
|
103
|
+
def initialize( file, options = {} )
|
104
|
+
super( )
|
105
|
+
@name = file.underscore
|
106
|
+
@scene_node = ShatteredOgre::Scene.getSingleton.createMesh( [0,0,0].to_v3, "#{file}.mesh" )
|
107
|
+
# TODO Log this
|
108
|
+
# puts "Loading Mesh: #{scene_node} from #{file}.mesh"
|
109
|
+
populate_animations
|
110
|
+
end
|
111
|
+
|
112
|
+
# Access a given animation. Returns nil on failure.
|
113
|
+
def animation( animation )
|
114
|
+
return @animations[animation]
|
115
|
+
end
|
116
|
+
|
117
|
+
# Remove the Ogre Mesh from the scene
|
118
|
+
def remove_from_scene
|
119
|
+
scene_node.removeFromScene
|
120
|
+
end
|
121
|
+
private
|
122
|
+
|
123
|
+
# populate_animations queries ShatteredOgre and adds the found animations to the mesh.
|
124
|
+
def populate_animations
|
125
|
+
@animations = {}
|
126
|
+
(0...scene_node.getNumberOfAnimations).each do |idx|
|
127
|
+
name = scene_node.getAnimationName(idx)
|
128
|
+
@animations[name.downcase.to_sym] = ShatteredView::Animation.new(scene_node, name)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|