author_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 (55) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.travis.yml +7 -0
  4. data/API.md +81 -0
  5. data/Gemfile +6 -0
  6. data/Gemfile.lock +26 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +38 -0
  9. data/Rakefile +10 -0
  10. data/SAVEFILE.md +23 -0
  11. data/assets/fonts/Connection.otf +0 -0
  12. data/assets/fonts/ConnectionBold.otf +0 -0
  13. data/assets/fonts/README.md +3 -0
  14. data/assets/fonts/SIL Open Font License.txt +94 -0
  15. data/assets/ui/bucket_icon.png +0 -0
  16. data/assets/ui/code_icon.png +0 -0
  17. data/assets/ui/error_icon.png +0 -0
  18. data/assets/ui/level_icon.png +0 -0
  19. data/assets/ui/loading_icon.png +0 -0
  20. data/assets/ui/lock_icon.png +0 -0
  21. data/assets/ui/pencil_icon.png +0 -0
  22. data/assets/ui/play_icon.png +0 -0
  23. data/assets/ui/sprite_icon.png +0 -0
  24. data/assets/ui/unlock_icon.png +0 -0
  25. data/author_engine.gemspec +41 -0
  26. data/bin/author_engine +4 -0
  27. data/lib/author_engine/button.rb +154 -0
  28. data/lib/author_engine/code_editor/cursor.rb +339 -0
  29. data/lib/author_engine/code_editor/highlighting.rb +49 -0
  30. data/lib/author_engine/container.rb +24 -0
  31. data/lib/author_engine/containers/editor.rb +97 -0
  32. data/lib/author_engine/containers/loader.rb +105 -0
  33. data/lib/author_engine/game/game.rb +26 -0
  34. data/lib/author_engine/game/parts/colors.rb +59 -0
  35. data/lib/author_engine/game/parts/common.rb +13 -0
  36. data/lib/author_engine/game/parts/graphics.rb +41 -0
  37. data/lib/author_engine/game/parts/input.rb +25 -0
  38. data/lib/author_engine/image.rb +53 -0
  39. data/lib/author_engine/palette.rb +114 -0
  40. data/lib/author_engine/save_file.rb +134 -0
  41. data/lib/author_engine/sprite.rb +4 -0
  42. data/lib/author_engine/sprite_picker.rb +154 -0
  43. data/lib/author_engine/support.rb +22 -0
  44. data/lib/author_engine/text.rb +41 -0
  45. data/lib/author_engine/version.rb +3 -0
  46. data/lib/author_engine/view.rb +55 -0
  47. data/lib/author_engine/views/code_editor.rb +154 -0
  48. data/lib/author_engine/views/level_editor.rb +7 -0
  49. data/lib/author_engine/views/play_viewer.rb +163 -0
  50. data/lib/author_engine/views/sprite_editor.rb +333 -0
  51. data/lib/author_engine/window.rb +132 -0
  52. data/lib/author_engine.rb +32 -0
  53. data/test_3.authorengine +519 -0
  54. data/testing.authorengine +578 -0
  55. metadata +169 -0
