glimmer_snake 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/glimmer_snake.svg)](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
|
+
![glimmer-dsl-libui-mac-snake.gif](/screenshots/glimmer-dsl-libui-mac-snake.gif)
|
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
|
+
![glimmer-dsl-libui-mac-snake.png](/screenshots/glimmer-dsl-libui-mac-snake.png) ![glimmer-dsl-libui-mac-snake-game-over.png](/screenshots/glimmer-dsl-libui-mac-snake-game-over.png) | ![glimmer-dsl-libui-windows-snake.png](/screenshots/glimmer-dsl-libui-windows-snake.png) ![glimmer-dsl-libui-windows-snake-game-over.png](/screenshots/glimmer-dsl-libui-windows-snake-game-over.png) | ![glimmer-dsl-libui-linux-snake.png](/screenshots/glimmer-dsl-libui-linux-snake.png) ![glimmer-dsl-libui-linux-snake-game-over.png](/screenshots/glimmer-dsl-libui-linux-snake-game-over.png)
|
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
|
+
...
|