Compare commits

..

18 Commits

Author SHA1 Message Date
a1513be709 Get rvx bundle exec rake release functional... 2026-10-04 23:43:02 -05:00
d0d5bbac3a Bump version 2026-10-04 23:39:37 -05:00
0ae3ecc145 Fix up some errors with BFS and pathfinding grid 2026-10-04 19:30:58 -05:00
afa8a9dbb6 Add asset textures for nine sliced rounded corners and the like 2026-09-28 19:13:56 -05:00
0ec55bef55 Fixed typo in BFS file name, require pathfinding bits. 2026-09-28 19:13:25 -05:00
904ac78d89 More work on pathfinding support 2026-09-28 15:22:42 -05:00
70d270688f Added .idea to gitignore, first pass at adding intregrated pathfindiing support using redblobgames.com tutorials as reference 2026-09-28 09:35:45 -05:00
685c94bd1b Fixed using this instead of self for slider and check box 2026-09-27 18:16:47 -05:00
d6d3c07bbc First pass at adding fixed update support 2026-09-27 18:06:13 -05:00
2cc1382696 Fixed Text border color not getting set correctly due to misnamed color parameter, generate Text border image with true white text since we draw it with the requested color later. 2026-09-20 16:10:10 -05:00
9fca64b643 Added render mode to BackgroundNineSlice 2026-09-19 19:10:39 -05:00
abe99ce949 Ignore sibling elements that aren't visible from fill mode space considerations 2026-09-17 12:25:48 -05:00
66fb136c83 Make elements sizing by like css' border-box box-sizing instead of like content-box for elements with specific width/height that isn't a ratio, tweaks to gui debug display, make F12 key toggle gui debug display for convenience 2026-09-11 13:05:08 -05:00
b23e5c2a42 Fix pending element recalculate requests apparently not getting processed properly... 2026-09-10 18:32:01 -05:00
747822aa61 Fixed flow containers not correctly positioning their children on the x axis when they wrap to the the next line, fix up containers vertical and horizontal alignment 2026-09-10 18:31:19 -05:00
140e7a3619 Make elements publish the :size_changed event when they change their size 2026-09-09 22:30:19 -05:00
349222f387 Flip flop Element#resolution_scaled 2026-09-04 10:31:30 -05:00
9d4bc89174 Fix Widget element unable to find children element tooltips if the widget's parent(s) had been scrolled 2026-09-04 10:31:02 -05:00
36 changed files with 314 additions and 61 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
/.idea
/.bundle/ /.bundle/
/.yardoc /.yardoc
/_yardoc/ /_yardoc/

View File

@@ -1,25 +1,37 @@
PATH PATH
remote: . remote: .
specs: specs:
cyberarm_engine (0.24.5) cyberarm_engine (0.30.0)
gosu (~> 1.1) gosu (~> 1.1)
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
gosu (1.4.6) ffi (1.17.4-x86_64-linux-gnu)
minitest (5.25.5) ffi (1.17.4-x86_64-linux-musl)
rake (13.2.1) gosu (1.5.0-x86_64-linux)
ffi (~> 1.12)
minitest (5.27.0)
rake (13.4.2)
PLATFORMS PLATFORMS
x64-mingw-ucrt x86_64-linux-gnu
x86_64-linux x86_64-linux-musl
DEPENDENCIES DEPENDENCIES
bundler (~> 2.2) bundler (~> 4)
cyberarm_engine! cyberarm_engine!
minitest (~> 5.0) minitest (~> 5.0)
rake (~> 13.0) rake (~> 13.0)
CHECKSUMS
bundler (4.1.0.beta1) sha256=8a2dac8ca276ff4eff5efc2c6457b0044080fc1e431534ad7c5cc6187232b800
cyberarm_engine (0.30.0)
ffi (1.17.4-x86_64-linux-gnu) sha256=9d3db14c2eae074b382fa9c083fe95aec6e0a1451da249eab096c34002bc752d
ffi (1.17.4-x86_64-linux-musl) sha256=3fdf9888483de005f8ef8d1cf2d3b20d86626af206cbf780f6a6a12439a9c49e
gosu (1.5.0-x86_64-linux)
minitest (5.27.0) sha256=2d3b17f8a36fe7801c1adcffdbc38233b938eb0b4966e97a6739055a45fa77d5
rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
BUNDLED WITH BUNDLED WITH
2.6.8 4.1.0.beta1

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