@@ -0,0 +1,13 @@
1
+ class AuthorEngine
2
+ class Part
3
+ module Common
4
+ def width; Window::VIEW_WIDTH; end
5
+ def height; Window::VIEW_HEIGHT; end
6
+ def fps; Gosu.fps; end
7
+ def milliseconds
8
+ @__initial_milliseconds ||= Gosu.milliseconds
9
+ Gosu.milliseconds - @__initial_milliseconds
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,41 @@
1
+ class AuthorEngine
2
+ class Part
3
+ module Graphics
4
+ def rect(x = 0, y = 0, width = 1, height = 1, color = Gosu::Color::WHITE, z = 0)
5
+ Gosu.draw_rect(x, y, width, height, color, z)
6
+ end
7
+
8
+ def text(text, x = 0, y = 0, size = 4, z = 0, color = white)
9
+ @fonts ||= {}
10
+
11
+ font = nil
12
+
13
+ if @fonts.dig(size)
14
+ font = @fonts.dig(size)
15
+ else
16
+ font = (@fonts[size] = Gosu::Font.new(size, name: Text::FONT_DEFAULT))
17
+ end
18
+
19
+ font.draw_markup(text, x, y, z, 1, 1, color)
20
+ end
21
+
22
+ def sprite(index, x = 0, y = 0, z = 0, alpha = 255)
23
+ image = SpriteEditor.instance.sprites[index]
24
+ raise "No sprite at '#{index}'!" unless image
25
+ image.draw(x, y, z, 1,1, Gosu::Color.rgba(255,255,255, alpha))
26
+ end
27
+
28
+ def translate(x, y, &block)
29
+ Gosu.translate(x, y) do
30
+ block.call if block
31
+ end
32
+ end
33
+
34
+ def rotate(angle, around_x = 0, around_y = 0, &block)
35
+ Gosu.rotate(angle, around_x, around_y) do
36
+ block.call if block
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,25 @@
1
+ class AuthorEngine
2
+ class Part
3
+ module Input
4
+ BUTTONS = {
5
+ "left" => Gosu::KbLeft,
6
+ "right" => Gosu::KbRight,
7
+ "up" => Gosu::KbUp,
8
+ "down" => Gosu::KbDown,
9
+ "x" => Gosu::KbX,
10
+ "y" => Gosu::KbC,
11
+ }
12
+ def button?(name)
13
+ down = false
14
+
15
+ if BUTTONS.dig(name)
16
+ down = Gosu.button_down?(BUTTONS.dig(name))
17
+ else
18
+ raise "Button '#{name}' not found!"
19
+ end
20
+
21
+ return down
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,53 @@
1
+ class AuthorEngine
2
+ class Image
3
+ include AuthorEngine::Support
4
+ CACHE = {}
5
+
6
+ def initialize(path, retro: true)
7
+ @retro = retro
8
+ @image = image_from_cache(path)
9
+ end
10
+
11
+ def width; @image.width; end
12
+ def height; @image.height; end
13
+
14
+ def image_from_cache(path)
15
+ image = nil
16
+ if image = CACHE.dig(path)
17
+ return image
18
+ else
19
+ _image = nil
20
+ begin
21
+ _image = Gosu::Image.new(path, retro: @retro)
22
+ rescue RuntimeError => e
23
+ if e.message.downcase.include?("cannot open file")
24
+ warn e.message
25
+ warn caller[0..2].map{|s| s = " #{s}"}.reverse
26
+ _image = image_missing
27
+ else
28
+ raise
29
+ end
30
+ end
31
+
32
+ image = CACHE[path] = _image
33
+ end
34
+
35
+ return image
36
+ end
37
+
38
+ def image_missing
39
+ return Gosu.render(window.sprite_size, window.sprite_size) do
40
+ Gosu.draw_rect(0, 0, window.sprite_size, window.sprite_size, Gosu::Color::YELLOW)
41
+ Gosu.draw_rect(2, 2, window.sprite_size-4, window.sprite_size-4, Gosu::Color::RED)
42
+ end
43
+ end
44
+
45
+ def draw(*args)
46
+ @image.draw(*args)
47
+ end
48
+
49
+ def draw_rot(*args)
50
+ @image.draw_rot(*args)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,114 @@
1
+ class AuthorEngine
2
+ class Palette
3
+ include Support
4
+ include AuthorEngine::Part::Colors
5
+
6
+ attr_accessor :x, :y, :width, :height
7
+ def initialize(x:, y:, size: 8)
8
+ @x_padding = window.scale_x
9
+ @y_padding = window.scale_y
10
+
11
+ @size = (size * @y_padding)
12
+ @slot_width = 8
13
+
14
+ set_origin(x, y)
15
+
16
+ @color_set = [
17
+ [
18
+ black,
19
+ dark_blue,
20
+ dark_purple,
21
+ dark_green
22
+ ],
23
+ [
24
+ brown,
25
+ dark_gray,
26
+ light_gray,
27
+ white
28
+ ],
29
+ [
30
+ red,
31
+ orange,
32
+ yellow,
33
+ green
34
+ ],
35
+ [
36
+ blue,
37
+ indigo,
38
+ pink,
39
+ peach
40
+ ]
41
+ ]
42
+ @active_set = 0
43
+ @active_color = nil
44
+ end
45
+
46
+ def color
47
+ @active_color
48
+ end
49
+
50
+ def set_origin(x, y)
51
+ _x = x
52
+ _y = y
53
+
54
+ if x == :center
55
+ _x = window.width/2 - (@slot_width*@size)/2
56
+ end
57
+ if y == :bottom
58
+ _y = window.height - ((@size*2)+@y_padding)
59
+ end
60
+
61
+ @x, @y = _x, _y
62
+ @width = 4 * @size
63
+ @height = 4 * @size
64
+ end
65
+
66
+ def draw
67
+ Gosu.draw_rect(@x-window.square_scale, @y-window.square_scale, @width + (window.square_scale*2), @height + (window.square_scale*2), light_gray)
68
+ draw_colors
69
+ hightlight_active_color
70
+ end
71
+
72
+ def update
73
+ end
74
+
75
+ def button_up(id)
76
+ if id == Gosu::MsLeft
77
+ @color_set.each_with_index do |row, i|
78
+ row.each_with_index do |color, x|
79
+ if window.mouse_x.between?(@x+(x*@size), @x+(x*@size) + @size)
80
+ if window.mouse_y.between?(@y + (@size*i), @y + (@size*i) + @size)
81
+ @active_color = color
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ def draw_colors
90
+ @color_set.each_with_index do |row, i|
91
+ row.each_with_index do |color, x|
92
+ z = color == @active_color ? 100 : 7
93
+ Gosu.draw_rect(
94
+ @x+(x*@size), @y+(@size*i),
95
+ @size, @size,
96
+ color,
97
+ z
98
+ )
99
+ end
100
+ end
101
+ end
102
+
103
+ def hightlight_active_color
104
+ @color_set.each_with_index do |row, i|
105
+ row.each_with_index do |color, x|
106
+ if color == @active_color
107
+ Gosu.draw_rect(@x+(x*@size)-window.square_scale, (@y+(@size*i))-window.square_scale, @size+(window.square_scale*2), @size+(window.square_scale*2), Gosu::Color.rgba(255,255,255, 200), 8)
108
+ break
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,134 @@
1
+ class AuthorEngine
2
+ class SaveFile
3
+ SpriteSheetData = Struct.new(:columns, :rows, :to_blob)
4
+
5
+ def self.create(file)
6
+ if File.exists?(file)
7
+ return false
8
+ else
9
+ File.open(file, "w") {|f| f.write ""}
10
+ if File.exists?(file)
11
+ return true
12
+ else
13
+ return false
14
+ end
15
+ end
16
+ end
17
+
18
+ attr_reader :file
19
+ attr_reader :code, :sprites, :levels
20
+ def initialize(file)
21
+ @file = file
22
+ @buffer = ""
23
+
24
+ @code, @sprites, @levels = nil, nil, nil
25
+
26
+ load
27
+ end
28
+
29
+ def save
30
+ save_code
31
+ save_spritesheet
32
+ save_levels
33
+
34
+ File.open(@file, "w") do |f|
35
+ f.write @buffer
36
+ end
37
+
38
+ @buffer = ""
39
+ puts "Saved #{file}"
40
+ end
41
+
42
+ def save_code
43
+ @buffer+= "___CODE___\n"
44
+ @buffer+= CodeEditor.instance.code
45
+ # @buffer+="\n" # CodeEditor always has this newline
46
+ end
47
+
48
+ def save_spritesheet
49
+ sheet = SpriteEditor.instance.spritesheet
50
+
51
+ @buffer+= "___SPRITES___\n"
52
+ @buffer+="#{sheet.width}x#{sheet.height}"
53
+ @buffer+="\n"
54
+
55
+ pack = sheet.to_blob.unpack('H*').first
56
+ # @buffer+= pack
57
+ pack.chars.each_slice(1024) do |slice|
58
+ @buffer+=slice.join
59
+ @buffer+="\n"
60
+ end
61
+
62
+ @buffer+="\n"
63
+ end
64
+
65
+ def save_levels
66
+ @buffer+= "___LEVELS___\n"
67
+ # @buffer+= LevelEditor.instance.levels
68
+ @buffer+="\n"
69
+ end
70
+
71
+ def load
72
+ file = ""
73
+ File.open(@file, "r") {|f| file = f.read}
74
+
75
+ load_code(file)
76
+ load_spritesheet(file)
77
+ load_levels(file)
78
+ end
79
+
80
+ def load_code(file)
81
+ buffer = ""
82
+ in_code= false
83
+ file.each_line do |line|
84
+ if line.start_with?("___CODE___")
85
+ in_code = true
86
+ next
87
+ end
88
+ if line.start_with?("___") && in_code
89
+ break
90
+ end
91
+
92
+ buffer+="#{line}" if in_code
93
+ end
94
+
95
+ @code = buffer
96
+ end
97
+
98
+ def load_spritesheet(file)
99
+ buffer = ""
100
+ width = 0
101
+ height = 0
102
+ in_sprites = false
103
+
104
+ file.each_line do |line|
105
+ if line.strip.start_with?("___SPRITES___")
106
+ in_sprites = true
107
+ next
108
+ end
109
+ if line.start_with?("___") && in_sprites
110
+ break
111
+ end
112
+
113
+ next unless in_sprites
114
+
115
+ if line.include?("x")
116
+ a = line.strip.split("x")
117
+ width = a.first.to_i
118
+ height = a.last.to_i
119
+ next
120
+ end
121
+
122
+
123
+ buffer += line.strip
124
+ end
125
+
126
+ stream = buffer.scan(/../).map { |x| x.hex }.pack('c*')
127
+
128
+ @sprites = SpriteSheetData.new(width, height, stream)
129
+ end
130
+
131
+ def load_levels(file)
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,4 @@
1
+ class AuthorEngine
2
+ class Sprite
3
+ end
4
+ end
@@ -0,0 +1,154 @@
1
+ class AuthorEngine
2
+ class SpritePicker
3
+ include Support
4
+
5
+ attr_reader :active_sprite
6
+ attr_reader :x, :y, :width, :height
7
+ attr_reader :rows, :columns
8
+ def initialize(x: nil, y:, width: nil, height: nil)
9
+ @x, @y, @width, @height = x, y, width, height
10
+ @sprite_size = window.sprite_size
11
+ @scaled_sprite_size = @sprite_size * window.square_scale
12
+ @active_sprite = 0 # array index
13
+
14
+ @width = width ? width : window.width - (@scaled_sprite_size)
15
+ @height= height ? height : @scaled_sprite_size*2
16
+
17
+ @x = x ? x : window.width/2 - @width/2
18
+
19
+ @columns = (@width / @scaled_sprite_size).floor
20
+ @rows = (@height / @scaled_sprite_size).floor
21
+
22
+ @offset = 1 * window.square_scale
23
+ @tooltip = AuthorEngine::Text.new(message: "", z: 100)
24
+ @current_page = AuthorEngine::Text.new(message: "Page 0", size: 20, x: window.width/2, y: @y - 24, z: 100)
25
+
26
+ @page = 0
27
+ end
28
+
29
+ def draw
30
+ Gosu.draw_rect(@x-@offset, @y-@offset, @width+(@offset*2), @height+(@offset*2), Gosu::Color::WHITE, 15)
31
+ Gosu.draw_rect(@x, @y, @width, @height, Gosu::Color.rgba(10, 10, 10, 200), 15)
32
+ draw_grid
33
+ draw_sprites
34
+
35
+ draw_and_update_tooltip
36
+ @current_page.message = "Page #{@page}"
37
+ @current_page.draw
38
+ end
39
+
40
+ def draw_grid
41
+ (@columns-1).times do |i|
42
+ i += 1
43
+ # Vertical line
44
+ Gosu.draw_rect((@x + (i * @width / @columns)) - 1, @y, 1, @height, Gosu::Color::WHITE, 17)
45
+ end
46
+ #Horizontal line
47
+ (@rows-1).times do |i|
48
+ Gosu.draw_rect(@x, (@y + (i * @height / @rows)) + @scaled_sprite_size, @width, 1, Gosu::Color::WHITE, 17)
49
+ end
50
+ end
51
+
52
+ def draw_sprites
53
+ y = @y
54
+ x = @x
55
+ n = 0
56
+ size = (@columns * @rows)
57
+ index = size * @page
58
+
59
+ SpriteEditor.instance.sprites[index..(index + size)].each_with_index do |sprite, i|
60
+ sprite.draw(x, y, 16, 1.0 * window.square_scale, 1.0 * window.square_scale) if sprite
61
+ x+=@scaled_sprite_size
62
+
63
+ if n >= @columns-1
64
+ y+=@scaled_sprite_size
65
+ x = @x
66
+ n = 0
67
+ else
68
+ n += 1
69
+ end
70
+ end
71
+
72
+ highlight_sprite
73
+ end
74
+
75
+ def highlight_sprite
76
+ sprite_block do |x, y|
77
+ Gosu.draw_rect(x + @x, y + @y, @sprite_size * window.square_scale, @sprite_size * window.square_scale, Gosu::Color.rgba(0,0,0, 50), 17)
78
+ end
79
+ end
80
+
81
+ def mouse_over_sprite?(x, y, width, height)
82
+ if window.mouse_x.between?(x, x + width) &&
83
+ window.mouse_y.between?(y, y + height)
84
+ return true
85
+ end
86
+ end
87
+
88
+ def draw_and_update_tooltip
89
+ found = false
90
+
91
+ sprite_block do |x,y,index|
92
+ if @tooltip
93
+ @tooltip.message = "#{index}"
94
+ @tooltip.x = window.mouse_x - @tooltip.width/2
95
+ @tooltip.y = window.mouse_y - @tooltip.height
96
+ end
97
+
98
+ found = true
99
+ end
100
+
101
+ if found
102
+ Gosu.draw_rect(@tooltip.x - @offset, @tooltip.y - @offset, @tooltip.width+(@offset*2), @tooltip.height+(@offset), Gosu::Color.rgba(0,0,0,100), 100)
103
+ @tooltip.draw
104
+ else
105
+ @tooltip.message = ""
106
+ end
107
+ end
108
+
109
+ def select_sprite
110
+ sprite_block do |x, y, index|
111
+ @active_sprite = index
112
+ SpriteEditor.instance.set_sprite
113
+ end
114
+ end
115
+
116
+ def sprite_block(&block)
117
+ found = false
118
+ index = @page * (@columns * @rows)
119
+
120
+ @rows.times do |y|
121
+ _y = y * @scaled_sprite_size
122
+ break if found
123
+
124
+ @columns.times do |x|
125
+ break if found
126
+ _x = x * @scaled_sprite_size
127
+
128
+ if mouse_over_sprite?(_x + @x, _y + @y, @sprite_size * window.square_scale, @sprite_size * window.square_scale)
129
+ found = true
130
+ block.call(_x, _y, index, found) if block
131
+ end
132
+
133
+ break if index >= 255
134
+ index+=1
135
+ end
136
+ end
137
+ end
138
+
139
+ def button_up(id)
140
+ case id
141
+ when Gosu::MsLeft
142
+ if mouse_over?(self)
143
+ select_sprite
144
+ end
145
+ when Gosu::KbLeft
146
+ @page-=1
147
+ @page = (255/(@rows * @columns)) if @page < 0
148
+ when Gosu::KbRight
149
+ @page+=1
150
+ @page = 0 if @page > (255/(@rows * @columns))
151
+ end
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,22 @@
1
+ class AuthorEngine
2
+ module Support
3
+ def window
4
+ Window.instance
5
+ end
6
+
7
+ def code_editor
8
+ CodeEditor.instance
9
+ end
10
+
11
+ def sprite_editor
12
+ SpriteEditor.instance
13
+ end
14
+
15
+ def mouse_over?(object)
16
+ if window.mouse_x.between?(object.x, object.x + object.width) &&
17
+ window.mouse_y.between?( object.y, object.y + object.height)
18
+ true
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,41 @@
1
+ class AuthorEngine
2
+ class Text
3
+ include Support
4
+ FONT_DEFAULT = "assets/fonts/Connection.otf"
5
+ FONT_DEFAULT_BOLD = "assets/fonts/ConnectionBold.otf"
6
+
7
+ attr_accessor :message, :x, :y, :z, :color
8
+ attr_reader :size, :font
9
+ def initialize(message: "", size: nil, x: 0, y: 0, z: 0, color: Gosu::Color::WHITE, font: FONT_DEFAULT) # Consolas
10
+ @message = message
11
+ @size = size ? size : (8 * window.scale_y).floor
12
+ @x, @y, @z = x, y, z
13
+ @color, @font_name = color, font
14
+
15
+ @font = Gosu::Font.new(@size, name: @font_name)
16
+ end
17
+
18
+ def width
19
+ @font.text_width(@message)
20
+ end
21
+
22
+ def width_markup
23
+ @font.markup_width(@message)
24
+ end
25
+
26
+ def height
27
+ @font.height
28
+ end
29
+
30
+ def draw
31
+ @font.draw_text(@message, @x, @y, @z, 1, 1, @color)
32
+ end
33
+
34
+ def draw_markup
35
+ @font.draw_markup(@message, @x, @y, @z, 1, 1, @color)
36
+ end
37
+
38
+ def update
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ class AuthorEngine
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,55 @@
1
+ class AuthorEngine
2
+ class View
3
+ include Support
4
+ include AuthorEngine::Part::Colors
5
+
6
+ def self.instance
7
+ @instance
8
+ end
9
+
10
+ def self.instance=(klass)
11
+ @instance = klass
12
+ end
13
+
14
+ attr_reader :x, :y, :width, :height, :background
15
+ def initialize(x:, y:, width:, height:, background: Gosu::Color::BLACK)
16
+ @x, @y, @width, @height, @background = x, y, width, height, background
17
+
18
+ @x_padding = Button::PADDING * window.scale_x
19
+ @y_padding = Button::PADDING * window.scale_y
20
+
21
+ self.class.instance = self
22
+ setup
23
+ end
24
+
25
+ def setup
26
+ end
27
+
28
+ def focus
29
+ end
30
+
31
+ def blur
32
+ end
33
+
34
+ def draw
35
+ Gosu.draw_rect(@x, @y, @width, @height, @background)
36
+ end
37
+
38
+ def mouse_inside_view?
39
+ if window.mouse_x.between?(@x, @x+@width)
40
+ if window.mouse_y.between?(@y, @y+@height)
41
+ return true
42
+ end
43
+ end
44
+ end
45
+
46
+ def update
47
+ end
48
+
49
+ def button_down(id)
50
+ end
51
+
52
+ def button_up(id)
53
+ end
54
+ end
55
+ end