cyberarm_engine 0.1.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.
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