View File

@@ -28,9 +28,8 @@ Gem::Specification.new do |spec|
spec.require_paths = %w[lib assets] spec.require_paths = %w[lib assets]
spec.add_dependency "gosu", "~> 1.1" spec.add_dependency "gosu", "~> 1.1"
# spec.add_dependency "ffi", :platforms => [:mswin, :mingw] # Required by Clipboard on Windows
spec.add_development_dependency "bundler", "~> 2.2" spec.add_development_dependency "bundler", "~> 4"
spec.add_development_dependency "minitest", "~> 5.0" spec.add_development_dependency "minitest", "~> 5.0"
spec.add_development_dependency "rake", "~> 13.0" spec.add_development_dependency "rake", "~> 13.0"
end end

View File

@@ -42,6 +42,13 @@ require_relative "cyberarm_engine/console/command"
require_relative "cyberarm_engine/console/subcommand" require_relative "cyberarm_engine/console/subcommand"
require_relative "cyberarm_engine/console/commands/help_command" require_relative "cyberarm_engine/console/commands/help_command"
require_relative "cyberarm_engine/pathfinding/graph"
require_relative "cyberarm_engine/pathfinding/graphs/grid"
require_relative "cyberarm_engine/pathfinding/graph_search"
require_relative "cyberarm_engine/pathfinding/graph_searches/breadth_first_search"
require_relative "cyberarm_engine/pathfinding/graph_searches/dijkstra_search"
require_relative "cyberarm_engine/pathfinding/graph_searches/astar_search"
require_relative "cyberarm_engine/ui/dsl" require_relative "cyberarm_engine/ui/dsl"
require_relative "cyberarm_engine/ui/theme" require_relative "cyberarm_engine/ui/theme"

View File

