hemi 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +79 -0
- data/.gitignore +3 -1
- data/.rubocop.yml +11 -0
- data/.yardopts +1 -0
- data/DEV.md +26 -0
- data/Gemfile.lock +11 -1
- data/README.md +87 -34
- data/hemi.gemspec +2 -0
- data/lib/hemi/engine.rb +67 -5
- data/lib/hemi/event/_manifest.rb +4 -0
- data/lib/hemi/event/event_loop.rb +2 -24
- data/lib/hemi/event/key_handler.rb +30 -0
- data/lib/hemi/event/loop_machine.rb +51 -3
- data/lib/hemi/event/pattern/key.rb +38 -0
- data/lib/hemi/helpers/injections.rb +11 -0
- data/lib/hemi/helpers/simple.rb +3 -2
- data/lib/hemi/loader.rb +3 -3
- data/lib/hemi/render/texture.rb +2 -2
- data/lib/hemi/version.rb +1 -1
- metadata +36 -2
- data/lib/hemi/helpers/self_manager.rb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f36ce1ac46670d07a633de63c38a9f5b0f5faeb44e35c207647634cc9c34319
|
4
|
+
data.tar.gz: 71a1d9d0f6833d6ec66cd952a0ffc6d538508244d30165bdbb54c8dfd461eb54
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76cb55701b6c8c2a6464baebeadd91b0fe134bc42ec7d6beb543c4e50b7ee8db5c4951f518350a650c661e26bd3d97e453b5671cb4e37d8a3f92a1ff21dac8ae
|
7
|
+
data.tar.gz: c11c2a318a70225d2cf5773c10245e842f7fdc9fc7c509006d225e004d7be9a43b58b2a2faf2dd0ad1ee424e8aa4e22844266fff898e98726b27c1f5ed1d8009
|
@@ -0,0 +1,79 @@
|
|
1
|
+
version: 2.1
|
2
|
+
orbs:
|
3
|
+
ruby: circleci/ruby@0.1.2
|
4
|
+
|
5
|
+
defaults: &defaults
|
6
|
+
working_directory: ~/hemi
|
7
|
+
|
8
|
+
ruby_machine: &ruby_machine
|
9
|
+
<<: *defaults
|
10
|
+
docker:
|
11
|
+
- image: ellmo/ruby-hemi:0.0.3
|
12
|
+
environment:
|
13
|
+
RAILS_ENV: test
|
14
|
+
BUNDLE_PATH: vendor/bundle
|
15
|
+
BUNDLER_VERSION: 2.1.4
|
16
|
+
executor: ruby/default
|
17
|
+
|
18
|
+
jobs:
|
19
|
+
build:
|
20
|
+
<<: *ruby_machine
|
21
|
+
steps:
|
22
|
+
- checkout
|
23
|
+
- attach_workspace:
|
24
|
+
at: ~/hemi
|
25
|
+
- run:
|
26
|
+
name: Bundle install
|
27
|
+
command: |
|
28
|
+
gem install bundler -v=${BUNDLER_VERSION}
|
29
|
+
bundle install --path=vendor/bundle
|
30
|
+
- run:
|
31
|
+
name: Download cc-test-reporter
|
32
|
+
command: |
|
33
|
+
mkdir -p tmp/
|
34
|
+
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./tmp/cc-test-reporter
|
35
|
+
chmod +x ./tmp/cc-test-reporter
|
36
|
+
- persist_to_workspace:
|
37
|
+
root: ~/hemi
|
38
|
+
paths:
|
39
|
+
- vendor/bundle
|
40
|
+
- tmp/cc-test-reporter
|
41
|
+
|
42
|
+
test:
|
43
|
+
<<: *ruby_machine
|
44
|
+
steps:
|
45
|
+
- checkout
|
46
|
+
- attach_workspace:
|
47
|
+
at: ~/hemi
|
48
|
+
- run:
|
49
|
+
name: RSpec
|
50
|
+
command: |
|
51
|
+
gem install bundler -v=${BUNDLER_VERSION}
|
52
|
+
bundle exec rspec
|
53
|
+
./tmp/cc-test-reporter format-coverage -t simplecov -o tmp/codeclimate.backend.json coverage/backend/.resultset.json
|
54
|
+
- persist_to_workspace:
|
55
|
+
root: ~/hemi
|
56
|
+
paths:
|
57
|
+
- tmp/codeclimate.backend.json
|
58
|
+
upload_coverage:
|
59
|
+
<<: *ruby_machine
|
60
|
+
steps:
|
61
|
+
- attach_workspace:
|
62
|
+
at: ~/hemi
|
63
|
+
- run:
|
64
|
+
name: Upload coverage results to Code Climate
|
65
|
+
command: |
|
66
|
+
./tmp/cc-test-reporter sum-coverage tmp/codeclimate.*.json -p 1 -o tmp/codeclimate.total.json
|
67
|
+
./tmp/cc-test-reporter upload-coverage -i tmp/codeclimate.total.json
|
68
|
+
|
69
|
+
workflows:
|
70
|
+
version: 2
|
71
|
+
build_and_test:
|
72
|
+
jobs:
|
73
|
+
- build
|
74
|
+
- test:
|
75
|
+
requires:
|
76
|
+
- build
|
77
|
+
- upload_coverage:
|
78
|
+
requires:
|
79
|
+
- test
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -41,12 +41,23 @@ Style/ClassAndModuleChildren:
|
|
41
41
|
Style/Documentation:
|
42
42
|
Enabled: false
|
43
43
|
|
44
|
+
# NAMING
|
45
|
+
Naming/FileName:
|
46
|
+
Exclude:
|
47
|
+
- 'demo/**/*'
|
48
|
+
|
44
49
|
# RSPEC
|
45
50
|
RSpec/ContextWording:
|
46
51
|
Enabled: false
|
52
|
+
RSpec/MessageSpies:
|
53
|
+
Enabled: false
|
54
|
+
RSpec/MultipleExpectations:
|
55
|
+
Max: 5
|
47
56
|
RSpec/NamedSubject:
|
48
57
|
Enabled: false
|
49
58
|
RSpec/NestedGroups:
|
50
59
|
Max: 5
|
60
|
+
RSpec/SubjectStub:
|
61
|
+
Enabled: false
|
51
62
|
RSpec/VerifiedDoubles:
|
52
63
|
Enabled: false
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup=markdown
|
data/DEV.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
## Development
|
2
|
+
(`sdl2` libs are - obviously - still required)
|
3
|
+
|
4
|
+
#### 1. Install Ruby and gems
|
5
|
+
|
6
|
+
Install specific ruby version using Rbenv (`rbenv install`) or RVM (yuck)
|
7
|
+
|
8
|
+
Make sure you have Bundler gem installed for this revsion (`gem install bundler -v=1.17.3`)
|
9
|
+
|
10
|
+
And `bundle install` away.
|
11
|
+
|
12
|
+
#### 2. Update code (and bump the version)
|
13
|
+
|
14
|
+
Dont forget to `git tag` and push with `--tags option`
|
15
|
+
|
16
|
+
#### 3. Build and push to Rubygems
|
17
|
+
|
18
|
+
`gem build hemi.gemspec`
|
19
|
+
|
20
|
+
`gem push hemi-{VERSION}.gem`
|
21
|
+
|
22
|
+
And if you need to test gem installation locally:
|
23
|
+
|
24
|
+
`gem push hemi-{VERSION}.gem`
|
25
|
+
|
26
|
+
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
hemi (0.0.
|
4
|
+
hemi (0.0.3)
|
5
5
|
pry (~> 0.12)
|
6
6
|
ruby-sdl2 (= 0.3.5)
|
7
7
|
|
@@ -11,6 +11,7 @@ GEM
|
|
11
11
|
ast (2.4.0)
|
12
12
|
coderay (1.1.3)
|
13
13
|
diff-lcs (1.3)
|
14
|
+
docile (1.3.4)
|
14
15
|
jaro_winkler (1.5.4)
|
15
16
|
method_source (1.0.0)
|
16
17
|
parallel (1.19.1)
|
@@ -46,7 +47,14 @@ GEM
|
|
46
47
|
rubocop (>= 0.68.1)
|
47
48
|
ruby-progressbar (1.10.1)
|
48
49
|
ruby-sdl2 (0.3.5)
|
50
|
+
simplecov (0.20.0)
|
51
|
+
docile (~> 1.1)
|
52
|
+
simplecov-html (~> 0.11)
|
53
|
+
simplecov_json_formatter (~> 0.1)
|
54
|
+
simplecov-html (0.12.3)
|
55
|
+
simplecov_json_formatter (0.1.2)
|
49
56
|
unicode-display_width (1.6.0)
|
57
|
+
yard (0.9.26)
|
50
58
|
|
51
59
|
PLATFORMS
|
52
60
|
ruby
|
@@ -57,6 +65,8 @@ DEPENDENCIES
|
|
57
65
|
rubocop (~> 0.77)
|
58
66
|
rubocop-performance (~> 1.5)
|
59
67
|
rubocop-rspec (~> 1.37)
|
68
|
+
simplecov (~> 0.20)
|
69
|
+
yard (~> 0.9)
|
60
70
|
|
61
71
|
BUNDLED WITH
|
62
72
|
2.1.4
|
data/README.md
CHANGED
@@ -7,37 +7,90 @@ Made for self-educational purposes.
|
|
7
7
|
|
8
8
|
## Usage
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
`
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
10
|
+
### 0. Required libraries
|
11
|
+
Install `sdl2`, `sdl2_image`, `sdl2_mixer` and `sdl2_ttf` libraries.
|
12
|
+
For MacOS you can simply `brew install` all of them.
|
13
|
+
|
14
|
+
### 1. Using the gem
|
15
|
+
|
16
|
+
#### 1.0 installation
|
17
|
+
Install the gem, either straight-up with `gem install hemi` or using Bundler:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
# Gemfile
|
21
|
+
source "https://rubygems.org"
|
22
|
+
|
23
|
+
gem "hemi"
|
24
|
+
```
|
25
|
+
|
26
|
+
#### 1.1 prepend your starting class
|
27
|
+
```ruby
|
28
|
+
require "hemi"
|
29
|
+
|
30
|
+
class Game
|
31
|
+
prepend Hemi::Engine
|
32
|
+
end
|
33
|
+
|
34
|
+
```
|
35
|
+
|
36
|
+
#### 1.2 prepare a logic proc
|
37
|
+
This `proc` will contain logic to be performed during each rendered frame.
|
38
|
+
```ruby
|
39
|
+
Font = Hemi::Render::Font
|
40
|
+
Sprite = Hemi::Render::Sprite
|
41
|
+
|
42
|
+
def text_logic
|
43
|
+
proc {
|
44
|
+
Font[:jost_32].render("quick brown fox jumped over the lazy dog", position: [20, 20])
|
45
|
+
Font[:jost_16].render("press [space] to change LoopState", position: [20, 400])
|
46
|
+
Font[:jost_16].render("press [q] or [esc] to quit", position: [20, 420])
|
47
|
+
Font[:jost_16].render("press [F12] to start debug", position: [20, 440])
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def sprite_logic
|
52
|
+
proc {
|
53
|
+
Sprite[:gem].render(position: { y: 220, x: 20 })
|
54
|
+
Sprite[:gem].render(position: { y: 320, x: 220 }, size: { height: 64, width: 128 })
|
55
|
+
Font[:jost_16].render("press [space] to change LoopState", position: [20, 400])
|
56
|
+
Font[:jost_16].render("press [q] or [esc] to quit", position: [20, 420])
|
57
|
+
Font[:jost_16].render("press [F12] to start debug", position: [20, 440])
|
58
|
+
}
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
#### 1.3 prepare an {event:action} hash
|
63
|
+
```ruby
|
64
|
+
LM = Hemi::Event::LoopMachine
|
65
|
+
|
66
|
+
def text_events
|
67
|
+
{
|
68
|
+
space: -> { LM.switch(:image) },
|
69
|
+
escape: :stop!,
|
70
|
+
q: :stop!,
|
71
|
+
f12: :debug!
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
def sprite_events
|
76
|
+
{
|
77
|
+
space: -> { LM.switch(:text) },
|
78
|
+
escape: :stop!,
|
79
|
+
q: :stop!,
|
80
|
+
f12: :debug!
|
81
|
+
}
|
82
|
+
end
|
83
|
+
```
|
84
|
+
|
85
|
+
#### 1.4 register Loop Machine states
|
86
|
+
```ruby
|
87
|
+
def run
|
88
|
+
LM.register(:text, text_logic, text_events)
|
89
|
+
LM.register(:image, sprite_logic, sprite_events)
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
#### 1.5 and run it
|
94
|
+
```ruby
|
95
|
+
Game.instance.run
|
96
|
+
```
|
data/hemi.gemspec
CHANGED
@@ -30,4 +30,6 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.add_development_dependency "rubocop", "~> 0.77"
|
31
31
|
spec.add_development_dependency "rubocop-performance", "~> 1.5"
|
32
32
|
spec.add_development_dependency "rubocop-rspec", "~> 1.37"
|
33
|
+
spec.add_development_dependency "simplecov", "~> 0.20"
|
34
|
+
spec.add_development_dependency "yard", "~> 0.9"
|
33
35
|
end
|
data/lib/hemi/engine.rb
CHANGED
@@ -4,24 +4,54 @@ require "sdl2"
|
|
4
4
|
require_relative "loader"
|
5
5
|
|
6
6
|
module Hemi
|
7
|
+
# Entry-level module, meant to be _prepended_ in the main class of the game using the `hemi` gem.
|
8
|
+
#
|
9
|
+
# Prepending this module allows developers to write their custom +initialize+ and +run+ methods
|
10
|
+
# without overriding any of the mandatory logic. Becasue of the `prepend` behavior,
|
11
|
+
# `Hemi::Engine` will end up first in ancestors' list.
|
12
|
+
#
|
13
|
+
# So, technically, if `Game` implements its own `initialize` / `run` methods, those will be
|
14
|
+
# super-called from `Hemi::Engine`:
|
15
|
+
#
|
16
|
+
# ```ruby
|
17
|
+
# require "hemi"
|
18
|
+
#
|
19
|
+
# class Game
|
20
|
+
# prepend Hemi::Engine
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# Game.ancestors
|
24
|
+
# => [Hemi::Engine, Game, Singleton, Object, PP::ObjectMixin, Kernel, BasicObject]
|
25
|
+
# ```
|
7
26
|
module Engine
|
8
27
|
@debug = false
|
9
28
|
@stop = false
|
10
29
|
|
30
|
+
# Initializes all required `SDL` modules and then proceeds to execute the constructor of the
|
31
|
+
# class it prepends.
|
11
32
|
def initialize
|
12
33
|
sdl_init
|
13
34
|
super
|
14
35
|
end
|
15
36
|
|
37
|
+
# @return [SDL2::Window]
|
38
|
+
# @api private
|
16
39
|
attr_reader :window
|
17
40
|
|
18
|
-
def sdl_init
|
19
|
-
SDL2.init(SDL2::INIT_EVERYTHING)
|
20
|
-
end
|
21
|
-
|
22
41
|
class << self
|
23
|
-
|
42
|
+
# @return [Boolean] Returns `true` if the engine is set to debugging mode.
|
43
|
+
attr_reader :debug
|
44
|
+
# @return [Boolean] Returns `true` if the engine is set to gracefully exit upon finishing
|
45
|
+
# this event loop.
|
46
|
+
attr_reader :stop
|
24
47
|
|
48
|
+
# Ran when a class calls to be prepended by this module.
|
49
|
+
#
|
50
|
+
# As mentioned - this module is meant to be _prepended_ in the main game class. When
|
51
|
+
# prepended, this method is automatically ran, making the class a Singleton and makes sure all
|
52
|
+
# `Hemi` modules are loaded in required order.
|
53
|
+
#
|
54
|
+
# @param [Class] klass
|
25
55
|
def prepended(klass)
|
26
56
|
klass.include Singleton
|
27
57
|
|
@@ -31,19 +61,47 @@ module Hemi
|
|
31
61
|
Loader.load_tree "event"
|
32
62
|
end
|
33
63
|
|
64
|
+
# Sets `@debug` instance variable to `true`. Doing this will trigger the current
|
65
|
+
# {Hemi::Event::LoopMachine#call LoopMachine's} {Hemi::Event::EventLoop EventLoop} to stop at
|
66
|
+
# the nearest `binding.pry` (thus, halting the game and allowing game's current state to be
|
67
|
+
# debugged).
|
68
|
+
#
|
69
|
+
# @note Ideally this method should NOT be called manually, {Hemi::Event::EventLoop EventLoop}
|
70
|
+
# calls it when it receives an event resulting in a `:debug!` action.
|
71
|
+
#
|
72
|
+
# @api private
|
34
73
|
def debug_on!
|
35
74
|
@debug = true
|
36
75
|
end
|
37
76
|
|
77
|
+
# Sets `@debug` instance variable to `false`. This makes sure that after opening a pry
|
78
|
+
# REPL session and ending it with calling `exit` from pry's REPL, the `@debug` flag is off
|
79
|
+
# and the program can continue operating normally.
|
80
|
+
#
|
81
|
+
# @note Ideally this method should NOT be called manually. It is called internally right after
|
82
|
+
# {Hemi::Event::LoopMachine#call LoopMachine} handles `binding.pry` in `#debug?` method.
|
83
|
+
#
|
84
|
+
# @api private
|
38
85
|
def debug_off!
|
39
86
|
@debug = false
|
40
87
|
end
|
41
88
|
|
89
|
+
# Sets `@stop` instance variable to `true`. This triggers a _graceful_ exit of the entire
|
90
|
+
# {Hemi::Event::LoopMachine#call LoopMachine's} {Hemi::Event::EventLoop EventLoop} - and,
|
91
|
+
# by extension, exits the program upon the next complete loop.
|
92
|
+
#
|
93
|
+
# @note Ideally this method should NOT be called manually, {Hemi::Event::EventLoop EventLoop}
|
94
|
+
# calls it when it receives an event resulting in a `:stop!` action.
|
95
|
+
#
|
96
|
+
# @api private
|
42
97
|
def stop!
|
43
98
|
@stop = true
|
44
99
|
end
|
45
100
|
end
|
46
101
|
|
102
|
+
# Starts the game engine. Takes care of all custom logic in prepended class' `#run` method, then
|
103
|
+
# initializes a program window and calls {Hemi::Event::LoopMachine LoopMachine} to start running
|
104
|
+
# its event loops.
|
47
105
|
def run
|
48
106
|
super if defined?(super)
|
49
107
|
init_window
|
@@ -52,6 +110,10 @@ module Hemi
|
|
52
110
|
|
53
111
|
private
|
54
112
|
|
113
|
+
def sdl_init
|
114
|
+
SDL2.init(SDL2::INIT_EVERYTHING)
|
115
|
+
end
|
116
|
+
|
55
117
|
def init_window
|
56
118
|
@window = Hemi::Render::Window.instance
|
57
119
|
end
|
@@ -1,11 +1,10 @@
|
|
1
1
|
module Hemi::Event
|
2
2
|
class EventLoop
|
3
|
+
include Hemi::Event::KeyHandler
|
3
4
|
|
4
5
|
def initialize(logic, events)
|
5
6
|
@logic = logic
|
6
|
-
|
7
|
-
hsh[SDL2::Key::Scan.const_get(key.upcase)] = action
|
8
|
-
end
|
7
|
+
register_events!(events)
|
9
8
|
end
|
10
9
|
|
11
10
|
attr_reader :logic, :events, :event
|
@@ -17,8 +16,6 @@ module Hemi::Event
|
|
17
16
|
when SDL2::Event::KeyDown
|
18
17
|
handle_key
|
19
18
|
end
|
20
|
-
|
21
|
-
@event = nil
|
22
19
|
end
|
23
20
|
|
24
21
|
def process
|
@@ -27,25 +24,6 @@ module Hemi::Event
|
|
27
24
|
|
28
25
|
private
|
29
26
|
|
30
|
-
def handle_key
|
31
|
-
case action = events[event.scancode]
|
32
|
-
when Symbol
|
33
|
-
instance_eval action.to_s
|
34
|
-
when Proc
|
35
|
-
action.call
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def key_event?
|
40
|
-
event.is_a?
|
41
|
-
end
|
42
|
-
|
43
|
-
def key_down
|
44
|
-
return unless key_event?
|
45
|
-
|
46
|
-
SDL2::Key::Scan.const_get(event.scancode).downcase
|
47
|
-
end
|
48
|
-
|
49
27
|
def debug!
|
50
28
|
Hemi::Engine.debug_on!
|
51
29
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Hemi::Event
|
2
|
+
module KeyHandler
|
3
|
+
private
|
4
|
+
|
5
|
+
def handle_key
|
6
|
+
case action = events[event.structize]
|
7
|
+
when Symbol
|
8
|
+
instance_eval action.to_s
|
9
|
+
when Proc
|
10
|
+
action.call
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def register_events!(events)
|
15
|
+
@events = event_hash(events)
|
16
|
+
end
|
17
|
+
|
18
|
+
def event_hash(events)
|
19
|
+
events.each_with_object({}) do |(input, action), hsh|
|
20
|
+
key, mods = if input.is_a? Array
|
21
|
+
[input.shift, input]
|
22
|
+
else
|
23
|
+
input
|
24
|
+
end
|
25
|
+
|
26
|
+
hsh[Hemi::Event::Pattern::Key.new(key, mods: mods)] = action
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -1,12 +1,27 @@
|
|
1
1
|
module Hemi::Event
|
2
|
+
# The brain of the operation. A state machine which keeps performing assigned logic, while
|
3
|
+
# listening for assigned events.
|
2
4
|
class LoopMachine
|
3
5
|
include Singleton
|
4
6
|
|
5
7
|
@loops = {}
|
6
8
|
@current = nil
|
7
9
|
|
10
|
+
# @return [SDL2::Event] the last/current SDL event being handled.
|
11
|
+
# @api private
|
8
12
|
attr_reader :event
|
9
13
|
|
14
|
+
# Main operation method. Performs these steps in order:
|
15
|
+
#
|
16
|
+
# 1. Wipes the current window (by drawing a black rectangle over it).
|
17
|
+
# 2. Checks if SDL picked up any events and handles them.
|
18
|
+
# 3. Processes the "frame" logic: calculating, moving and drawing to framebuffer.
|
19
|
+
# 4. Copies the frame's content from framebuffer to display (inside the window).
|
20
|
+
# 5. Checks if `Hemi::Engine.debug` has been set to `true`; opens a `pry` session if so.
|
21
|
+
# 6. Checks if `Hemi::Engine.stop` has been set to `true`; breaks from the loop if so.
|
22
|
+
# 7. Sleeps for a hardcoded amount of time.
|
23
|
+
#
|
24
|
+
# @note This method is being automatically called by {Hemi::Engine#run Hemi::Engine's} `#run`.
|
10
25
|
def call
|
11
26
|
loop do
|
12
27
|
Hemi::Render::Window.wipe_screen
|
@@ -24,9 +39,32 @@ module Hemi::Event
|
|
24
39
|
end
|
25
40
|
|
26
41
|
class << self
|
27
|
-
|
28
|
-
|
29
|
-
|
42
|
+
# @return [Hash] A simple collection of "loop-states", with as their keys,
|
43
|
+
# and {EventLoop} instances as values.
|
44
|
+
attr_reader :loops
|
45
|
+
# @return [EventLoop] The currently active "loop-state", which logic and events are being
|
46
|
+
# handled in the main `#call` loop.
|
47
|
+
attr_reader :current
|
48
|
+
|
49
|
+
# Registers an {EventLoop} in the `@loops` collection with the `name` as its identifier.
|
50
|
+
# If the collection was empty before registration, the first {EventLoop} is automatically
|
51
|
+
# set as _current_.
|
52
|
+
#
|
53
|
+
# @param [Symbol] name The {EventLoop}'s identifier, i.e. - a key in `@loops` collection.
|
54
|
+
# @param [Proc] logic Proc-wrapped logic to be ran at every iteration of the loop (frame).
|
55
|
+
# @param [Hash] events A simple collection of events and their corresponding actions.
|
56
|
+
#
|
57
|
+
# @example excerpt from demo/01-loop_machine_demo.rb
|
58
|
+
# class LoopMachineDemo
|
59
|
+
# prepend Hemi::Engine
|
60
|
+
# LM = Hemi::Event::LoopMachine
|
61
|
+
#
|
62
|
+
# def run
|
63
|
+
# LM.register(:text, text_block, text_events)
|
64
|
+
# LM.register(:image, sprite_block, sprite_events)
|
65
|
+
# end
|
66
|
+
# end
|
67
|
+
def register(name, logic = proc {}, events = {})
|
30
68
|
event_loop = EventLoop.new(logic, events)
|
31
69
|
@current = event_loop if loops.empty?
|
32
70
|
@loops[name] = event_loop
|
@@ -34,14 +72,24 @@ module Hemi::Event
|
|
34
72
|
event_loop
|
35
73
|
end
|
36
74
|
|
75
|
+
# Fetch a registered {EventLoop} from `@loops` collection.
|
76
|
+
#
|
77
|
+
# @param [Symbol] name
|
78
|
+
# @return [EventLoop]
|
37
79
|
def [](name)
|
38
80
|
@loops[name]
|
39
81
|
end
|
40
82
|
|
83
|
+
# Transitions to another state, setting its {EventLoop} as `@current`. Starts performing its
|
84
|
+
# logic and listening to its events.
|
41
85
|
def switch(name)
|
42
86
|
@current = LoopMachine[name]
|
43
87
|
end
|
44
88
|
|
89
|
+
# Empties `@loops` collection and sets `@current` state to nil. Currently only used
|
90
|
+
# to ensure spec scenario isolation.
|
91
|
+
#
|
92
|
+
# @api private
|
45
93
|
def purge!
|
46
94
|
@loops = {}
|
47
95
|
@current = nil
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Hemi::Event
|
2
|
+
module Pattern
|
3
|
+
class Key
|
4
|
+
MATCHED_EVENT = "SDL2::Event::KeyDown".freeze
|
5
|
+
|
6
|
+
ALLOWED_TYPES = %i[up down].freeze
|
7
|
+
MOD_KEYS = %i[lshift rshift lctrl rctrl lalt ralt lgui rgui].freeze
|
8
|
+
|
9
|
+
def initialize(key, type: :down, mods: nil)
|
10
|
+
@type = type.to_s
|
11
|
+
@key = key.to_s
|
12
|
+
@mods = mods
|
13
|
+
key_to_scancode
|
14
|
+
mods_to_modcode
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :type, :key, :mods, :scancode, :modcode
|
18
|
+
|
19
|
+
def hash
|
20
|
+
KeyPattern.new(scancode, modcode).hash
|
21
|
+
end
|
22
|
+
|
23
|
+
def inspect
|
24
|
+
"#<#{self.class}:#{hash} key=#{key} mods=#{mods.join(', ')}>"
|
25
|
+
end
|
26
|
+
|
27
|
+
def key_to_scancode
|
28
|
+
@scancode = SDL2::Key::Scan.const_get(key.upcase)
|
29
|
+
end
|
30
|
+
|
31
|
+
def mods_to_modcode
|
32
|
+
@modcode = mods&.sum do |modkey|
|
33
|
+
SDL2::Key::Mod.const_get(modkey.upcase)
|
34
|
+
end || 0
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/hemi/helpers/simple.rb
CHANGED
@@ -1,2 +1,3 @@
|
|
1
|
-
Size
|
2
|
-
Position
|
1
|
+
Size = Struct.new(:width, :height, keyword_init: true)
|
2
|
+
Position = Struct.new(:x, :y, keyword_init: true)
|
3
|
+
KeyPattern = Struct.new(:scancode, :mod)
|
data/lib/hemi/loader.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
module Hemi
|
2
2
|
module Loader
|
3
|
-
def self.load_tree(tree_dir)
|
3
|
+
def self.load_tree(tree_dir, relative: false)
|
4
4
|
if File.exist?(manifest_file = File.join(__dir__, tree_dir, "_manifest.rb"))
|
5
|
-
|
5
|
+
relative ? require_relative(manifest_file) : require(manifest_file)
|
6
6
|
else
|
7
7
|
Dir[File.join(__dir__, tree_dir, "**", "*.rb")].sort.each do |file|
|
8
|
-
|
8
|
+
relative ? require_relative(file) : require(file)
|
9
9
|
end
|
10
10
|
end
|
11
11
|
end
|
data/lib/hemi/render/texture.rb
CHANGED
@@ -2,7 +2,7 @@ module Hemi::Render
|
|
2
2
|
class Texture
|
3
3
|
ERR__INVALID_POSITION = "Ivalid position.".freeze
|
4
4
|
|
5
|
-
def initialize
|
5
|
+
def initialize
|
6
6
|
raise NotImplementedError
|
7
7
|
end
|
8
8
|
|
@@ -66,7 +66,7 @@ module Hemi::Render
|
|
66
66
|
position_obj.x = position[:x]
|
67
67
|
position_obj.y = position[:y]
|
68
68
|
else
|
69
|
-
raise ArgumentError
|
69
|
+
raise ArgumentError, ERR__INVALID_POSITION
|
70
70
|
end
|
71
71
|
|
72
72
|
position_obj
|
data/lib/hemi/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hemi
|
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
|
- Jakub Żuchowski
|
@@ -94,25 +94,59 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '1.37'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: simplecov
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.20'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.20'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: yard
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.9'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0.9'
|
97
125
|
description:
|
98
126
|
email: ellmo@ellmo.net
|
99
127
|
executables: []
|
100
128
|
extensions: []
|
101
129
|
extra_rdoc_files: []
|
102
130
|
files:
|
131
|
+
- ".circleci/config.yml"
|
103
132
|
- ".gitignore"
|
104
133
|
- ".rspec"
|
105
134
|
- ".rubocop.yml"
|
106
135
|
- ".ruby-version"
|
136
|
+
- ".yardopts"
|
137
|
+
- DEV.md
|
107
138
|
- Gemfile
|
108
139
|
- Gemfile.lock
|
109
140
|
- README.md
|
110
141
|
- hemi.gemspec
|
111
142
|
- lib/hemi.rb
|
112
143
|
- lib/hemi/engine.rb
|
144
|
+
- lib/hemi/event/_manifest.rb
|
113
145
|
- lib/hemi/event/event_loop.rb
|
146
|
+
- lib/hemi/event/key_handler.rb
|
114
147
|
- lib/hemi/event/loop_machine.rb
|
115
|
-
- lib/hemi/
|
148
|
+
- lib/hemi/event/pattern/key.rb
|
149
|
+
- lib/hemi/helpers/injections.rb
|
116
150
|
- lib/hemi/helpers/simple.rb
|
117
151
|
- lib/hemi/loader.rb
|
118
152
|
- lib/hemi/render/_manifest.rb
|
File without changes
|