cyberarm_engine 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.travis.yml +5 -0
  4. data/Gemfile +6 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +43 -0
  7. data/Rakefile +10 -0
  8. data/bin/console +14 -0
  9. data/bin/setup +8 -0
  10. data/cyberarm_engine.gemspec +36 -0
  11. data/lib/cyberarm_engine.rb +36 -0
  12. data/lib/cyberarm_engine/background.rb +166 -0
  13. data/lib/cyberarm_engine/common.rb +85 -0
  14. data/lib/cyberarm_engine/engine.rb +95 -0
  15. data/lib/cyberarm_engine/game_object.rb +256 -0
  16. data/lib/cyberarm_engine/game_state.rb +90 -0
  17. data/lib/cyberarm_engine/lib/bounding_box.rb +124 -0
  18. data/lib/cyberarm_engine/lib/vector.rb +97 -0
  19. data/lib/cyberarm_engine/objects/multi_line_text.rb +67 -0
  20. data/lib/cyberarm_engine/objects/text.rb +96 -0
  21. data/lib/cyberarm_engine/objects/timer.rb +23 -0
  22. data/lib/cyberarm_engine/ui/border_canvas.rb +101 -0
  23. data/lib/cyberarm_engine/ui/button.rb +53 -0
  24. data/lib/cyberarm_engine/ui/check_box.rb +52 -0
  25. data/lib/cyberarm_engine/ui/container.rb +154 -0
  26. data/lib/cyberarm_engine/ui/dsl.rb +82 -0
  27. data/lib/cyberarm_engine/ui/edit_line.rb +88 -0
  28. data/lib/cyberarm_engine/ui/element.rb +197 -0
  29. data/lib/cyberarm_engine/ui/event.rb +46 -0
  30. data/lib/cyberarm_engine/ui/flow.rb +15 -0
  31. data/lib/cyberarm_engine/ui/gui_state.rb +119 -0
  32. data/lib/cyberarm_engine/ui/image.rb +42 -0
  33. data/lib/cyberarm_engine/ui/label.rb +34 -0
  34. data/lib/cyberarm_engine/ui/stack.rb +11 -0
  35. data/lib/cyberarm_engine/ui/style.rb +15 -0
  36. data/lib/cyberarm_engine/ui/theme.rb +91 -0
  37. data/lib/cyberarm_engine/ui/toggle_button.rb +49 -0
  38. data/lib/cyberarm_engine/version.rb +4 -0
  39. metadata +137 -0