@@ -4,10 +4,10 @@ module CyberarmEngine
CACHE = {} CACHE = {}
attr_accessor :x, :y, :z, :width, :height, :mode, :color attr_accessor :x, :y, :z, :width, :height, :mode, :color, :render_mode
attr_reader :image, :left, :top, :right, :bottom attr_reader :image, :left, :top, :right, :bottom
def initialize(image_path: nil, x: 0, y: 0, z: 0, width: 0, height: 0, mode: :tiled, left: 1, top: 1, right: 1, bottom: 1, color: Gosu::Color::WHITE) def initialize(image_path: nil, x: 0, y: 0, z: 0, width: 0, height: 0, mode: :tiled, left: 1, top: 1, right: 1, bottom: 1, color: Gosu::Color::WHITE, render_mode: :default)
@image = get_image(image_path) if image_path @image = get_image(image_path) if image_path
@x = x @x = x
@@ -25,6 +25,7 @@ module CyberarmEngine
@bottom = bottom @bottom = bottom
@color = color @color = color
@render_mode = render_mode
nine_slice if @image nine_slice if @image
end end
@@ -121,58 +122,58 @@ module CyberarmEngine
end end
def draw_stretched def draw_stretched
@segment_top_left.draw(@x, @y, @z, 1, 1, @color) @segment_top_left.draw(@x, @y, @z, 1, 1, @color, @render_mode)
@segment_top.draw(@x + @segment_top_left.width, @y, @z, width_scale, 1, @color) # SCALE X @segment_top.draw(@x + @segment_top_left.width, @y, @z, width_scale, 1, @color, @render_mode) # SCALE X
@segment_top_right.draw((@x + @width) - @segment_top_right.width, @y, @z, 1, 1, @color) @segment_top_right.draw((@x + @width) - @segment_top_right.width, @y, @z, 1, 1, @color, @render_mode)
@segment_right.draw((@x + @width) - @segment_right.width, @y + @top, @z, 1, height_scale, @color) # SCALE Y @segment_right.draw((@x + @width) - @segment_right.width, @y + @top, @z, 1, height_scale, @color, @render_mode) # SCALE Y
@segment_bottom_right.draw((@x + @width) - @segment_bottom_right.width, @y + @height - @segment_bottom_right.height, @z, 1, 1, @color) @segment_bottom_right.draw((@x + @width) - @segment_bottom_right.width, @y + @height - @segment_bottom_right.height, @z, 1, 1, @color, @render_mode)
@segment_bottom.draw(@x + @segment_bottom_left.width, (@y + @height) - @segment_bottom.height, @z, width_scale, 1, @color) # SCALE X @segment_bottom.draw(@x + @segment_bottom_left.width, (@y + @height) - @segment_bottom.height, @z, width_scale, 1, @color, @render_mode) # SCALE X
@segment_bottom_left.draw(@x, (@y + @height) - @segment_bottom_left.height, @z, 1, 1, @color) @segment_bottom_left.draw(@x, (@y + @height) - @segment_bottom_left.height, @z, 1, 1, @color, @render_mode)
@segment_left.draw(@x, @y + @top, @z, 1, height_scale, @color) # SCALE Y @segment_left.draw(@x, @y + @top, @z, 1, height_scale, @color, @render_mode) # SCALE Y
@segment_middle.draw(@x + @segment_top_left.width, @y + @segment_top.height, @z, width_scale, height_scale, @color) # SCALE X and SCALE Y @segment_middle.draw(@x + @segment_top_left.width, @y + @segment_top.height, @z, width_scale, height_scale, @color, @render_mode) # SCALE X and SCALE Y
end end
def draw_tiled def draw_tiled
@segment_top_left.draw(@x, @y, @z, 1, 1, @color) @segment_top_left.draw(@x, @y, @z, 1, 1, @color, @render_mode)
# p [width_scale, height_scale] # p [width_scale, height_scale]
Gosu.clip_to(@x + @segment_top_left.width, @y, @segment_top.width * width_scale, @segment_top.height) do Gosu.clip_to(@x + @segment_top_left.width, @y, @segment_top.width * width_scale, @segment_top.height) do
width_scale.ceil.times do |i| width_scale.ceil.times do |i|
@segment_top.draw(@x + @segment_top_left.width + (@segment_top.width * i), @y, @z, 1, 1, @color) # SCALE X @segment_top.draw(@x + @segment_top_left.width + (@segment_top.width * i), @y, @z, 1, 1, @color, @render_mode) # SCALE X
end end
end end
@segment_top_right.draw((@x + @width) - @segment_top_right.width, @y, @z, 1, 1, @color) @segment_top_right.draw((@x + @width) - @segment_top_right.width, @y, @z, 1, 1, @color, @render_mode)
Gosu.clip_to(@x + @width - @segment_top_right.width, @y + @top, @segment_right.width, @segment_right.height * height_scale) do Gosu.clip_to(@x + @width - @segment_top_right.width, @y + @top, @segment_right.width, @segment_right.height * height_scale) do
height_scale.ceil.times do |i| height_scale.ceil.times do |i|
@segment_right.draw((@x + @width) - @segment_right.width, @y + @top + (@segment_right.height * i), @z, 1, 1, @color) # SCALE Y @segment_right.draw((@x + @width) - @segment_right.width, @y + @top + (@segment_right.height * i), @z, 1, 1, @color, @render_mode) # SCALE Y
end end
end end
@segment_bottom_right.draw((@x + @width) - @segment_bottom_right.width, @y + @height - @segment_bottom_right.height, @z, 1, 1, @color) @segment_bottom_right.draw((@x + @width) - @segment_bottom_right.width, @y + @height - @segment_bottom_right.height, @z, 1, 1, @color, @render_mode)
Gosu.clip_to(@x + @segment_top_left.width, @y + @height - @segment_bottom.height, @segment_top.width * width_scale, @segment_bottom.height) do Gosu.clip_to(@x + @segment_top_left.width, @y + @height - @segment_bottom.height, @segment_top.width * width_scale, @segment_bottom.height) do
width_scale.ceil.times do |i| width_scale.ceil.times do |i|
@segment_bottom.draw(@x + @segment_bottom_left.width + (@segment_bottom.width * i), (@y + @height) - @segment_bottom.height, @z, 1, 1, @color) # SCALE X @segment_bottom.draw(@x + @segment_bottom_left.width + (@segment_bottom.width * i), (@y + @height) - @segment_bottom.height, @z, 1, 1, @color, @render_mode) # SCALE X
end end
end end
@segment_bottom_left.draw(@x, (@y + @height) - @segment_bottom_left.height, @z, 1, 1, @color) @segment_bottom_left.draw(@x, (@y + @height) - @segment_bottom_left.height, @z, 1, 1, @color, @render_mode)
Gosu.clip_to(@x, @y + @top, @segment_left.width, @segment_left.height * height_scale) do Gosu.clip_to(@x, @y + @top, @segment_left.width, @segment_left.height * height_scale) do
height_scale.ceil.times do |i| height_scale.ceil.times do |i|
@segment_left.draw(@x, @y + @top + (@segment_left.height * i), @z, 1, 1, @color) # SCALE Y @segment_left.draw(@x, @y + @top + (@segment_left.height * i), @z, 1, 1, @color, @render_mode) # SCALE Y
end end
end end
Gosu.clip_to(@x + @segment_top_left.width, @y + @segment_top.height, @width - (@segment_left.width + @segment_right.width), @height - (@segment_top.height + @segment_bottom.height)) do Gosu.clip_to(@x + @segment_top_left.width, @y + @segment_top.height, @width - (@segment_left.width + @segment_right.width), @height - (@segment_top.height + @segment_bottom.height)) do
height_scale.ceil.times do |y| height_scale.ceil.times do |y|
width_scale.ceil.times do |x| width_scale.ceil.times do |x|
@segment_middle.draw(@x + @segment_top_left.width + (@segment_middle.width * x), @y + @segment_top.height + (@segment_middle.height * y), @z, 1, 1, @color) # SCALE X and SCALE Y @segment_middle.draw(@x + @segment_top_left.width + (@segment_middle.width * x), @y + @segment_top.height + (@segment_middle.height * y), @z, 1, 1, @color, @render_mode) # SCALE X and SCALE Y
end end
end end
end end

