author_engine 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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