@@ -0,0 +1,95 @@
1
+ module CyberarmEngine
2
+ class Engine < Gosu::Window
3
+ IMAGES = {}
4
+ SAMPLES= {}
5
+ SONGS = {}
6
+
7
+ attr_accessor :show_cursor
8
+ attr_reader :current_state, :last_frame_time
9
+
10
+ def self.now
11
+ Gosu.milliseconds
12
+ end
13
+
14
+ def self.dt
15
+ $window.last_frame_time/1000.0
16
+ end
17
+
18
+ def initialize(width = 800, height = 600, fullscreen = false, update_interval = 1000.0/60)
19
+ @show_cursor = false
20
+
21
+ super(width, height, fullscreen, update_interval)
22
+ $window = self
23
+ @last_frame_time = Gosu.milliseconds-1
24
+ @current_frame_time = Gosu.milliseconds
25
+ self.caption = "CyberarmEngine #{CyberarmEngine::VERSION} #{Gosu.language}"
26
+
27
+ @states = []
28
+
29
+ setup if defined?(setup)
30
+ end
31
+
32
+ def draw
33
+ current_state.draw if current_state
34
+ end
35
+
36
+ def update
37
+ current_state.update if current_state
38
+ @last_frame_time = Gosu.milliseconds-@current_frame_time
39
+ @current_frame_time = Gosu.milliseconds
40
+ end
41
+
42
+ def needs_cursor?
43
+ @show_cursor
44
+ end
45
+
46
+ def dt
47
+ @last_frame_time/1000.0
48
+ end
49
+
50
+ def button_down(id)
51
+ current_state.button_down(id) if current_state
52
+ end
53
+
54
+ def button_up(id)
55
+ current_state.button_up(id) if current_state
56
+ end
57
+
58
+ def push_state(klass, options={})
59
+ if klass.instance_of?(klass.class) && defined?(klass.options)
60
+ @states << klass
61
+ else
62
+ @states << klass.new(options) if child_of?(klass, GameState)
63
+ @states << klass.new if child_of?(klass, Container)
64
+ end
65
+ end
66
+
67
+ private def child_of?(input, klass)
68
+ input.ancestors.detect {|c| c == klass}
69
+ end
70
+
71
+ def current_state
72
+ @states.last
73
+ end
74
+
75
+ def previous_state
76
+ if @states.size > 1 && state = @states[@states.size-2]
77
+ return state
78
+ else
79
+ return nil
80
+ end
81
+ end
82
+
83
+ def pop_state
84
+ @states.pop
85
+ end
86
+
87
+ # Sourced from https://gist.github.com/ippa/662583
88
+ def draw_circle(cx,cy,r, z = 9999,color = Gosu::Color::GREEN, step = 10)
89
+ 0.step(360, step) do |a1|
90
+ a2 = a1 + step
91
+ draw_line(cx + Gosu.offset_x(a1, r), cy + Gosu.offset_y(a1, r), color, cx + Gosu.offset_x(a2, r), cy + Gosu.offset_y(a2, r), color, z)
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,256 @@
1
+ module CyberarmEngine
2
+ class GameObject
3
+ include Common
4
+
5
+ attr_accessor :image, :angle, :position, :velocity, :center_x, :center_y, :scale_x, :scale_y,
6
+ :color, :alpha, :mode, :options, :paused, :radius, :last_position
7
+ def initialize(options={})
8
+ if options[:auto_manage] || options[:auto_manage] == nil
9
+ $window.current_state.add_game_object(self)
10
+ end
11
+
12
+ @options = options
13
+ @image = options[:image] ? image(options[:image]) : nil
14
+ x = options[:x] ? options[:x] : 0
15
+ y = options[:y] ? options[:y] : 0
16
+ z = options[:z] ? options[:z] : 0
17
+ @position = Vector.new(x, y, z)
18
+ @velocity = Vector.new
19
+ @last_position = Vector.new
20
+ @angle = options[:angle] ? options[:angle] : 0
21
+
22
+ @center_x = options[:center_x] ? options[:center_x] : 0.5
23
+ @center_y = options[:center_y] ? options[:center_y] : 0.5
24
+
25
+ @scale_x = options[:scale_x] ? options[:scale_x] : 1
26
+ @scale_y = options[:scale_y] ? options[:scale_y] : 1
27
+
28
+ @color = options[:color] ? options[:color] : Gosu::Color.argb(0xff_ffffff)
29
+ @alpha = options[:alpha] ? options[:alpha] : 255
30
+ @mode = options[:mode] ? options[:mode] : :default
31
+
32
+ @paused = false
33
+ @speed = 0
34
+ @debug_color = Gosu::Color::GREEN
35
+ @world_center_point = Vector.new(0,0)
36
+
37
+ setup
38
+
39
+ @debug_text = MultiLineText.new("", color: @debug_color, y: @position.y-(self.height*self.scale), z: 9999)
40
+ @debug_text.x = @position.x
41
+ if @radius == 0 || @radius == nil
42
+ @radius = options[:radius] ? options[:radius] : defined?(@image.width) ? ((@image.width+@image.height)/4)*scale : 1
43
+ end
44
+ end
45
+
46
+ def draw
47
+ if @image
48
+ @image.draw_rot(@position.x, @position.y, @position.z, @angle, @center_x, @center_y, @scale_x, @scale_y, @color, @mode)
49
+ end
50
+
51
+ if $debug
52
+ show_debug_heading
53
+ $window.draw_circle(@position.x, @position.y, radius, 9999, @debug_color)
54
+ if @debug_text.text != ""
55
+ $window.draw_rect(@debug_text.x-10, (@debug_text.y-10), @debug_text.width+20, @debug_text.height+20, Gosu::Color.rgba(0,0,0,200), 9999)
56
+ @debug_text.draw
57
+ end
58
+ end
59
+ end
60
+
61
+ def update
62
+ end
63
+
64
+ def debug_text(text)
65
+ @debug_text.text = text
66
+ @debug_text.x = @position.x-(@debug_text.width / 2)
67
+ @debug_text.y = @position.y-(@debug_text.height + self.radius + self.height)
68
+ end
69
+
70
+ def scale
71
+ if @scale_x == @scale_y
72
+ return @scale_x
73
+ else
74
+ false
75
+ # maths?
76
+ end
77
+ end
78
+
79
+ def scale=(int)
80
+ self.scale_x = int
81
+ self.scale_y = int
82
+ self.radius = ((@image.width+@image.height)/4)*self.scale
83
+ end
84
+
85
+ def visible
86
+ true
87
+ # if _x_visible
88
+ # if _y_visible
89
+ # true
90
+ # else
91
+ # false
92
+ # end
93
+ # else
94
+ # false
95
+ # end
96
+ end
97
+
98
+ def _x_visible
99
+ self.x.between?(($window.width/2)-(@world_center_point.x), ($window.width/2)+@world_center_point.x) ||
100
+ self.x.between?(((@world_center_point.x)-$window.width/2), ($window.width/2)+@world_center_point.x)
101
+ end
102
+
103
+ def _y_visible
104
+ self.y.between?(($window.height/2)-(@world_center_point.y), ($window.height/2)+@world_center_point.y) ||
105
+ self.y.between?((@world_center_point.y)-($window.height/2), ($window.height/2)+@world_center_point.y)
106
+ end
107
+
108
+ def heading(ahead_by = 100, object = nil, angle_only = false)
109
+ direction = Gosu.angle(@last_position.x, @last_position.x, @position.x, position.y).gosu_to_radians
110
+
111
+ _x = @position.x + (ahead_by * Math.cos(direction))
112
+ _y = @position.y + (ahead_by * Math.sin(direction))
113
+
114
+ return direction if angle_only
115
+ return Vector.new(_x, _y) unless angle_only
116
+ end
117
+
118
+ def show_debug_heading
119
+ _heading = heading
120
+ Gosu.draw_line(@position.x, @position.y, @debug_color, _heading.x, _heading.y, @debug_color, 9999)
121
+ end
122
+
123
+ def width
124
+ @image ? @image.width : 0
125
+ end
126
+
127
+ def height
128
+ @image ? @image.height : 0
129
+ end
130
+
131
+ def pause
132
+ @paused = true
133
+ end
134
+
135
+ def unpause
136
+ @paused = false
137
+ end
138
+
139
+ def rotate(int)
140
+ self.angle+=int
141
+ self.angle%=360
142
+ end
143
+
144
+ def alpha=int # 0-255
145
+ @alpha = int
146
+ @alpha = 255 if @alpha > 255
147
+ @color = Gosu::Color.rgba(@color.red, @color.green, @color.blue, int)
148
+ end
149
+
150
+ def draw_rect(x, y, width, height, color, z = 0)
151
+ $window.draw_rect(x,y,width,height,color,z)
152
+ end
153
+
154
+ def button_up(id)
155
+ end
156
+
157
+ def button_down?(id)
158
+ end
159
+
160
+ def find_closest(game_object_class)
161
+ best_object = nil
162
+ best_distance = 100_000_000_000 # Huge default number
163
+
164
+ game_object_class.all.each do |object|
165
+ distance = Gosu::distance(self.x, self.y, object.x, object.y)
166
+ if distance <= best_distance
167
+ best_object = object
168
+ best_distance = distance
169
+ end
170
+ end
171
+
172
+ return best_object
173
+ end
174
+
175
+ def look_at(object)
176
+ # TODO: Implement
177
+ end
178
+
179
+ def circle_collision?(object)
180
+ distance = Gosu.distance(self.x, self.y, object.x, object.y)
181
+ if distance <= self.radius+object.radius
182
+ true
183
+ else
184
+ false
185
+ end
186
+ end
187
+
188
+ # Duplication... so DRY.
189
+ def each_circle_collision(object, resolve_with = :width, &block)
190
+ if object.class != Class && object.instance_of?(object.class)
191
+ $window.current_state.game_objects.select {|i| i.class == object.class}.each do |o|
192
+ distance = Gosu.distance(self.x, self.y, object.x, object.y)
193
+ if distance <= self.radius+object.radius
194
+ block.call(o, object) if block
195
+ end
196
+ end
197
+ else
198
+ list = $window.current_state.game_objects.select {|i| i.class == object}
199
+ list.each do |o|
200
+ next if self == o
201
+ distance = Gosu.distance(self.x, self.y, o.x, o.y)
202
+ if distance <= self.radius+o.radius
203
+ block.call(self, o) if block
204
+ end
205
+ end
206
+ end
207
+ end
208
+
209
+ def destroy
210
+ if $window.current_state
211
+ $window.current_state.game_objects.each do |o|
212
+ if o.is_a?(self.class) && o == self
213
+ $window.current_state.game_objects.delete(o)
214
+ end
215
+ end
216
+ end
217
+ end
218
+
219
+ # NOTE: This could be implemented more reliably
220
+ def all
221
+ INSTANCES.select {|i| i.class == self}
222
+ end
223
+
224
+ def self.each_circle_collision(object, resolve_with = :width, &block)
225
+ if object.class != Class && object.instance_of?(object.class)
226
+ $window.current_state.game_objects.select {|i| i.class == self}.each do |o|
227
+ distance = Gosu.distance(o.x, o.y, object.x, object.y)
228
+ if distance <= o.radius+object.radius
229
+ block.call(o, object) if block
230
+ end
231
+ end
232
+ else
233
+ lista = $window.current_state.game_objects.select {|i| i.class == self}
234
+ listb = $window.current_state.game_objects.select {|i| i.class == object}
235
+ lista.product(listb).each do |o, o2|
236
+ next if o == o2
237
+ distance = Gosu.distance(o.x, o.y, o2.x, o2.y)
238
+ if distance <= o.radius+o2.radius
239
+ block.call(o, o2) if block
240
+ end
241
+ end
242
+ end
243
+ end
244
+
245
+ def self.destroy_all
246
+ INSTANCES.clear
247
+ if $window.current_state
248
+ $window.current_state.game_objects.each do |o|
249
+ if o.is_a?(self.class)
250
+ $window.current_state.game_objects.delete(o)
251
+ end
252
+ end
253
+ end
254
+ end
255
+ end
256
+ end
@@ -0,0 +1,90 @@
1
+ module CyberarmEngine
2
+ class GameState
3
+ include Common
4
+
5
+ attr_accessor :options, :global_pause
6
+ attr_reader :game_objects, :containers
7
+
8
+ def initialize(options={})
9
+ @options = options
10
+ @game_objects = []
11
+ @global_pause = false
12
+
13
+ @down_keys = {}
14
+
15
+ setup
16
+ end
17
+
18
+ def setup
19
+ end
20
+
21
+ def draw
22
+ @game_objects.each(&:draw)
23
+ end
24
+
25
+ def update
26
+ @game_objects.each(&:update)
27
+ end
28
+
29
+ def draw_bounding_box(box)
30
+ x,y, max_x, max_y = box.x, box.y, box.max_x, box.max_y
31
+
32
+ color = Gosu::Color.rgba(255, 127, 64, 240)
33
+
34
+ # pipe = 4
35
+ # Gosu.draw_rect(x-width, y-height, x+(width*2), y+(height*2), color, Float::INFINITY)
36
+ # puts "BB render: #{x}:#{y} w:#{x.abs+width} h:#{y.abs+height}"
37
+ # Gosu.draw_rect(x, y, x.abs+width, y.abs+height, color, Float::INFINITY)
38
+
39
+ # TOP LEFT to BOTTOM LEFT
40
+ $window.draw_line(
41
+ x, y, color,
42
+ x, max_y, color,
43
+ Float::INFINITY
44
+ )
45
+ # BOTTOM LEFT to BOTTOM RIGHT
46
+ $window.draw_line(
47
+ x, max_y, color,
48
+ max_x, max_y, color,
49
+ Float::INFINITY
50
+ )
51
+ # BOTTOM RIGHT to TOP RIGHT
52
+ $window.draw_line(
53
+ max_x, max_y, color,
54
+ max_x, y, color,
55
+ Float::INFINITY
56
+ )
57
+ # TOP RIGHT to TOP LEFT
58
+ $window.draw_line(
59
+ max_x, y, color,
60
+ x, y, color,
61
+ Float::INFINITY
62
+ )
63
+ end
64
+
65
+ def destroy
66
+ @options.clear
67
+ @game_objects.clear
68
+ end
69
+
70
+ def button_down(id)
71
+ @down_keys[id] = true
72
+
73
+ @game_objects.each do |o|
74
+ o.button_down(id)
75
+ end
76
+ end
77
+
78
+ def button_up(id)
79
+ @down_keys.delete(id)
80
+
81
+ @game_objects.each do |o|
82
+ o.button_up(id)
83
+ end
84
+ end
85
+
86
+ def add_game_object(object)
87
+ @game_objects << object
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,124 @@
1
+ module CyberarmEngine
2
+ class BoundingBox
3
+ attr_accessor :min, :max
4
+
5
+ def initialize(minx = 0, miny = 0, minz = 0, maxx = 0, maxy = 0, maxz = 0)
6
+ @min = Vector.new(minx, miny, minz)
7
+ @max = Vector.new(maxx, maxy, maxz)
8
+ end
9
+
10
+ def ==(other)
11
+ @min == other.min &&
12
+ @max == other.max
13
+ end
14
+
15
+ # returns a new bounding box that includes both bounding boxes
16
+ def union(other)
17
+ temp = BoundingBox.new
18
+ temp.min.x = [@min.x, other.min.x].min
19
+ temp.min.y = [@min.y, other.min.y].min
20
+ temp.min.z = [@min.z, other.min.z].min
21
+
22
+ temp.max.x = [@max.x, other.max.x].max
23
+ temp.max.y = [@max.y, other.max.y].max
24
+ temp.max.z = [@max.z, other.max.z].max
25
+
26
+ return temp
27
+ end
28
+
29
+ # returns the difference between both bounding boxes
30
+ def difference(other)
31
+ temp = BoundingBox.new
32
+ temp.min = @min - other.min
33
+ temp.max = @max - other.max
34
+
35
+ return temp
36
+ end
37
+
38
+ # returns whether both bounding boxes intersect
39
+ def intersect?(other)
40
+ (@min.x <= other.max.x && @max.x >= other.min.x) &&
41
+ (@min.y <= other.max.y && @max.y >= other.min.y) &&
42
+ (@min.z <= other.max.z && @max.z >= other.min.z)
43
+ end
44
+
45
+ # does this bounding box envelop other bounding box? (inclusive of border)
46
+ def contains?(other)
47
+ other.min.x >= min.x && other.min.y >= min.y && other.min.z >= min.z &&
48
+ other.max.x <= max.x && other.max.y <= max.y && other.max.z <= max.z
49
+ end
50
+
51
+ # returns whether the vector is inside of the bounding box
52
+ def point?(vector)
53
+ vector.x.between?(@min.x, @max.x) &&
54
+ vector.y.between?(@min.y, @max.y) &&
55
+ vector.z.between?(@min.z, @max.z)
56
+ end
57
+
58
+ def volume
59
+ width * height * depth
60
+ end
61
+
62
+ def width
63
+ @max.x - @min.x
64
+ end
65
+
66
+ def height
67
+ @max.y - @min.y
68
+ end
69
+
70
+ def depth
71
+ @max.z - @min.z
72
+ end
73
+
74
+ def normalize(entity)
75
+ temp = BoundingBox.new
76
+ temp.min.x = @min.x.to_f * entity.scale
77
+ temp.min.y = @min.y.to_f * entity.scale
78
+ temp.min.z = @min.z.to_f * entity.scale
79
+
80
+ temp.max.x = @max.x.to_f * entity.scale
81
+ temp.max.y = @max.y.to_f * entity.scale
82
+ temp.max.z = @max.z.to_f * entity.scale
83
+
84
+ return temp
85
+ end
86
+
87
+ def normalize_with_offset(entity)
88
+ temp = BoundingBox.new
89
+ temp.min.x = @min.x.to_f * entity.scale + entity.position.x
90
+ temp.min.y = @min.y.to_f * entity.scale + entity.position.y
91
+ temp.min.z = @min.z.to_f * entity.scale + entity.position.z
92
+
93
+ temp.max.x = @max.x.to_f * entity.scale + entity.position.x
94
+ temp.max.y = @max.y.to_f * entity.scale + entity.position.y
95
+ temp.max.z = @max.z.to_f * entity.scale + entity.position.z
96
+
97
+ return temp
98
+ end
99
+
100
+ def +(other)
101
+ box = BoundingBox.new
102
+ box.min = self.min + other.min
103
+ box.min = self.max + other.max
104
+
105
+ return box
106
+ end
107
+
108
+ def -(other)
109
+ box = BoundingBox.new
110
+ box.min = self.min - other.min
111
+ box.min = self.max - other.max
112
+
113
+ return box
114
+ end
115
+
116
+ def sum
117
+ @min.sum + @max.sum
118
+ end
119
+
120
+ def clone
121
+ BoundingBox.new(@min.x, @min.y, @min.z, @max.x, @max.y, @max.z)
122
+ end
123
+ end
124
+ end