View File

@@ -1,4 +1,6 @@
module CyberarmEngine module CyberarmEngine
GUI_DEBUG = false
module Common module Common
ImageBlob = Data.define(:to_blob, :columns, :rows) ImageBlob = Data.define(:to_blob, :columns, :rows)

View File

@@ -33,6 +33,9 @@ module CyberarmEngine
@timers.delete_if(&:dead?) @timers.delete_if(&:dead?)
end end
def fixed_update(dt)
end
def needs_redraw? def needs_redraw?
true true
end end

View File

@@ -0,0 +1,64 @@
module CyberarmEngine
module Pathfinding
class Graph
class Node
KEY_FORMAT = "%s:%s:%s".freeze
attr_reader :x, :y, :z, :cost, :key, :edge_nodes
def initialize(x:, y:, z: 0, cost: 0)
@x = x
@y = y
@z = z
@cost = cost
@key = format(KEY_FORMAT, @x, @y, @z).freeze
@edge_nodes = []
end
def add_edge_node(node)
index = @edge_nodes.find_index { |n| n.key == node.key }
return if index
@edge_nodes.push(node)
end
def remove_edge_node(node)
index = @edge_nodes.find_index { |n| n.key == node.key }
return unless index
@edge_nodes.delete(index)
end
def inspect
format "#<%<class>s:%<id>#018x @key=%<key>s @cost=%<cost>s @edge_nodes=%<edge_nodes>s>",
class: self.class,
id: object_id << 1,
key: key.inspect,
cost: cost.inspect,
edge_nodes: edge_nodes.map { |n| n&.key }
end
end
def initialize(nodes: {})
@nodes = nodes
end
def node(key)
@nodes[key]
end
def node_at(x, y, z = 0)
key = format(Node::KEY_FORMAT, x, y, z)
@nodes[key]
end
def neighbors(node)
node.edge_nodes
end
end
end
end

View File

@@ -0,0 +1,6 @@
module CyberarmEngine
module Pathfinding
class GraphSearch
end
end
end

View File

@@ -0,0 +1,6 @@
module CyberarmEngine
module Pathfinding
class AStarSearch < GraphSearch
end
end
end

View File

@@ -0,0 +1,27 @@
module CyberarmEngine
module Pathfinding
class BreadthFirstSearch < GraphSearch
def self.search(graph:, start:, goal: nil)
frontier = []
came_from = {}
frontier.push(start)
came_from[start.key] = start
while(current = frontier.shift)
# early exit if we reach our goal
break if current == goal
graph.neighbors(current).each do |neighbor|
next if came_from[neighbor.key]
frontier.push(neighbor)
came_from[neighbor.key] = current
end
end
came_from
end
end
end
end

View File

