glimmer_snake 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +20 -0
- data/README.md +126 -0
- data/TODO.md +3 -0
- data/VERSION +1 -0
- data/app/glimmer_snake/launch.rb +3 -0
- data/app/glimmer_snake/model/apple.rb +33 -0
- data/app/glimmer_snake/model/cell.rb +27 -0
- data/app/glimmer_snake/model/game.rb +68 -0
- data/app/glimmer_snake/model/grid.rb +49 -0
- data/app/glimmer_snake/model/snake.rb +95 -0
- data/app/glimmer_snake/model/vertebra.rb +22 -0
- data/app/glimmer_snake/view/glimmer_snake.rb +89 -0
- data/app/glimmer_snake/view/snake.rb +91 -0
- data/app/glimmer_snake.rb +20 -0
- data/bin/glimmer_snake +8 -0
- data/glimmer_snake.gemspec +0 -0
- data/icons/linux/Glimmer Snake.png +0 -0
- data/icons/macosx/Glimmer Snake.icns +0 -0
- data/icons/windows/Glimmer Snake.ico +0 -0
- metadata +132 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2d1bec8cd2eac33a2b2546c9a852007b7fb58d26556ee207a9c2ba0966775311
|
4
|
+
data.tar.gz: ebe57fdb0c8c69eace44d740d3972c3793932839807a3db87269833acb9d35d8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4d0e241b9fdeba7328906c739364d06dc518f45c279340775e5f85b305652b8c6da3d32f7a990f3fedf6dceeaf04dc4b4f8ea1093a0a6d043046eda4e2c0e9fe
|
7
|
+
data.tar.gz: 6c7775a38e281cfc373ee5b070803d9d65d75eb03316ea97a9ea2a84b1e617dfbe729d93c361d9f375c78aa390c815e818cd8f7fe6f9aaefad4c819d1e536441
|
data/CHANGELOG.md
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2023 Andy Maleh
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
# <img alt="Glimmer Tetris Icon" src="https://raw.githubusercontent.com/AndyObtiva/glimmer_snake/master/icons/linux/Glimmer%20Snake.png" height=85 /> Glimmer Snake 1.0.0
|
2
|
+
## [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=40 /> Glimmer DSL for LibUI Application](https://github.com/AndyObtiva/glimmer-dsl-libui)
|
3
|
+
[](http://badge.fury.io/rb/glimmer_snake)
|
4
|
+
|
5
|
+
Snake game that runs on Mac, Windows, and Linux. Built with [Ruby](https://www.ruby-lang.org/) and [Glimmer DSL for LibUI](https://github.com/AndyObtiva/glimmer-dsl-libui) (Prerequisite-Free Ruby Desktop Development Cross-Platform Native GUI Library) using [Application Scaffolding](https://github.com/AndyObtiva/glimmer-dsl-libui#scaffold-application).
|
6
|
+
|
7
|
+

|
8
|
+
|
9
|
+
## Setup
|
10
|
+
|
11
|
+
Assuming you have [Ruby](https://www.ruby-lang.org/) installed (standard MRI / CRuby).
|
12
|
+
|
13
|
+
Run:
|
14
|
+
|
15
|
+
```
|
16
|
+
gem install glimmer_snake
|
17
|
+
```
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Run:
|
22
|
+
|
23
|
+
```
|
24
|
+
glimmer_snake
|
25
|
+
```
|
26
|
+
|
27
|
+
Mac | Windows | Linux
|
28
|
+
----|---------|------
|
29
|
+
  |   |  
|
30
|
+
|
31
|
+
The goal is for the green snake to eat the red apple and to survive for as long as possible. Every time it eats an apple, it grows by 1 block (the size of the apple). If the snake hits its own body (especially after enlargement), it dies.
|
32
|
+
|
33
|
+
The game remembers the highest score by storing in `~/.glimmer-snake`. You can delete that file if you want to reset the highest score.
|
34
|
+
|
35
|
+
## Development
|
36
|
+
|
37
|
+
Clone project:
|
38
|
+
|
39
|
+
```
|
40
|
+
git clone https://github.com/AndyObtiva/glimmer_snake.git
|
41
|
+
```
|
42
|
+
|
43
|
+
Change directory:
|
44
|
+
|
45
|
+
```
|
46
|
+
cd glimmer_snake
|
47
|
+
```
|
48
|
+
|
49
|
+
Install project gems with [Bundler](https://bundler.io/):
|
50
|
+
|
51
|
+
```
|
52
|
+
bundle
|
53
|
+
```
|
54
|
+
|
55
|
+
Run application with `glimmer` command:
|
56
|
+
|
57
|
+
```
|
58
|
+
glimmer run
|
59
|
+
```
|
60
|
+
|
61
|
+
Or run using included binary script:
|
62
|
+
|
63
|
+
```
|
64
|
+
bin/glimmer_snake
|
65
|
+
```
|
66
|
+
|
67
|
+
Package as a Ruby gem with `glimmer` command:
|
68
|
+
|
69
|
+
```
|
70
|
+
glimmer "package:gem"
|
71
|
+
```
|
72
|
+
|
73
|
+
Or package using equivalent direct rake command:
|
74
|
+
|
75
|
+
```
|
76
|
+
rake build
|
77
|
+
```
|
78
|
+
|
79
|
+
Generate updated gemspec with `glimmer command`:
|
80
|
+
|
81
|
+
```
|
82
|
+
glimmer "package:gemspec"
|
83
|
+
```
|
84
|
+
|
85
|
+
Or generate gemspec using equivalent direct rake command:
|
86
|
+
|
87
|
+
```
|
88
|
+
rake gemspec:generate
|
89
|
+
```
|
90
|
+
|
91
|
+
## Contributing to glimmer_snake
|
92
|
+
|
93
|
+
- Check out the latest master to make sure the feature hasn't been
|
94
|
+
implemented or the bug hasn't been fixed yet.
|
95
|
+
- Check out the issue tracker to make sure someone already hasn't
|
96
|
+
requested it and/or contributed it.
|
97
|
+
- Fork the project.
|
98
|
+
- Start a feature/bugfix branch.
|
99
|
+
- Commit and push until you are happy with your contribution.
|
100
|
+
- Make sure to add tests for it. This is important so I don't break it
|
101
|
+
in a future version unintentionally.
|
102
|
+
- Please try not to mess with the Rakefile, version, or history. If
|
103
|
+
you want to have your own version, or is otherwise necessary, that
|
104
|
+
is fine, but please isolate to its own commit so I can cherry-pick
|
105
|
+
around it.
|
106
|
+
|
107
|
+
## TODO
|
108
|
+
|
109
|
+
[TODO.md](TODO.md)
|
110
|
+
|
111
|
+
## Change Log
|
112
|
+
|
113
|
+
[CHANGELOG.md](CHANGELOG.md)
|
114
|
+
|
115
|
+
## Copyright
|
116
|
+
|
117
|
+
[MIT](LICENSE.txt)
|
118
|
+
|
119
|
+
Copyright (c) 2023 Andy Maleh. See
|
120
|
+
[LICENSE.txt](LICENSE.txt) for further details.
|
121
|
+
|
122
|
+
--
|
123
|
+
|
124
|
+
[<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=40 />](https://github.com/AndyObtiva/glimmer) Built with [Glimmer DSL for LibUI](https://github.com/AndyObtiva/glimmer-dsl-libui) (Prerequisite-Free Ruby Desktop Development Cross-Platform Native GUI Library)
|
125
|
+
|
126
|
+
Glimmer Snake icon made by <a href="https://www.flaticon.com/authors/freepik" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a>
|
data/TODO.md
ADDED
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class GlimmerSnake
|
2
|
+
module Model
|
3
|
+
class Apple
|
4
|
+
attr_reader :game
|
5
|
+
attr_accessor :row, :column
|
6
|
+
|
7
|
+
def initialize(game)
|
8
|
+
@game = game
|
9
|
+
end
|
10
|
+
|
11
|
+
# generates a new location from scratch or via dependency injection of what cell is (for testing purposes)
|
12
|
+
def generate(initial_row: nil, initial_column: nil)
|
13
|
+
if initial_row && initial_column
|
14
|
+
self.row, self.column = initial_row, initial_column
|
15
|
+
else
|
16
|
+
self.row, self.column = @game.height.times.zip(@game.width.times).reject do |row, column|
|
17
|
+
@game.snake.vertebrae.map {|v| [v.row, v.column]}.include?([row, column])
|
18
|
+
end.sample
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def remove
|
23
|
+
self.row = nil
|
24
|
+
self.column = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
# inspect is overridden to prevent printing very long stack traces
|
28
|
+
def inspect
|
29
|
+
"#{super[0, 120]}... >"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class GlimmerSnake
|
2
|
+
module Presenter
|
3
|
+
class Cell
|
4
|
+
COLOR_CLEAR = :white
|
5
|
+
COLOR_SNAKE = :green
|
6
|
+
COLOR_APPLE = :red
|
7
|
+
|
8
|
+
attr_reader :row, :column, :grid
|
9
|
+
attr_accessor :color
|
10
|
+
|
11
|
+
def initialize(grid: ,row: ,column: )
|
12
|
+
@row = row
|
13
|
+
@column = column
|
14
|
+
@grid = grid
|
15
|
+
end
|
16
|
+
|
17
|
+
def clear
|
18
|
+
self.color = COLOR_CLEAR unless color == COLOR_CLEAR
|
19
|
+
end
|
20
|
+
|
21
|
+
# inspect is overridden to prevent printing very long stack traces
|
22
|
+
def inspect
|
23
|
+
"#{super[0, 150]}... >"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
require_relative 'snake'
|
4
|
+
require_relative 'apple'
|
5
|
+
|
6
|
+
class GlimmerSnake
|
7
|
+
module Model
|
8
|
+
class Game
|
9
|
+
WIDTH_DEFAULT = 20
|
10
|
+
HEIGHT_DEFAULT = 20
|
11
|
+
FILE_HIGH_SCORE = File.expand_path(File.join(Dir.home, '.glimmer-snake'))
|
12
|
+
|
13
|
+
attr_reader :width, :height
|
14
|
+
attr_accessor :snake, :apple, :over, :score, :high_score, :paused
|
15
|
+
alias over? over
|
16
|
+
alias paused? paused
|
17
|
+
|
18
|
+
def initialize(width = WIDTH_DEFAULT, height = HEIGHT_DEFAULT)
|
19
|
+
@width = width
|
20
|
+
@height = height
|
21
|
+
@snake = Snake.new(self)
|
22
|
+
@apple = Apple.new(self)
|
23
|
+
FileUtils.touch(FILE_HIGH_SCORE)
|
24
|
+
@high_score = File.read(FILE_HIGH_SCORE).to_i rescue 0
|
25
|
+
end
|
26
|
+
|
27
|
+
def score=(new_score)
|
28
|
+
@score = new_score
|
29
|
+
self.high_score = @score if @score > @high_score
|
30
|
+
end
|
31
|
+
|
32
|
+
def high_score=(new_high_score)
|
33
|
+
@high_score = new_high_score
|
34
|
+
File.write(FILE_HIGH_SCORE, @high_score.to_s)
|
35
|
+
rescue => e
|
36
|
+
puts e.full_message
|
37
|
+
end
|
38
|
+
|
39
|
+
def start
|
40
|
+
self.over = false
|
41
|
+
self.score = 0
|
42
|
+
self.snake.generate
|
43
|
+
self.apple.generate
|
44
|
+
end
|
45
|
+
|
46
|
+
def pause
|
47
|
+
self.paused = true
|
48
|
+
end
|
49
|
+
|
50
|
+
def resume
|
51
|
+
self.paused = false
|
52
|
+
end
|
53
|
+
|
54
|
+
def toggle_pause
|
55
|
+
unless paused?
|
56
|
+
pause
|
57
|
+
else
|
58
|
+
resume
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# inspect is overridden to prevent printing very long stack traces
|
63
|
+
def inspect
|
64
|
+
"#{super[0, 75]}... >"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'glimmer'
|
2
|
+
require_relative '../model/game'
|
3
|
+
require_relative 'cell'
|
4
|
+
|
5
|
+
class GlimmerSnake
|
6
|
+
module Presenter
|
7
|
+
class Grid
|
8
|
+
include Glimmer
|
9
|
+
|
10
|
+
attr_reader :game, :cells
|
11
|
+
|
12
|
+
def initialize(game = Model::Game.new)
|
13
|
+
@game = game
|
14
|
+
@cells = @game.height.times.map do |row|
|
15
|
+
@game.width.times.map do |column|
|
16
|
+
Cell.new(grid: self, row: row, column: column)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
observe(@game.snake, :vertebrae) do |new_vertebrae|
|
20
|
+
occupied_snake_positions = @game.snake.vertebrae.map {|v| [v.row, v.column]}
|
21
|
+
@cells.each_with_index do |row_cells, row|
|
22
|
+
row_cells.each_with_index do |cell, column|
|
23
|
+
if [@game.apple.row, @game.apple.column] == [row, column]
|
24
|
+
cell.color = Cell::COLOR_APPLE
|
25
|
+
elsif occupied_snake_positions.include?([row, column])
|
26
|
+
cell.color = Cell::COLOR_SNAKE
|
27
|
+
else
|
28
|
+
cell.clear
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def clear
|
36
|
+
@cells.each do |row_cells|
|
37
|
+
row_cells.each do |cell|
|
38
|
+
cell.clear
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# inspect is overridden to prevent printing very long stack traces
|
44
|
+
def inspect
|
45
|
+
"#{super[0, 75]}... >"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require_relative 'vertebra'
|
2
|
+
|
3
|
+
class GlimmerSnake
|
4
|
+
module Model
|
5
|
+
class Snake
|
6
|
+
SCORE_EAT_APPLE = 50
|
7
|
+
RIGHT_TURN_MAP = {
|
8
|
+
north: :east,
|
9
|
+
east: :south,
|
10
|
+
south: :west,
|
11
|
+
west: :north
|
12
|
+
}
|
13
|
+
LEFT_TURN_MAP = RIGHT_TURN_MAP.invert
|
14
|
+
|
15
|
+
attr_accessor :collided
|
16
|
+
alias collided? collided
|
17
|
+
|
18
|
+
attr_reader :game
|
19
|
+
# vertebrae and joins are ordered from tail to head
|
20
|
+
attr_accessor :vertebrae
|
21
|
+
|
22
|
+
def initialize(game)
|
23
|
+
@game = game
|
24
|
+
end
|
25
|
+
|
26
|
+
# generates a new snake location and orientation from scratch or via dependency injection of what head_cell and orientation are (for testing purposes)
|
27
|
+
def generate(initial_row: nil, initial_column: nil, initial_orientation: nil)
|
28
|
+
self.collided = false
|
29
|
+
initial_vertebra = Vertebra.new(snake: self, row: initial_row, column: initial_column, orientation: initial_orientation)
|
30
|
+
self.vertebrae = [initial_vertebra]
|
31
|
+
end
|
32
|
+
|
33
|
+
def length
|
34
|
+
@vertebrae.length
|
35
|
+
end
|
36
|
+
|
37
|
+
def head
|
38
|
+
@vertebrae.last
|
39
|
+
end
|
40
|
+
|
41
|
+
def tail
|
42
|
+
@vertebrae.first
|
43
|
+
end
|
44
|
+
|
45
|
+
def remove
|
46
|
+
self.vertebrae.clear
|
47
|
+
self.joins.clear
|
48
|
+
end
|
49
|
+
|
50
|
+
def move
|
51
|
+
@old_tail = tail.dup
|
52
|
+
@new_head = head.dup
|
53
|
+
case @new_head.orientation
|
54
|
+
when :east
|
55
|
+
@new_head.column = (@new_head.column + 1) % @game.width
|
56
|
+
when :west
|
57
|
+
@new_head.column = (@new_head.column - 1) % @game.width
|
58
|
+
when :south
|
59
|
+
@new_head.row = (@new_head.row + 1) % @game.height
|
60
|
+
when :north
|
61
|
+
@new_head.row = (@new_head.row - 1) % @game.height
|
62
|
+
end
|
63
|
+
if @vertebrae.map {|v| [v.row, v.column]}.include?([@new_head.row, @new_head.column])
|
64
|
+
self.collided = true
|
65
|
+
@game.over = true
|
66
|
+
else
|
67
|
+
@vertebrae.append(@new_head)
|
68
|
+
@vertebrae.delete(tail)
|
69
|
+
if head.row == @game.apple.row && head.column == @game.apple.column
|
70
|
+
grow
|
71
|
+
@game.apple.generate
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def turn_right
|
77
|
+
head.orientation = RIGHT_TURN_MAP[head.orientation]
|
78
|
+
end
|
79
|
+
|
80
|
+
def turn_left
|
81
|
+
head.orientation = LEFT_TURN_MAP[head.orientation]
|
82
|
+
end
|
83
|
+
|
84
|
+
def grow
|
85
|
+
@game.score += SCORE_EAT_APPLE
|
86
|
+
@vertebrae.prepend(@old_tail)
|
87
|
+
end
|
88
|
+
|
89
|
+
# inspect is overridden to prevent printing very long stack traces
|
90
|
+
def inspect
|
91
|
+
"#{super[0, 150]}... >"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class GlimmerSnake
|
2
|
+
module Model
|
3
|
+
class Vertebra
|
4
|
+
ORIENTATIONS = %i[north east south west]
|
5
|
+
# orientation is needed for snake occuppied cells (but not apple cells)
|
6
|
+
attr_reader :snake
|
7
|
+
attr_accessor :row, :column, :orientation
|
8
|
+
|
9
|
+
def initialize(snake: , row: , column: , orientation: )
|
10
|
+
@row = row || rand(snake.game.height)
|
11
|
+
@column = column || rand(snake.game.width)
|
12
|
+
@orientation = orientation || ORIENTATIONS.sample
|
13
|
+
@snake = snake
|
14
|
+
end
|
15
|
+
|
16
|
+
# inspect is overridden to prevent printing very long stack traces
|
17
|
+
def inspect
|
18
|
+
"#{super[0, 150]}... >"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'glimmer_snake/model/grid'
|
2
|
+
|
3
|
+
class GlimmerSnake
|
4
|
+
module View
|
5
|
+
class GlimmerSnake
|
6
|
+
include Glimmer::LibUI::Application
|
7
|
+
|
8
|
+
CELL_SIZE = 15
|
9
|
+
SNAKE_MOVE_DELAY = 0.1
|
10
|
+
|
11
|
+
before_body do
|
12
|
+
@game = Model::Game.new
|
13
|
+
@grid = Presenter::Grid.new(@game)
|
14
|
+
@game.start
|
15
|
+
@keypress_queue = []
|
16
|
+
end
|
17
|
+
|
18
|
+
after_body do
|
19
|
+
register_observers
|
20
|
+
end
|
21
|
+
|
22
|
+
body {
|
23
|
+
window {
|
24
|
+
# data-bind window title to game score, converting it to a title string on read from the model
|
25
|
+
title <= [@game, :score, on_read: -> (score) {"Snake (Score: #{@game.score})"}]
|
26
|
+
content_size @game.width * CELL_SIZE, @game.height * CELL_SIZE
|
27
|
+
resizable false
|
28
|
+
|
29
|
+
vertical_box {
|
30
|
+
padded false
|
31
|
+
|
32
|
+
@game.height.times do |row|
|
33
|
+
horizontal_box {
|
34
|
+
padded false
|
35
|
+
|
36
|
+
@game.width.times do |column|
|
37
|
+
area {
|
38
|
+
square(0, 0, CELL_SIZE) {
|
39
|
+
fill <= [@grid.cells[row][column], :color] # data-bind square fill to grid cell color
|
40
|
+
}
|
41
|
+
|
42
|
+
on_key_up do |area_key_event|
|
43
|
+
if area_key_event[:key] == ' '
|
44
|
+
@game.toggle_pause
|
45
|
+
else
|
46
|
+
@keypress_queue << area_key_event[:ext_key]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
}
|
50
|
+
end
|
51
|
+
}
|
52
|
+
end
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
def register_observers
|
58
|
+
observe(@game, :over) do |game_over|
|
59
|
+
Glimmer::LibUI.queue_main do
|
60
|
+
if game_over
|
61
|
+
msg_box('Game Over!', "Score: #{@game.score} | High Score: #{@game.high_score}")
|
62
|
+
@game.start
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
Glimmer::LibUI.timer(SNAKE_MOVE_DELAY) do
|
68
|
+
unless @game.paused? || @game.over?
|
69
|
+
process_queued_keypress
|
70
|
+
@game.snake.move
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def process_queued_keypress
|
76
|
+
# key press queue ensures one turn per snake move to avoid a double-turn resulting in instant death (due to snake illogically going back against itself)
|
77
|
+
key = @keypress_queue.shift
|
78
|
+
case [@game.snake.head.orientation, key]
|
79
|
+
in [:north, :right] | [:east, :down] | [:south, :left] | [:west, :up]
|
80
|
+
@game.snake.turn_right
|
81
|
+
in [:north, :left] | [:west, :down] | [:south, :right] | [:east, :up]
|
82
|
+
@game.snake.turn_left
|
83
|
+
else
|
84
|
+
# No Op
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'glimmer-dsl-libui'
|
2
|
+
|
3
|
+
require_relative 'snake/presenter/grid'
|
4
|
+
|
5
|
+
class Snake
|
6
|
+
include Glimmer
|
7
|
+
|
8
|
+
CELL_SIZE = 15
|
9
|
+
SNAKE_MOVE_DELAY = 0.1
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@game = Model::Game.new
|
13
|
+
@grid = Presenter::Grid.new(@game)
|
14
|
+
@game.start
|
15
|
+
@keypress_queue = []
|
16
|
+
create_gui
|
17
|
+
register_observers
|
18
|
+
end
|
19
|
+
|
20
|
+
def launch
|
21
|
+
@main_window.show
|
22
|
+
end
|
23
|
+
|
24
|
+
def register_observers
|
25
|
+
observe(@game, :over) do |game_over|
|
26
|
+
Glimmer::LibUI.queue_main do
|
27
|
+
if game_over
|
28
|
+
msg_box('Game Over!', "Score: #{@game.score} | High Score: #{@game.high_score}")
|
29
|
+
@game.start
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Glimmer::LibUI.timer(SNAKE_MOVE_DELAY) do
|
35
|
+
unless @game.paused? || @game.over?
|
36
|
+
process_queued_keypress
|
37
|
+
@game.snake.move
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def process_queued_keypress
|
43
|
+
# key press queue ensures one turn per snake move to avoid a double-turn resulting in instant death (due to snake illogically going back against itself)
|
44
|
+
key = @keypress_queue.shift
|
45
|
+
case [@game.snake.head.orientation, key]
|
46
|
+
in [:north, :right] | [:east, :down] | [:south, :left] | [:west, :up]
|
47
|
+
@game.snake.turn_right
|
48
|
+
in [:north, :left] | [:west, :down] | [:south, :right] | [:east, :up]
|
49
|
+
@game.snake.turn_left
|
50
|
+
else
|
51
|
+
# No Op
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def create_gui
|
56
|
+
@main_window = window {
|
57
|
+
# data-bind window title to game score, converting it to a title string on read from the model
|
58
|
+
title <= [@game, :score, on_read: -> (score) {"Snake (Score: #{@game.score})"}]
|
59
|
+
content_size @game.width * CELL_SIZE, @game.height * CELL_SIZE
|
60
|
+
resizable false
|
61
|
+
|
62
|
+
vertical_box {
|
63
|
+
padded false
|
64
|
+
|
65
|
+
@game.height.times do |row|
|
66
|
+
horizontal_box {
|
67
|
+
padded false
|
68
|
+
|
69
|
+
@game.width.times do |column|
|
70
|
+
area {
|
71
|
+
square(0, 0, CELL_SIZE) {
|
72
|
+
fill <= [@grid.cells[row][column], :color] # data-bind square fill to grid cell color
|
73
|
+
}
|
74
|
+
|
75
|
+
on_key_up do |area_key_event|
|
76
|
+
if area_key_event[:key] == ' '
|
77
|
+
@game.toggle_pause
|
78
|
+
else
|
79
|
+
@keypress_queue << area_key_event[:ext_key]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
}
|
83
|
+
end
|
84
|
+
}
|
85
|
+
end
|
86
|
+
}
|
87
|
+
}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
Snake.new.launch
|
@@ -0,0 +1,20 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path('..', __FILE__))
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'bundler/setup'
|
5
|
+
Bundler.require(:default)
|
6
|
+
rescue StandardError, Gem::LoadError
|
7
|
+
# this runs when packaged as a gem (no bundler)
|
8
|
+
require 'glimmer-dsl-libui'
|
9
|
+
# add more gems if needed
|
10
|
+
end
|
11
|
+
|
12
|
+
class GlimmerSnake
|
13
|
+
include Glimmer
|
14
|
+
|
15
|
+
APP_ROOT = File.expand_path('../..', __FILE__)
|
16
|
+
VERSION = File.read(File.join(APP_ROOT, 'VERSION'))
|
17
|
+
LICENSE = File.read(File.join(APP_ROOT, 'LICENSE.txt'))
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'glimmer_snake/view/glimmer_snake'
|
data/bin/glimmer_snake
ADDED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: glimmer_snake
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andy Maleh
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-10-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: glimmer-dsl-libui
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.9.7
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.9.7
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.5.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 3.5.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: juwelier
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 2.4.9
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.4.9
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: simplecov
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Glimmer Snake game desktop application built with Glimmer DSL for LibUI.
|
70
|
+
Gem ships with a glimmer_snake binary script for launching the game.
|
71
|
+
email: andy.am@gmail.com
|
72
|
+
executables:
|
73
|
+
- glimmer_snake
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files:
|
76
|
+
- CHANGELOG.md
|
77
|
+
- LICENSE.txt
|
78
|
+
- README.md
|
79
|
+
files:
|
80
|
+
- CHANGELOG.md
|
81
|
+
- LICENSE.txt
|
82
|
+
- README.md
|
83
|
+
- TODO.md
|
84
|
+
- VERSION
|
85
|
+
- app/glimmer_snake.rb
|
86
|
+
- app/glimmer_snake/launch.rb
|
87
|
+
- app/glimmer_snake/model/apple.rb
|
88
|
+
- app/glimmer_snake/model/cell.rb
|
89
|
+
- app/glimmer_snake/model/game.rb
|
90
|
+
- app/glimmer_snake/model/grid.rb
|
91
|
+
- app/glimmer_snake/model/snake.rb
|
92
|
+
- app/glimmer_snake/model/vertebra.rb
|
93
|
+
- app/glimmer_snake/view/glimmer_snake.rb
|
94
|
+
- app/glimmer_snake/view/snake.rb
|
95
|
+
- bin/glimmer_snake
|
96
|
+
- glimmer_snake.gemspec
|
97
|
+
- icons/linux/Glimmer Snake.png
|
98
|
+
- icons/macosx/Glimmer Snake.icns
|
99
|
+
- icons/windows/Glimmer Snake.ico
|
100
|
+
homepage: http://github.com/AndyObtiva/glimmer_snake
|
101
|
+
licenses:
|
102
|
+
- MIT
|
103
|
+
metadata: {}
|
104
|
+
post_install_message:
|
105
|
+
- |2+
|
106
|
+
|
107
|
+
Glimmer Snake 1.0.0 was installed!
|
108
|
+
Play by running:
|
109
|
+
|
110
|
+
glimmer_snake
|
111
|
+
|
112
|
+
rdoc_options: []
|
113
|
+
require_paths:
|
114
|
+
- lib
|
115
|
+
- app
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
requirements: []
|
127
|
+
rubygems_version: 3.4.10
|
128
|
+
signing_key:
|
129
|
+
specification_version: 4
|
130
|
+
summary: Glimmer Snake
|
131
|
+
test_files: []
|
132
|
+
...
|