ruby_rpg 0.0.2 → 0.0.4
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.
- checksums.yaml +4 -4
- data/README.md +4 -2
- data/{lib → bin}/build.bash +4 -3
- data/lib/engine/autoloader.rb +11 -0
- data/lib/engine/component.rb +16 -1
- data/lib/engine/components/audio_source.rb +41 -0
- data/lib/engine/components/orthographic_camera.rb +2 -2
- data/lib/engine/debugging.rb +41 -0
- data/lib/engine/engine.rb +15 -105
- data/lib/engine/font.rb +2 -2
- data/lib/engine/game_object.rb +45 -9
- data/lib/engine/input.rb +44 -1
- data/lib/engine/mesh.rb +2 -2
- data/lib/engine/quaternion.rb +6 -0
- data/lib/engine/texture.rb +3 -2
- data/lib/ruby_rpg.rb +53 -0
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 73ebf7bd3a497f3da5bb8bf0c953da36446ef912edede3605ae811a7d7778c21
|
4
|
+
data.tar.gz: 2c6d68447ef0502ca2d19020659bf09b1821fec4ff741ee5901a142358513701
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc07ac48782722967f54d33c0aa633891f1f585557b6cb9427cf0d4ae711b5869c318631f17fd90ef5e82fbdfcf6946542e8cf0874b438aa2165818f601bb20d
|
7
|
+
data.tar.gz: da7fb040ce08572ff69666fe850a3d2bc6d0dd326b040e1c8772f2c4891cef54550baf18d2c558e29b1e9b5ed983a0b016eea6d5345137faaf878bcbbe28d350
|
data/README.md
CHANGED
@@ -5,10 +5,12 @@ It is designed to be easy to use and easy to extend.
|
|
5
5
|
It is still in the early stages of development, but it is already capable of rendering both 2D and 3D graphics.
|
6
6
|
|
7
7
|
## Installation
|
8
|
-
|
8
|
+
You can find full instructions on th [wiki](https://github.com/rubyrpg/ruby_rpg/wiki/Installation).
|
9
9
|
|
10
10
|
## Usage
|
11
|
-
|
11
|
+
You can find docs and guides on the [wiki](https://github.com/rubyrpg/ruby_rpg/wiki).
|
12
|
+
For a basic example to get you up off the ground take a look at [hello_ruby_rpg](https://github.com/rubyrpg/hello_ruby_rpg).
|
13
|
+
For some more complex examples you can take a look in the samples folder of this repo.
|
12
14
|
|
13
15
|
## Contributing
|
14
16
|
1. Fork it
|
data/{lib → bin}/build.bash
RENAMED
@@ -5,8 +5,9 @@ output_file=$2
|
|
5
5
|
|
6
6
|
export BUILDING=true
|
7
7
|
|
8
|
+
parent_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
|
9
|
+
glfw_path=$parent_path/../glfw-3.4.bin.WIN64
|
10
|
+
|
8
11
|
ocran $input_file \
|
9
|
-
**/*.png **/*.obj **/*.glsl **/*.vertex_data **/*.index_data **/*.json **/*.csv
|
12
|
+
**/*.png **/*.obj **/*.glsl **/*.vertex_data **/*.index_data **/*.json **/*.csv $glfw_path/**/* src/**/*.rb \
|
10
13
|
--output $output_file
|
11
|
-
|
12
|
-
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Engine
|
4
|
+
module AutoLoader
|
5
|
+
def self.load(load_path = nil)
|
6
|
+
base_dir = File.expand_path(load_path || File.dirname($PROGRAM_NAME))
|
7
|
+
Dir[File.join(base_dir, "components", "**/*.rb")].each { |file| require file }
|
8
|
+
Dir[File.join(base_dir, "game_objects", "**/*.rb")].each { |file| require file }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/engine/component.rb
CHANGED
@@ -30,8 +30,12 @@ module Engine
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def destroy!
|
33
|
+
Component.destroyed_components << self unless @destroyed
|
34
|
+
destroy unless @destroyed
|
33
35
|
@destroyed = true
|
34
|
-
|
36
|
+
end
|
37
|
+
|
38
|
+
def _erase!
|
35
39
|
game_object.components.delete(self)
|
36
40
|
class_name = self.class.name.split('::').last
|
37
41
|
self.class.instance_variable_get(:@methods).each do |method|
|
@@ -42,7 +46,18 @@ module Engine
|
|
42
46
|
end
|
43
47
|
end
|
44
48
|
|
49
|
+
def self.erase_destroyed_components
|
50
|
+
destroyed_components.each do |object|
|
51
|
+
object._erase!
|
52
|
+
end
|
53
|
+
@destroyed_components = []
|
54
|
+
end
|
55
|
+
|
45
56
|
def destroy
|
46
57
|
end
|
58
|
+
|
59
|
+
def self.destroyed_components
|
60
|
+
@destroyed_components ||= []
|
61
|
+
end
|
47
62
|
end
|
48
63
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Engine::Components
|
4
|
+
class AudioSource < Engine::Component
|
5
|
+
def initialize(clip, radius: 1000)
|
6
|
+
@clip = clip
|
7
|
+
@radius = radius
|
8
|
+
@source = NativeAudio::AudioSource.new(clip)
|
9
|
+
end
|
10
|
+
|
11
|
+
def play
|
12
|
+
@source.play
|
13
|
+
end
|
14
|
+
|
15
|
+
def stop
|
16
|
+
@source.stop
|
17
|
+
end
|
18
|
+
|
19
|
+
def pause
|
20
|
+
@source.pause
|
21
|
+
end
|
22
|
+
|
23
|
+
def resume
|
24
|
+
@source.resume
|
25
|
+
end
|
26
|
+
|
27
|
+
def volume=(volume)
|
28
|
+
@source.set_volume(volume)
|
29
|
+
end
|
30
|
+
|
31
|
+
def update(delta_time)
|
32
|
+
camera = Engine::Camera.instance
|
33
|
+
local_pos = camera.game_object.world_to_local_coordinate(game_object.pos)
|
34
|
+
angle = Math.atan2(local_pos[0], -local_pos[2]) * 180 / Math::PI
|
35
|
+
angle = (angle + 360) % 360
|
36
|
+
distance = (local_pos.magnitude * 255 / @radius).clamp(0, 255)
|
37
|
+
|
38
|
+
@source.set_pos(angle, distance)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -33,8 +33,8 @@ module Engine::Components
|
|
33
33
|
@right = nil if game_object.rotation != @rotation
|
34
34
|
@up = nil if game_object.rotation != @rotation
|
35
35
|
@front = nil if game_object.rotation != @rotation
|
36
|
-
@matrix = nil if game_object.rotation.
|
37
|
-
@rotation = game_object.rotation.
|
36
|
+
@matrix = nil if game_object.rotation.dup != @rotation
|
37
|
+
@rotation = game_object.rotation.dup
|
38
38
|
end
|
39
39
|
|
40
40
|
private
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Engine
|
4
|
+
module Debugging
|
5
|
+
|
6
|
+
# Hit a breakpoint within the context of where the breakpoint is defined, assuming a block is passed
|
7
|
+
# with a `binding.pry` (or an alternative debugger), otherwise hit a breakpoint within this method.
|
8
|
+
def self.breakpoint(&block)
|
9
|
+
orig_fullscreen = Window.full_screen?
|
10
|
+
if orig_fullscreen
|
11
|
+
Window.set_to_windowed
|
12
|
+
GLFW.PollEvents # Required to trigger the switch from fullscreen to windowed within this breakpoint
|
13
|
+
end
|
14
|
+
|
15
|
+
orig_cursor_mode = Cursor.get_input_mode
|
16
|
+
Cursor.enable
|
17
|
+
|
18
|
+
block_given? ? yield : binding.pry
|
19
|
+
Cursor.restore_input_mode(orig_cursor_mode)
|
20
|
+
Window.set_to_full_screen if orig_fullscreen
|
21
|
+
Window.focus_window
|
22
|
+
|
23
|
+
# Reset the time, otherwise delta_time will be off for the next frame, and teleporting occurs
|
24
|
+
@time = Time.now
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.debug_opengl_call
|
28
|
+
errors = []
|
29
|
+
until GL.GetError == 0; end
|
30
|
+
yield
|
31
|
+
until (error = GL.GetError) == 0
|
32
|
+
errors += error.to_s(16)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.print_opengl_version
|
37
|
+
puts "OpenGL Version: #{GL.GetString(GL::VERSION)}"
|
38
|
+
puts "GLSL Version: #{GL.GetString(GL::SHADING_LANGUAGE_VERSION)}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/engine/engine.rb
CHANGED
@@ -1,55 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
require 'os'
|
5
|
-
|
6
|
-
require_relative 'rendering/render_pipeline'
|
7
|
-
require_relative 'rendering/instance_renderer'
|
8
|
-
require_relative 'screenshoter'
|
9
|
-
require_relative 'input'
|
10
|
-
require_relative "quaternion"
|
11
|
-
require_relative 'game_object'
|
12
|
-
require_relative 'texture'
|
13
|
-
require_relative 'material'
|
14
|
-
require_relative 'mesh'
|
15
|
-
require_relative "font"
|
16
|
-
require_relative 'path'
|
17
|
-
require_relative 'polygon_mesh'
|
18
|
-
require_relative 'importers/obj_file'
|
19
|
-
require_relative 'tangent_calculator'
|
20
|
-
require_relative 'shader'
|
21
|
-
require_relative 'component'
|
22
|
-
require_relative "camera"
|
23
|
-
require_relative "window"
|
24
|
-
require_relative "video_mode"
|
25
|
-
require_relative "cursor"
|
26
|
-
|
27
|
-
require_relative "components/orthographic_camera"
|
28
|
-
require_relative "components/perspective_camera"
|
29
|
-
require_relative "components/sprite_renderer"
|
30
|
-
require_relative "components/ui_sprite_renderer"
|
31
|
-
require_relative "components/mesh_renderer"
|
32
|
-
require_relative "components/font_renderer"
|
33
|
-
require_relative "components/ui_font_renderer"
|
34
|
-
require_relative "components/point_light"
|
35
|
-
require_relative "components/direction_light"
|
36
|
-
|
37
|
-
require_relative "physics/physics_resolver"
|
38
|
-
require_relative 'physics/collision'
|
39
|
-
require_relative "physics/components/sphere_collider"
|
40
|
-
require_relative "physics/components/cube_collider"
|
41
|
-
require_relative "physics/components/rigidbody"
|
42
|
-
|
43
|
-
if OS.windows?
|
44
|
-
GLFW.load_lib(File.expand_path(File.join(__dir__, "..", "..", "glfw-3.4.bin.WIN64", "lib-static-ucrt", "glfw3.dll")))
|
45
|
-
elsif OS.mac?
|
46
|
-
GLFW.load_lib(File.expand_path(File.join(__dir__, "..", "..", "glfw-3.3.9.bin.MACOS", "lib-arm64", "libglfw.3.dylib")))
|
47
|
-
end
|
48
|
-
GLFW.Init
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
GAME_DIR = File.expand_path(File.dirname($PROGRAM_NAME))
|
49
4
|
|
50
5
|
module Engine
|
51
|
-
def self.start(
|
52
|
-
load
|
6
|
+
def self.start(&first_frame_block)
|
7
|
+
Engine::AutoLoader.load
|
53
8
|
return if ENV["BUILDING"] == "true"
|
54
9
|
|
55
10
|
open_window
|
@@ -61,20 +16,14 @@ module Engine
|
|
61
16
|
@engine_started
|
62
17
|
end
|
63
18
|
|
64
|
-
def self.load(base_dir)
|
65
|
-
base_dir = File.expand_path(base_dir)
|
66
|
-
Dir[File.join(base_dir, "components", "**/*.rb")].each { |file| require file }
|
67
|
-
Dir[File.join(base_dir, "game_objects", "**/*.rb")].each { |file| require file }
|
68
|
-
end
|
69
|
-
|
70
19
|
def self.open_window
|
71
20
|
@old_time = Time.now
|
72
21
|
@time = Time.now
|
73
|
-
@key_callback = create_key_callbacks # This must be an instance variable to prevent garbage collection
|
74
22
|
|
75
23
|
Window.create_window
|
76
24
|
GLFW.MakeContextCurrent(Window.window)
|
77
|
-
|
25
|
+
|
26
|
+
Input.init
|
78
27
|
GL.load_lib
|
79
28
|
|
80
29
|
set_opengl_blend_mode
|
@@ -85,8 +34,6 @@ module Engine
|
|
85
34
|
GL.CullFace(GL::BACK)
|
86
35
|
|
87
36
|
GLFW.SwapInterval(0)
|
88
|
-
|
89
|
-
Cursor.hide
|
90
37
|
end
|
91
38
|
|
92
39
|
def self.main_game_loop(&first_frame_block)
|
@@ -144,13 +91,10 @@ module Engine
|
|
144
91
|
@fps
|
145
92
|
end
|
146
93
|
|
147
|
-
def self.terminate
|
148
|
-
GLFW.DestroyWindow(Window.window)
|
149
|
-
GLFW.Terminate
|
150
|
-
end
|
151
|
-
|
152
94
|
def self.close
|
153
95
|
GameObject.destroy_all
|
96
|
+
Component.erase_destroyed_components
|
97
|
+
GameObject.erase_destroyed_objects
|
154
98
|
GLFW.SetWindowShouldClose(Window.window, 1)
|
155
99
|
end
|
156
100
|
|
@@ -158,31 +102,17 @@ module Engine
|
|
158
102
|
@game_stopped = true
|
159
103
|
@swap_buffers_promise.wait! if @swap_buffers_promise && !@swap_buffers_promise.complete?
|
160
104
|
GameObject.destroy_all
|
105
|
+
Component.erase_destroyed_components
|
106
|
+
GameObject.erase_destroyed_objects
|
161
107
|
end
|
162
108
|
|
163
|
-
|
164
|
-
# with a `binding.pry` (or an alternative debugger), otherwise hit a breakpoint within this method.
|
165
|
-
def self.breakpoint(&block)
|
166
|
-
orig_fullscreen = Window.full_screen?
|
167
|
-
if orig_fullscreen
|
168
|
-
Window.set_to_windowed
|
169
|
-
GLFW.PollEvents # Required to trigger the switch from fullscreen to windowed within this breakpoint
|
170
|
-
end
|
171
|
-
|
172
|
-
orig_cursor_mode = Cursor.get_input_mode
|
173
|
-
Cursor.enable
|
174
|
-
|
175
|
-
block_given? ? yield : binding.pry
|
176
|
-
Cursor.restore_input_mode(orig_cursor_mode)
|
177
|
-
Window.set_to_full_screen if orig_fullscreen
|
178
|
-
Window.focus_window
|
109
|
+
private
|
179
110
|
|
180
|
-
|
181
|
-
|
111
|
+
def self.terminate
|
112
|
+
GLFW.DestroyWindow(Window.window)
|
113
|
+
GLFW.Terminate
|
182
114
|
end
|
183
115
|
|
184
|
-
private
|
185
|
-
|
186
116
|
def self.print_fps(delta_time)
|
187
117
|
@time_since_last_fps_print = (@time_since_last_fps_print || 0) + delta_time
|
188
118
|
@frame = (@frame || 0) + 1
|
@@ -198,24 +128,4 @@ module Engine
|
|
198
128
|
GL.Enable(GL::BLEND)
|
199
129
|
GL.BlendFunc(GL::SRC_ALPHA, GL::ONE_MINUS_SRC_ALPHA)
|
200
130
|
end
|
201
|
-
|
202
|
-
def self.create_key_callbacks
|
203
|
-
GLFW::create_callback(:GLFWkeyfun) do |window, key, scancode, action, mods|
|
204
|
-
Input.key_callback(key, action)
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
def self.debug_opengl_call
|
209
|
-
errors = []
|
210
|
-
until GL.GetError == 0; end
|
211
|
-
yield
|
212
|
-
until (error = GL.GetError) == 0
|
213
|
-
errors += error.to_s(16)
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
def self.print_opengl_version
|
218
|
-
puts "OpenGL Version: #{GL.GetString(GL::VERSION)}"
|
219
|
-
puts "GLSL Version: #{GL.GetString(GL::SHADING_LANGUAGE_VERSION)}"
|
220
|
-
end
|
221
131
|
end
|
data/lib/engine/font.rb
CHANGED
@@ -15,7 +15,7 @@ module Engine
|
|
15
15
|
def texture
|
16
16
|
@texture ||=
|
17
17
|
begin
|
18
|
-
path = File.
|
18
|
+
path = File.join("_imported", @font_file_path.gsub(".ttf", ".png"))
|
19
19
|
Engine::Texture.for(path)
|
20
20
|
end
|
21
21
|
end
|
@@ -35,7 +35,7 @@ module Engine
|
|
35
35
|
scale_factor = 1 / (1024.0 * 2)
|
36
36
|
horizontal_offset = 0.0
|
37
37
|
vertical_offset = 0.0
|
38
|
-
font_path = File.expand_path(File.join(
|
38
|
+
font_path = File.expand_path(File.join(GAME_DIR, "_imported", @font_file_path.gsub(".ttf", ".json")))
|
39
39
|
font_metrics = JSON.parse File.read(font_path)
|
40
40
|
string.chars.each do |char|
|
41
41
|
if char == "\n"
|
data/lib/engine/game_object.rb
CHANGED
@@ -8,15 +8,17 @@ module Engine
|
|
8
8
|
@methods.add(name)
|
9
9
|
end
|
10
10
|
|
11
|
-
attr_accessor :name, :pos, :
|
11
|
+
attr_accessor :name, :pos, :scale, :components, :renderers, :ui_renderers, :created_at, :parent
|
12
12
|
|
13
13
|
def initialize(name = "Game Object", pos: Vector[0, 0, 0], rotation: 0, scale: Vector[1, 1, 1], components: [], parent: nil)
|
14
14
|
GameObject.object_spawned(self)
|
15
15
|
@pos = Vector[pos[0], pos[1], pos[2] || 0]
|
16
16
|
if rotation.is_a?(Numeric)
|
17
|
-
|
17
|
+
self.rotation = Quaternion.from_euler(Vector[0, 0, rotation])
|
18
|
+
elsif rotation.is_a?(Quaternion)
|
19
|
+
self.rotation = rotation
|
18
20
|
else
|
19
|
-
|
21
|
+
self.rotation = Quaternion.from_euler(rotation)
|
20
22
|
end
|
21
23
|
@scale = scale
|
22
24
|
@name = name
|
@@ -50,6 +52,20 @@ module Engine
|
|
50
52
|
parent.children << self if parent
|
51
53
|
end
|
52
54
|
|
55
|
+
def rotation
|
56
|
+
@rotation_quaternion
|
57
|
+
end
|
58
|
+
|
59
|
+
def rotation=(value)
|
60
|
+
raise "Rotation must be a Quaternion" unless value.is_a?(Quaternion)
|
61
|
+
|
62
|
+
@rotation_quaternion = value
|
63
|
+
end
|
64
|
+
|
65
|
+
def euler_angles
|
66
|
+
rotation.to_euler
|
67
|
+
end
|
68
|
+
|
53
69
|
def x
|
54
70
|
@pos[0]
|
55
71
|
end
|
@@ -93,16 +109,16 @@ module Engine
|
|
93
109
|
def rotate_around(axis, angle)
|
94
110
|
rotation_quaternion = Quaternion.from_angle_axis(angle, axis)
|
95
111
|
|
96
|
-
|
112
|
+
self.rotation = rotation_quaternion * rotation
|
97
113
|
end
|
98
114
|
|
99
115
|
def model_matrix
|
100
|
-
cache_key = [@pos.dup,
|
116
|
+
cache_key = [@pos.dup, rotation.dup, @scale.dup, @parent&.model_matrix&.to_a]
|
101
117
|
@model_matrix = nil if @model_matrix_cache_key != cache_key
|
102
118
|
@model_matrix_cache_key = cache_key
|
103
119
|
@model_matrix ||=
|
104
120
|
begin
|
105
|
-
rot =
|
121
|
+
rot = euler_angles * Math::PI / 180
|
106
122
|
|
107
123
|
cos_x = Math.cos(rot[0])
|
108
124
|
cos_y = Math.cos(rot[1])
|
@@ -132,17 +148,30 @@ module Engine
|
|
132
148
|
|
133
149
|
def destroy!
|
134
150
|
return unless GameObject.objects.include?(self)
|
135
|
-
|
151
|
+
children.each(&:destroy!)
|
136
152
|
components.each(&:destroy!)
|
137
153
|
ui_renderers.each(&:destroy!)
|
138
154
|
renderers.each(&:destroy!)
|
155
|
+
|
156
|
+
GameObject.destroyed_objects << self unless @destroyed
|
157
|
+
@destroyed = true
|
158
|
+
end
|
159
|
+
|
160
|
+
def _erase!
|
139
161
|
GameObject.objects.delete(self)
|
140
162
|
parent.children.delete(self) if parent
|
141
|
-
|
163
|
+
name = @name
|
142
164
|
self.class.instance_variable_get(:@methods).each do |method|
|
143
165
|
singleton_class.send(:undef_method, method)
|
144
|
-
singleton_class.send(:define_method, method) { raise "This object has been destroyed
|
166
|
+
singleton_class.send(:define_method, method) { raise "This object has been destroyed: #{name}" }
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def self.erase_destroyed_objects
|
171
|
+
destroyed_objects.each do |object|
|
172
|
+
object._erase!
|
145
173
|
end
|
174
|
+
@destroyed_objects = []
|
146
175
|
end
|
147
176
|
|
148
177
|
def up
|
@@ -173,6 +202,9 @@ module Engine
|
|
173
202
|
GameObject.objects.each do |object|
|
174
203
|
object.components.each { |component| component.update(delta_time) }
|
175
204
|
end
|
205
|
+
|
206
|
+
Component.erase_destroyed_components
|
207
|
+
GameObject.erase_destroyed_objects
|
176
208
|
end
|
177
209
|
|
178
210
|
def self.mesh_renderers
|
@@ -194,5 +226,9 @@ module Engine
|
|
194
226
|
def self.objects
|
195
227
|
@objects ||= []
|
196
228
|
end
|
229
|
+
|
230
|
+
def self.destroyed_objects
|
231
|
+
@destroyed_objects ||= []
|
232
|
+
end
|
197
233
|
end
|
198
234
|
end
|
data/lib/engine/input.rb
CHANGED
@@ -2,6 +2,23 @@
|
|
2
2
|
|
3
3
|
module Engine
|
4
4
|
class Input
|
5
|
+
def self.init
|
6
|
+
@key_callback = GLFW::create_callback(:GLFWkeyfun) do |window, key, scancode, action, mods|
|
7
|
+
Input.key_callback(key, action)
|
8
|
+
end
|
9
|
+
GLFW.SetKeyCallback(Window.window, @key_callback)
|
10
|
+
|
11
|
+
@cursor_pos_callback = GLFW::create_callback(:GLFWcursorposfun) do |window, x, y|
|
12
|
+
Input.mouse_callback(x, y)
|
13
|
+
end
|
14
|
+
GLFW.SetCursorPosCallback(Window.window, @cursor_pos_callback)
|
15
|
+
|
16
|
+
@mouse_button_callback = GLFW::create_callback(:GLFWmousebuttonfun) do |window, button, action, mods|
|
17
|
+
Input.mouse_button_callback(button, action)
|
18
|
+
end
|
19
|
+
GLFW.SetMouseButtonCallback(Window.window, @mouse_button_callback)
|
20
|
+
end
|
21
|
+
|
5
22
|
def self.key?(key)
|
6
23
|
keys[key] == :down || keys[key] == :held
|
7
24
|
end
|
@@ -14,6 +31,17 @@ module Engine
|
|
14
31
|
keys[key] == :up
|
15
32
|
end
|
16
33
|
|
34
|
+
def self.mouse_pos
|
35
|
+
@mouse_pos
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.mouse_delta
|
39
|
+
return Vector[0, 0] if @old_mouse_pos.nil?
|
40
|
+
return Vector[0, 0] unless @mouse_pos_updated
|
41
|
+
|
42
|
+
@mouse_pos - @old_mouse_pos
|
43
|
+
end
|
44
|
+
|
17
45
|
def self._on_key_down(key)
|
18
46
|
keys[key] = :down
|
19
47
|
if key == GLFW::KEY_ESCAPE
|
@@ -21,7 +49,7 @@ module Engine
|
|
21
49
|
end
|
22
50
|
|
23
51
|
if key == GLFW::KEY_BACKSPACE
|
24
|
-
Engine.breakpoint { binding.pry }
|
52
|
+
Engine::Debugging.breakpoint { binding.pry }
|
25
53
|
# Engine.breakpoint { debugger }
|
26
54
|
end
|
27
55
|
|
@@ -42,7 +70,22 @@ module Engine
|
|
42
70
|
end
|
43
71
|
end
|
44
72
|
|
73
|
+
def self.mouse_callback(x, y)
|
74
|
+
@mouse_pos_updated = true
|
75
|
+
@old_mouse_pos = @mouse_pos
|
76
|
+
@mouse_pos = Vector[x, y]
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.mouse_button_callback(button, action)
|
80
|
+
if action == GLFW::PRESS
|
81
|
+
keys[button] = :down
|
82
|
+
elsif action == GLFW::RELEASE
|
83
|
+
keys[button] = :up
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
45
87
|
def self.update_key_states
|
88
|
+
@mouse_pos_updated = false
|
46
89
|
keys.each do |key, state|
|
47
90
|
if state == :down
|
48
91
|
keys[key] = :held
|
data/lib/engine/mesh.rb
CHANGED
@@ -21,7 +21,7 @@ module Engine
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def self.open_vertex(mesh_file)
|
24
|
-
vertex_cache[File.join(
|
24
|
+
vertex_cache[File.join(GAME_DIR, "_imported", mesh_file + ".vertex_data")]
|
25
25
|
end
|
26
26
|
|
27
27
|
def self.vertex_cache
|
@@ -31,7 +31,7 @@ module Engine
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def self.open_index(mesh_file)
|
34
|
-
index_cache[File.join(
|
34
|
+
index_cache[File.join(GAME_DIR, "_imported", mesh_file + ".index_data")]
|
35
35
|
end
|
36
36
|
|
37
37
|
def self.index_cache
|
data/lib/engine/quaternion.rb
CHANGED
@@ -16,6 +16,12 @@ module Engine
|
|
16
16
|
"Quaternion(w: #{@w}, x: #{@x}, y: #{@y}, z: #{@z})"
|
17
17
|
end
|
18
18
|
|
19
|
+
def ==(other)
|
20
|
+
return false unless other.is_a?(Quaternion)
|
21
|
+
|
22
|
+
@w == other.w && @x == other.x && @y == other.y && @z == other.z
|
23
|
+
end
|
24
|
+
|
19
25
|
def *(other)
|
20
26
|
Quaternion.new(
|
21
27
|
@w * other.w - @x * other.x - @y * other.y - @z * other.z,
|
data/lib/engine/texture.rb
CHANGED
@@ -12,8 +12,9 @@ module Engine
|
|
12
12
|
load_texture
|
13
13
|
end
|
14
14
|
|
15
|
-
def self.for(
|
16
|
-
|
15
|
+
def self.for(path, flip: false)
|
16
|
+
full_path = File.expand_path(File.join(GAME_DIR, path))
|
17
|
+
texture_cache[[full_path, flip]]
|
17
18
|
end
|
18
19
|
|
19
20
|
def self.texture_cache
|
data/lib/ruby_rpg.rb
CHANGED
@@ -1,3 +1,56 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'opengl'
|
4
|
+
require 'glfw'
|
5
|
+
require 'concurrent'
|
6
|
+
require 'os'
|
7
|
+
require 'native_audio'
|
8
|
+
|
9
|
+
require_relative 'engine/autoloader'
|
10
|
+
require_relative "engine/debugging"
|
11
|
+
require_relative 'engine/rendering/render_pipeline'
|
12
|
+
require_relative 'engine/rendering/instance_renderer'
|
13
|
+
require_relative 'engine/screenshoter'
|
14
|
+
require_relative 'engine/input'
|
15
|
+
require_relative "engine/quaternion"
|
16
|
+
require_relative 'engine/game_object'
|
17
|
+
require_relative 'engine/texture'
|
18
|
+
require_relative 'engine/material'
|
19
|
+
require_relative 'engine/mesh'
|
20
|
+
require_relative "engine/font"
|
21
|
+
require_relative 'engine/path'
|
22
|
+
require_relative 'engine/polygon_mesh'
|
23
|
+
require_relative 'engine/importers/obj_file'
|
24
|
+
require_relative 'engine/tangent_calculator'
|
25
|
+
require_relative 'engine/shader'
|
26
|
+
require_relative 'engine/component'
|
27
|
+
require_relative "engine/camera"
|
28
|
+
require_relative "engine/window"
|
29
|
+
require_relative "engine/video_mode"
|
30
|
+
require_relative "engine/cursor"
|
31
|
+
|
32
|
+
require_relative "engine/components/orthographic_camera"
|
33
|
+
require_relative "engine/components/perspective_camera"
|
34
|
+
require_relative "engine/components/sprite_renderer"
|
35
|
+
require_relative "engine/components/ui_sprite_renderer"
|
36
|
+
require_relative "engine/components/mesh_renderer"
|
37
|
+
require_relative "engine/components/font_renderer"
|
38
|
+
require_relative "engine/components/ui_font_renderer"
|
39
|
+
require_relative "engine/components/point_light"
|
40
|
+
require_relative "engine/components/direction_light"
|
41
|
+
require_relative "engine/components/audio_source"
|
42
|
+
|
43
|
+
require_relative "engine/physics/physics_resolver"
|
44
|
+
require_relative 'engine/physics/collision'
|
45
|
+
require_relative "engine/physics/components/sphere_collider"
|
46
|
+
require_relative "engine/physics/components/cube_collider"
|
47
|
+
require_relative "engine/physics/components/rigidbody"
|
48
|
+
|
49
|
+
if OS.windows?
|
50
|
+
GLFW.load_lib(File.expand_path(File.join(__dir__, "..", "glfw-3.4.bin.WIN64", "lib-static-ucrt", "glfw3.dll")))
|
51
|
+
elsif OS.mac?
|
52
|
+
GLFW.load_lib(File.expand_path(File.join(__dir__, "..", "glfw-3.3.9.bin.MACOS", "lib-arm64", "libglfw.3.dylib")))
|
53
|
+
end
|
54
|
+
GLFW.Init
|
55
|
+
|
3
56
|
require_relative 'engine/engine'
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_rpg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Max Hatfull
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-11-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: native_audio
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: opengl-bindings2
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,6 +122,7 @@ extensions: []
|
|
108
122
|
extra_rdoc_files: []
|
109
123
|
files:
|
110
124
|
- README.md
|
125
|
+
- bin/build.bash
|
111
126
|
- bin/import
|
112
127
|
- glfw-3.3.9.bin.MACOS/LICENSE.md
|
113
128
|
- glfw-3.3.9.bin.MACOS/README.md
|
@@ -537,9 +552,10 @@ files:
|
|
537
552
|
- glfw-3.4.bin.WIN64/lib-vc2022/glfw3.lib
|
538
553
|
- glfw-3.4.bin.WIN64/lib-vc2022/glfw3_mt.lib
|
539
554
|
- glfw-3.4.bin.WIN64/lib-vc2022/glfw3dll.lib
|
540
|
-
- lib/
|
555
|
+
- lib/engine/autoloader.rb
|
541
556
|
- lib/engine/camera.rb
|
542
557
|
- lib/engine/component.rb
|
558
|
+
- lib/engine/components/audio_source.rb
|
543
559
|
- lib/engine/components/direction_light.rb
|
544
560
|
- lib/engine/components/font_renderer.rb
|
545
561
|
- lib/engine/components/mesh_renderer.rb
|
@@ -550,6 +566,7 @@ files:
|
|
550
566
|
- lib/engine/components/ui_font_renderer.rb
|
551
567
|
- lib/engine/components/ui_sprite_renderer.rb
|
552
568
|
- lib/engine/cursor.rb
|
569
|
+
- lib/engine/debugging.rb
|
553
570
|
- lib/engine/engine.rb
|
554
571
|
- lib/engine/font.rb
|
555
572
|
- lib/engine/game_object.rb
|