@@ -0,0 +1,6 @@
module CyberarmEngine
module Pathfinding
class DijkstraSearch < GraphSearch
end
end
end

View File

@@ -0,0 +1,52 @@
module CyberarmEngine
module Pathfinding
class Grid < Graph
def add_node(x:, y:, z: 0, cost: 0, replace: false)
key = format(Node::KEY_FORMAT, x, y, z)
node = @nodes[key]
raise "Node at: #{key} already exists! (#{node})" if node && !replace
node = Node.new(x: x, y: y, z: z, cost: cost)
@nodes[key] = node
update_node_edge_nodes(node)
node
end
def remove_node(node)
update_node_edge_nodes(node, remove_node: true)
@nodes.delete(node.key)
end
def update_node_edge_nodes(node, remove_node: false)
x = node.x
y = node.y
z = node.z
# add node to neighbors
# 2D
left = @nodes[format(Node::KEY_FORMAT, x - 1, y, z)]
right = @nodes[format(Node::KEY_FORMAT, x + 1, y, z)]
top = @nodes[format(Node::KEY_FORMAT, x, y - 1, z)]
bottom = @nodes[format(Node::KEY_FORMAT, x, y + 1, z)]
# 3D
front = @nodes[format(Node::KEY_FORMAT, x, y, z - 1)]
back = @nodes[format(Node::KEY_FORMAT, x, y, z + 1)]
possible_edge_nodes = [left, right, top, bottom, front, back]
if remove_node
possible_edge_nodes.each { |n| n&.remove_edge_node(node) }
else
possible_edge_nodes.each { |n| n&.add_edge_node(node) }
end
end
def update_edge_nodes
@nodes.each { |k, n| update_node_edge_nodes(n) }
end
end
end
end

View File

@@ -149,7 +149,7 @@ module CyberarmEngine
@border_alpha = n @border_alpha = n
end end
def border_color=(n) def border_color=(color)
old_color = @border_color old_color = @border_color
if color if color
@@ -208,17 +208,17 @@ module CyberarmEngine
img = Gosu::Image.send(:"from_#{method.to_s.split("_").last}", @text, @size, font: @font) img = Gosu::Image.send(:"from_#{method.to_s.split("_").last}", @text, @size, font: @font)
@cached_text_border_image = Gosu.render((_width + (@border_size * 2)).ceil, (height + (@border_size * 2)).ceil) do @cached_text_border_image = Gosu.render((_width + (@border_size * 2)).ceil, (height + (@border_size * 2)).ceil) do
img.draw(-_x, 0, @z, @factor_x, @factor_y, @border_color, @mode) img.draw(-_x, 0, @z, @factor_x, @factor_y, Gosu::Color::WHITE, @mode)
img.draw(-_x, -_y, @z, @factor_x, @factor_y, @border_color, @mode) img.draw(-_x, -_y, @z, @factor_x, @factor_y, Gosu::Color::WHITE, @mode)
img.draw(0, -_y, @z, @factor_x, @factor_y, @border_color, @mode) img.draw(0, -_y, @z, @factor_x, @factor_y, Gosu::Color::WHITE, @mode)
img.draw(_x, -_y, @z, @factor_x, @factor_y, @border_color, @mode) img.draw(_x, -_y, @z, @factor_x, @factor_y, Gosu::Color::WHITE, @mode)
img.draw(_x, 0, @z, @factor_x, @factor_y, @border_color, @mode) img.draw(_x, 0, @z, @factor_x, @factor_y, Gosu::Color::WHITE, @mode)
img.draw(_x, _y, @z, @factor_x, @factor_y, @border_color, @mode) img.draw(_x, _y, @z, @factor_x, @factor_y, Gosu::Color::WHITE, @mode)
img.draw(0, _y, @z, @factor_x, @factor_y, @border_color, @mode) img.draw(0, _y, @z, @factor_x, @factor_y, Gosu::Color::WHITE, @mode)
img.draw(-_x, _y, @z, @factor_x, @factor_y, @border_color, @mode) img.draw(-_x, _y, @z, @factor_x, @factor_y, Gosu::Color::WHITE, @mode)
end end
end end
@@ -256,7 +256,7 @@ module CyberarmEngine
@textobject.send(method, @text, _x + @border_size, _y + @border_size, @z, @factor_x, @factor_y, white, @mode) @textobject.send(method, @text, _x + @border_size, _y + @border_size, @z, @factor_x, @factor_y, white, @mode)
end end
@cached_text_border_image.draw(@x - @border_size, @y - @border_size, @z, @factor_x, @factor_y, border_color) @cached_text_border_image.draw(@x - @border_size, @y - @border_size, @z, @factor_x, @factor_y, border_color, @mode)
end end
if @shadow if @shadow

View File

@@ -18,7 +18,7 @@ module CyberarmEngine
@visible = !@options.key?(:visible) ? true : @options[:visible] @visible = !@options.key?(:visible) ? true : @options[:visible]
@tip = @options[:tip] || "" @tip = @options[:tip] || ""
@debug = @options[:debug] || CyberarmEngine.const_defined?("GUI_DEBUG") && CyberarmEngine::GUI_DEBUG || false @debug = @options[:debug].nil? ? nil : @options[:debug]
@debug_color = @options[:debug_color].nil? ? Gosu::Color::RED : @options[:debug_color] @debug_color = @options[:debug_color].nil? ? Gosu::Color::RED : @options[:debug_color]
@style = Style.new(options) @style = Style.new(options)
@@ -36,7 +36,7 @@ module CyberarmEngine
@width = 0 @width = 0
@height = 0 @height = 0
@style.width = default(:width) || nil @style.width = default(:width) || nil
@style.height = default(:height) || nil @style.height = default(:height) || nil
@background_canvas = nil # Background.new @background_canvas = nil # Background.new
@@ -56,7 +56,7 @@ module CyberarmEngine
def resolution_scaled(n) def resolution_scaled(n)
return n unless @style.design_width return n unless @style.design_width
((@style.design_width / Gosu.screen_width(window).to_f) * n).floor ((Gosu.screen_width(window).to_f / @style.design_width) * n).floor
end end
def stylize def stylize
@@ -215,6 +215,7 @@ module CyberarmEngine
event(:blur) event(:blur)
event(:changed) event(:changed)
event(:size_changed)
end end
def enter(_sender) def enter(_sender)
@@ -339,7 +340,7 @@ module CyberarmEngine
end end
def debug_draw def debug_draw
return unless @debug # allow elements to opt out of debug drawing, makes debugging some things easier. return if @debug == false || !CyberarmEngine::GUI_DEBUG # allow elements to opt out of debug drawing, makes debugging some things easier.
return if CyberarmEngine.const_defined?("GUI_DEBUG_ONLY_ELEMENT") && self.class == GUI_DEBUG_ONLY_ELEMENT return if CyberarmEngine.const_defined?("GUI_DEBUG_ONLY_ELEMENT") && self.class == GUI_DEBUG_ONLY_ELEMENT
Gosu.draw_line( Gosu.draw_line(
@@ -393,7 +394,7 @@ module CyberarmEngine
def width def width
if visible? if visible?
inner_width + @width inner_width + content_width
else else
0 0
end end
@@ -417,7 +418,7 @@ module CyberarmEngine
def height def height
if visible? if visible?
inner_height + @height inner_height + content_height
else else
0 0
end end
@@ -487,6 +488,8 @@ module CyberarmEngine
new_size = if size.is_a?(Float) && size.between?(0.0, 1.0) new_size = if size.is_a?(Float) && size.between?(0.0, 1.0)
(@parent.send(:"content_#{dimension}") * size).floor - send(:"noncontent_#{dimension}").floor (@parent.send(:"content_#{dimension}") * size).floor - send(:"noncontent_#{dimension}").floor
elsif size.is_a?(Numeric)
(size - send(:"noncontent_#{dimension}")).floor
else else
size size
end end
@@ -515,7 +518,7 @@ module CyberarmEngine
def space_available_height def space_available_height
# TODO: This may get expensive if there are a lot of children, probably should cache it somehow # TODO: This may get expensive if there are a lot of children, probably should cache it somehow
fill_siblings = @parent.children.select { |c| c.styled(:fill) }.count.to_f # include self since we're dividing fill_siblings = @parent.children.select { |c| c.styled(:fill) && c.visible? }.count.to_f # include self since we're dividing
available_space = ((@parent.content_height - (@parent.children.reject { |c| c.styled(:fill) }).map(&:outer_height).sum) / fill_siblings) available_space = ((@parent.content_height - (@parent.children.reject { |c| c.styled(:fill) }).map(&:outer_height).sum) / fill_siblings)
(available_space.nan? || available_space.infinite?) ? 0 : available_space.floor # The parent element might not have its dimensions, yet. (available_space.nan? || available_space.infinite?) ? 0 : available_space.floor # The parent element might not have its dimensions, yet.
@@ -576,6 +579,8 @@ module CyberarmEngine
@old_width = width @old_width = width
@old_height = height @old_height = height
publish(:size_changed)
end end
end end

View File

@@ -46,7 +46,7 @@ module CyberarmEngine
end end
def value=(bool) def value=(bool)
old_value = this.value old_value = self.value
@toggle_button.value = bool @toggle_button.value = bool
publish(:changed, bool) if bool != old_value publish(:changed, bool) if bool != old_value

View File

@@ -88,17 +88,20 @@ module CyberarmEngine
Gosu.translate(@scroll_position.x, @scroll_position.y) do Gosu.translate(@scroll_position.x, @scroll_position.y) do
@children.each(&:draw) @children.each(&:draw)
@children.each do |child|
next unless child.visible?
child.debug_draw
end
end end
end end
@children.each(&:debug_draw)
debug_draw debug_draw
end end
def debug_draw def debug_draw
super super
@children.each(&:debug_draw)
end end
def update def update
@@ -203,9 +206,9 @@ module CyberarmEngine
case styled(:v_align) case styled(:v_align)
when :center when :center
@y = parent.y + parent.styled(:margin_top) + parent.height / 2 - height / 2 @y = parent.y + parent.outer_height / 2 - outer_height / 2
when :bottom when :bottom
@y = parent.y + parent.styled(:margin_top) + parent.height - height @y = parent.y + parent.outer_height - outer_height
end end
end end
@@ -214,9 +217,9 @@ module CyberarmEngine
case styled(:h_align) case styled(:h_align)
when :center when :center
@x = parent.x + parent.styled(:margin_left) + parent.width / 2 - width / 2 @x = parent.x + parent.outer_width / 2 - outer_width / 2
when :right when :right
@x = parent.x + parent.styled(:margin_left) + parent.width - width @x = parent.x + parent.outer_width - outer_width
end end
end end
@@ -285,7 +288,7 @@ module CyberarmEngine
end end
def position_on_next_line(element) # Flow def position_on_next_line(element) # Flow
@current_position.x = 0 @current_position.x = styled(:margin_left) + styled(:padding_left)
@current_position.y += tallest_neighbor(element, @current_position.y).outer_height @current_position.y += tallest_neighbor(element, @current_position.y).outer_height
element.x = @current_position.x element.x = @current_position.x

View File

@@ -94,7 +94,7 @@ module CyberarmEngine
end end
def value=(n) def value=(n)
old_value = this.value old_value = self.value
@value = n @value = n
position_handle position_handle

View File

@@ -24,7 +24,16 @@ module CyberarmEngine
# Enable child elements to display their tooltips # Enable child elements to display their tooltips
# but fall back to the Widget if no hit element has a tip # but fall back to the Widget if no hit element has a tip
def tip def tip
elements = hit_element?(window.mouse_x, window.mouse_y) parent_scroll_position = CyberarmEngine::Vector.new
element = self
while (parent_element = element.parent)
parent_scroll_position += parent_element.scroll_position
element = parent_element
end
elements = hit_element?(window.mouse_x - parent_scroll_position.x, window.mouse_y - parent_scroll_position.y)
return @tip unless elements return @tip unless elements

View File

@@ -98,7 +98,15 @@ module CyberarmEngine
Stats.frame.start_timing(:gui_element_recalculate_requests) Stats.frame.start_timing(:gui_element_recalculate_requests)
# puts "PENDING REQUESTS: #{@pending_element_recalculate_requests.size}" if @pending_element_recalculate_requests.size.positive? # puts "PENDING REQUESTS: #{@pending_element_recalculate_requests.size}" if @pending_element_recalculate_requests.size.positive?
@pending_element_recalculate_requests.shift(&:recalculate) while (e = @pending_element_recalculate_requests.shift)
# its pointless to recalculate individual elements when we've been asked to recalculate the whole gui
if @pending_recalculate_request
@pending_element_recalculate_requests.clear
break
end
e.recalculate
end
Stats.frame.end_timing(:gui_element_recalculate_requests) Stats.frame.end_timing(:gui_element_recalculate_requests)
@@ -231,6 +239,9 @@ module CyberarmEngine
redirect_mouse_button(:right) redirect_mouse_button(:right)
when Gosu::KB_F5 when Gosu::KB_F5
request_recalculate request_recalculate
when Gosu::KB_F12
CyberarmEngine.const_set(:GUI_DEBUG, !CyberarmEngine::GUI_DEBUG)
request_repaint
end end
@focus.button_down(id) if @focus.respond_to?(:button_down) @focus.button_down(id) if @focus.respond_to?(:button_down)

View File

@@ -1,4 +1,4 @@
module CyberarmEngine module CyberarmEngine
NAME = "InDev".freeze NAME = "InDev".freeze
VERSION = "0.25.1".freeze VERSION = "0.30.0".freeze
end end

View File

@@ -6,6 +6,9 @@ module CyberarmEngine
SAMPLES = {} SAMPLES = {}
SONGS = {} SONGS = {}
FixedUpdateProperties = Data.define(:fixed_timestep, :fixed_timestep_int_ms, :max_timestep)
FixedUpdate = Struct.new(:milliseconds, :accumulator, :interpolation, :alpha)
attr_accessor :show_cursor, :show_stats_plotter attr_accessor :show_cursor, :show_stats_plotter
attr_writer :exit_on_opengl_error attr_writer :exit_on_opengl_error
attr_reader :last_frame_time, :delta_time, :states attr_reader :last_frame_time, :delta_time, :states
@@ -28,7 +31,7 @@ module CyberarmEngine
@@instance @@instance
end end
def initialize(width: 800, height: 600, fullscreen: false, update_interval: 1000.0 / 60, resizable: false, borderless: false) def initialize(width: 800, height: 600, fullscreen: false, update_interval: 1000.0 / 60, resizable: false, borderless: false, fixed_update_timestep: 1.0 / 125, fixed_update_timestep_int_ms: 8, fixed_max_timestep: 1.0 / 60)
@show_cursor = false @show_cursor = false
@has_focus = false @has_focus = false
@show_stats_plotter = false @show_stats_plotter = false
@@ -46,6 +49,9 @@ module CyberarmEngine
preload_default_shaders if respond_to?(:preload_default_shaders) preload_default_shaders if respond_to?(:preload_default_shaders)
@stats_plotter = Stats::StatsPlotter.new(2, 28) # FIXME: Make positioning easy @stats_plotter = Stats::StatsPlotter.new(2, 28) # FIXME: Make positioning easy
@fixed_timestep_data = FixedUpdateProperties.new(1.0 / 125, 8, 1.0 / 60)
@fixed_update = FixedUpdate.new(0, 0.0, 0.0, 1.0)
setup setup
end end
@@ -79,11 +85,44 @@ module CyberarmEngine
Stats.frame.start_timing(:update) Stats.frame.start_timing(:update)
current_state&.update current_state&.update
Stats.frame.start_timing(:fixed_update)
fixed_update
Stats.frame.end_timing(:fixed_update)
Stats.frame.end_timing(:update) Stats.frame.end_timing(:update)
Stats.frame.start_timing(:interframe_sleep) unless needs_redraw? Stats.frame.start_timing(:interframe_sleep) unless needs_redraw?
end end
def fixed_update
@delta_time = @fixed_timestep_data.max_timestep if @delta_time > @fixed_timestep_data.max_timestep
@fixed_update.accumulator += @delta_time
while @fixed_update.accumulator >= @fixed_timestep_data.fixed_timestep
@fixed_update.accumulator -= @fixed_timestep_data.fixed_timestep
@fixed_update.alpha = @fixed_update.accumulator / @fixed_timestep_data.fixed_timestep
@fixed_update.milliseconds += @fixed_timestep_data.fixed_timestep_int_ms
current_state&.fixed_update(@fixed_timestep_data.fixed_timestep)
end
end
def fixed_update_milliseconds
@fixed_update.milliseconds
end
def fixed_update_accumulator
@fixed_update.accumulator
end
def fixed_update_interpolation
@fixed_update.interpolation
end
def fixed_update_alpha
@fixed_update.alpha
end
def needs_cursor? def needs_cursor?
@show_cursor @show_cursor
end end