Neulich habe ich auf Twitter von folgenden Wohltätigkeitsprojekten erfahren.
Ich spiele nicht viel PC-Spiele, aber es enthält Materialien, und als ich es mir ansah, dachte ich, ich sollte es kaufen, wenn ich es gespendet habe ... Die Buchstaben ** DragonRuby GTK ** waren da.
Es scheint, dass Sie mit Ruby plattformübergreifende Spiele erstellen können. (RubyMotion, das auf einmal vorherrschte, gehört jetzt zu dieser Familie)
Das scheint interessant zu sein, also habe ich es sofort geknallt und am Wochenende ein wenig gespielt.
Unten finden Sie eine Aufzeichnung zum Ausprobieren der macOS-Version.
Hello World
Bewegen wir es zuerst.
$ unzip dragonruby-gtk-macos.zip
$ cd dragonruby-macos/
$ ./dragonruby
# ./Gleiches gilt für Dragonruby Mygame
Es funktionierte.
mygame / app / main.rb
läuft.
In meiner Umgebung stöhnt der CPU-Lüfter nicht, selbst wenn ich ihn eine Weile laufen lasse. (Der Körper wird heiß)
Ich habe in dem Verzeichnis gearbeitet, in dem ich die Zip-Datei zuvor entpackt habe, aber ich werde versuchen, an einem anderen Ort zu arbeiten. (Um das Git-Management zu vereinfachen)
$ mkdir -p hello-dragonruby-gtk/mygame/app
$ cd hello-dragonruby-gtk/
$ cp ~/Downloads/dragonruby-macos/dragonruby .
$ cp ~/Downloads/dragonruby-macos/font.ttf .
Ich habe das Gefühl, dass der Befehl "dragonruby" nicht von einem anderen Ort aus aufgerufen werden soll, indem der Pfad festgelegt wird, also habe ich ihn kopiert.
Ich brauchte auch font.ttf
.
(Insgesamt ca. 5,9 MB)
Wenn Sie es ausführen, werden verschiedene Verzeichnisse und Dateien erstellt, also gitignore sie zusammen.
.gitignore
# DragonRuby
/dragonruby
/font.ttf
/logs
/tmp
/exceptions
console_history.txt
Nachdem wir fertig sind, schreiben wir den Quellcode, um das Quadrat zu zeichnen.
mygame/app/main.rb
def tick args
args.outputs.solids << [args.grid.center_x - 32, args.grid.h * 0.1, 64, 64]
end
Ich werde das machen.
./dragonruby
Ich konnte zeichnen.
Wenn Sie es zu "args.outputs.solids" hinzufügen, wird die Figur gezeichnet.
Da die Informationen zur Bildschirmgröße usw. in args.grid
enthalten sind, verwende ich das auch.
Es ist ein bisschen einzigartig, aber ich denke nicht, dass es besonders schwierig ist.
Die grundlegenden Spezifikationen scheinen wie folgt zu sein.
Offiziell habe ich das Gefühl, dass ich diese Notation forciere, aber um ehrlich zu sein, es tut weh, mich zum ersten Mal zu töten ...
Andere Schreibstile wurden ebenfalls richtig vorbereitet.
Wenn dies der Fall ist, scheint es in Ordnung zu sein, es zum ersten Mal zu lesen.
mygame/app/main.rb
args.outputs.solids << { x: args.grid.center_x - 32, y: args.grid.h * 0.1, w: 64, h: 64 }
Es scheint in Ordnung zu sein, die folgende Klasse zu definieren.
primitive_marker
gibt einen Typ wie: solid
zurückIch benutze diese Methode jetzt.
mygame/app/primitives.rb
class Primitive
def initialize(attributes)
attr_keys.each { |key| send("#{key}=", attributes[key]) }
end
def primitive_marker
self.class.name.downcase
end
def attr_keys
self.class.class_variable_get(:@@attr_keys)
end
def serialize
attr_keys.map { |key| [key, send(key)] }.to_h
end
def inspect
serialize.to_s
end
def to_s
serialize.to_s
end
end
class Solid < Primitive
@@attr_keys = %i[x y w h r g b a]
attr_accessor(*@@attr_keys)
end
Wenn Sie nicht "serialize", "inspect" und "to_s" definieren, wird die Konsole mit der Warnung gefüllt, wenn ein Fehler auftritt, sodass sie definiert ist.
(Ich habe @@ attr_keys
dafür ...)
Dann laden Sie diese von main.rb
.
mygame/app/main.rb
require 'app/primitives.rb'
def tick args
args.outputs.solids << Solid.new(x: args.grid.center_x - 32, y: args.grid.h * 0.1, w: 64, h: 64)
end
Als anderes Beispiel als "Fest" zeichnen wir mit "Linie" eine Kreuzlinie in der Mitte. Es wird gezeichnet, indem es zu "args.outputs.lines" hinzugefügt wird.
Ich habe "Outputs" und "Grid" in die Variablen eingefügt, weil es schwierig ist, jedes Mal "Args" zu drücken.
mygame/app/primitives.rb
class Line < Primitive
@@attr_keys = %i[x y x2 y2 r g b a]
attr_accessor(*@@attr_keys)
end
mygame/app/main.rb
require 'app/primitives.rb'
def tick args
outputs, grid = args.outputs, args.grid
outputs.solids << Solid.new(x: grid.center_x - 32, y: grid.h * 0.1, w: 64, h: 64)
outputs.lines << Line.new(x: 0, y: grid.center_y, x2: grid.w, y2: grid.center_y)
outputs.lines << Line.new(x: grid.center_x, y: 0, x2: grid.center_x, y2: grid.h)
end
Es wurde bestätigt, dass das Quadrat in der Mitte links und rechts gezeichnet werden konnte.
Bevor die Tick-Methode kompliziert wird, klassifizieren Sie das Spiel selbst.
mygame/app/main.rb
require 'app/primitives.rb'
class Game
attr_accessor :state, :outputs, :grid
def tick
output
end
def output
outputs.solids << Solid.new(x: grid.center_x - 32, y: grid.h * 0.1, w: 64, h: 64)
outputs.lines << Line.new(x: 0, y: grid.center_y, x2: grid.w, y2: grid.center_y)
outputs.lines << Line.new(x: grid.center_x, y: 0, x2: grid.center_x, y2: grid.h)
end
def serialize
{}
end
def inspect
serialize.to_s
end
def to_s
serialize.to_s
end
end
$game = Game.new
def tick args
$game.state = args.state
$game.outputs = args.outputs
$game.grid = args.grid
$game.tick
end
Es gibt einen Helfer namens "attr_gtk", aber ich verwende hier "attr_accessor", weil ich direkt auf "state" usw. zugreifen wollte.
Verwenden Sie die linke und rechte Cursortaste, um das Quadrat zu bewegen (Spieler
).
Die Informationen, die Sie über Frames hinweg aufbewahren möchten, werden im Status gespeichert.
Die Tastatureingabe kann über "inputs.keyboard.key name" erkannt werden. (Es scheint, dass Sie die Presse abholen und mit inputs.keyboard.key_held.key name
halten können, aber ich habe es nicht verwendet)
Die folgenden Änderungen wurden an main.rb
vorgenommen.
mygame/app/main.rb
require 'app/primitives.rb'
class Game
- attr_accessor :state, :outputs, :grid
+ attr_accessor :state, :outputs, :grid, :inputs
def tick
+ set_defaults
+ handle_inputs
+ update_state
output
end
+ def set_defaults
+ state.player_x ||= grid.center_x - 32
+ state.player_dx ||= 0
+ end
+
+ def handle_inputs
+ if inputs.keyboard.right
+ state.player_dx = 5
+ elsif inputs.keyboard.left
+ state.player_dx = -5
+ else
+ state.player_dx = 0
+ end
+ end
+
+ def update_state
+ state.player_x += state.player_dx
+ end
+
def output
- outputs.solids << Solid.new(x: grid.center_x - 32, y: grid.h * 0.1, w: 64, h: 64)
+ outputs.solids << Solid.new(x: state.player_x, y: grid.h * 0.1, w: 64, h: 64)
outputs.lines << Line.new(x: 0, y: grid.center_y, x2: grid.w, y2: grid.center_y)
outputs.lines << Line.new(x: grid.center_x, y: 0, x2: grid.center_x, y2: grid.h)
@@ -26,12 +50,13 @@ class Game
serialize.to_s
end
end
$game = Game.new
def tick args
$game.state = args.state
$game.outputs = args.outputs
$game.grid = args.grid
+ $game.inputs = args.inputs
$game.tick
end
Jetzt können Sie das Viereck verschieben.
Fügen Sie einen grauen Festkörper hinzu, der sich von einer Seite zur anderen bewegt. Ich habe keine neuen Elemente verwendet.
mygame/app/main.rb
def set_defaults
state.player_x ||= grid.center_x - 32
state.player_dx ||= 0
+
+ state.enemy_x ||= grid.center_x - 32
+ state.enemy_dx ||= 5
end
def update_state
state.player_x += state.player_dx
+
+ state.enemy_x += state.enemy_dx
+ if state.enemy_x < 0 || state.enemy_x > grid.w - 64
+ state.enemy_dx *= -1
+ end
end
def output
outputs.solids << Solid.new(x: state.player_x, y: grid.h * 0.1, w: 64, h: 64)
+
+ outputs.solids << Solid.new(x: state.enemy_x, y: grid.h * 0.7, w: 64, h: 64, r: 150, g: 150, b: 150)
outputs.lines << Line.new(x: 0, y: grid.center_y, x2: grid.w, y2: grid.center_y)
outputs.lines << Line.new(x: grid.center_x, y: 0, x2: grid.center_x, y2: grid.h)
end
Sie können eine Entität mit state.new_entity
hinzufügen.
Es ist eine Möglichkeit, der Entität Informationen zu geben und diese Informationen zu verwenden, um sie mit "Solid" usw. auf dem Bildschirm anzuzeigen.
(Ich denke, es kann ohne eine Entität gemacht werden, aber ich werde es verwenden, weil es vorbereitet ist.)
Ich benutze key_up
, um zu verhindern, dass es erschossen wird, indem ich es gedrückt halte.
Wenn die Kugel den Rand des Bildschirms erreicht, wird sie durch Setzen des Flags "tot" gelöscht. (Wenn es eine "tote" Flagge gibt, wird sie "abgelehnt")
mygame/app/main.rb
def set_defaults
state.player_x ||= grid.center_x - 32
state.player_dx ||= 0
state.enemy_x ||= grid.center_x - 32
state.enemy_dx ||= 5
+
+ state.bullets ||= []
end
def handle_inputs
if inputs.keyboard.right
state.player_dx = 5
elsif inputs.keyboard.left
state.player_dx = -5
else
state.player_dx = 0
end
+
+ if inputs.keyboard.key_up.space
+ state.bullets << state.new_entity(:bullet) do |bullet|
+ bullet.y = player_rect[:y]
+ bullet.x = player_rect[:x] + 16
+ bullet.size = 32
+ bullet.dy = 10
+ bullet.solid = { x: bullet.x, y: bullet.y, w: bullet.size, h: bullet.size, r: 255, g: 100, b: 100 }
+ end
+ end
end
def update_state
state.player_x += state.player_dx
state.enemy_x += state.enemy_dx
if state.enemy_x < 0 || state.enemy_x > grid.w - 64
state.enemy_dx *= -1
end
+
+ state.bullets.each do |bullet|
+ bullet.y += bullet.dy
+ bullet.solid[:y] = bullet.y
+
+ if bullet.y > grid.h
+ bullet.dead = true
+ end
+ end
+ state.bullets = state.bullets.reject(&:dead)
end
def output
- outputs.solids << Solid.new(x: state.player_x, y: grid.h * 0.1, w: 64, h: 64)
+ outputs.solids << Solid.new(player_rect)
outputs.solids << Solid.new(x: state.enemy_x, y: grid.h * 0.7, w: 64, h: 64, r: 150, g: 150, b: 150)
+
+ outputs.solids << state.bullets.map(&:solid)
outputs.lines << Line.new(x: 0, y: grid.center_y, x2: grid.w, y2: grid.center_y)
outputs.lines << Line.new(x: grid.center_x, y: 0, x2: grid.center_x, y2: grid.h)
end
+
+ private
+
+ def player_rect
+ { x: state.player_x, y: grid.h * 0.1, w: 64, h: 64 }
+ end
Sie können jetzt Kugeln abschießen.
Sie können "intersect_rect" verwenden, um den Treffer zu bestimmen.
mygame/app/main.rb
def update_state
state.player_x += state.player_dx
state.enemy_x += state.enemy_dx
if state.enemy_x < 0 || state.enemy_x > grid.w - 64
state.enemy_dx *= -1
end
state.bullets.each do |bullet|
bullet.y += bullet.dy
bullet.solid[:y] = bullet.y
if bullet.y > grid.h
bullet.dead = true
end
+ if bullet.solid.intersect_rect?(enemy_rect)
+ bullet.dead = true
+ end
end
state.bullets = state.bullets.reject(&:dead)
end
def output
outputs.solids << Solid.new(player_rect)
- outputs.solids << Solid.new(x: state.enemy_x, y: grid.h * 0.7, w: 64, h: 64, r: 150, g: 150, b: 150)
+ outputs.solids << Solid.new(enemy_rect.merge(r: 150, g: 150, b: 150))
outputs.solids << state.bullets.map(&:solid)
outputs.lines << Line.new(x: 0, y: grid.center_y, x2: grid.w, y2: grid.center_y)
outputs.lines << Line.new(x: grid.center_x, y: 0, x2: grid.center_x, y2: grid.h)
end
+
+ def enemy_rect
+ { x: state.enemy_x, y: grid.h * 0.7, w: 64, h: 64 }
+ end
Es ist ein wenig verwirrend, aber wenn es einen Feind trifft, verschwindet die Kugel.
Wenn die Kugel den Feind trifft, sind es +2 Punkte, wenn sie nicht trifft, sind es -1 Punkte und die Summe wird oben rechts angezeigt.
Verwenden Sie Label
, um den Text anzuzeigen.
Ich habe Drücken Sie Start 2P - Google Fonts verwendet, um eine punktförmige Schriftart zu erstellen. (Fügen Sie das heruntergeladene und erweiterte in "mygame / fonts" ein
mygame/app/primitives.rb
class Label < Primitive
@@attr_keys = %i[x y text size_enum alignment_enum font r g b a]
attr_accessor(*@@attr_keys)
end
mygame/app/main.rb
def set_defaults
state.player_x ||= grid.center_x - 32
state.player_dx ||= 0
state.enemy_x ||= grid.center_x - 32
state.enemy_dx ||= 5
state.bullets ||= []
+
+ state.score ||= 0
end
def update_state
state.player_x += state.player_dx
state.enemy_x += state.enemy_dx
if state.enemy_x < 0 || state.enemy_x > grid.w - 64
state.enemy_dx *= -1
end
state.bullets.each do |bullet|
bullet.y += bullet.dy
bullet.solid[:y] = bullet.y
if bullet.y > grid.h
bullet.dead = true
+ state.score -= 1
end
if bullet.solid.intersect_rect?(enemy_rect)
bullet.dead = true
+ state.score += 2
end
end
state.bullets = state.bullets.reject(&:dead)
end
def output
outputs.solids << Solid.new(player_rect)
outputs.solids << Solid.new(enemy_rect.merge(r: 150, g: 150, b: 150))
outputs.solids << state.bullets.map(&:solid)
+
+ outputs.labels << Label.new(
+ x: grid.w * 0.99,
+ y: grid.h * 0.98,
+ text: state.score,
+ alignment_enum: 2,
+ font: 'fonts/Press_Start_2P/PressStart2P-Regular.ttf'
+ )
outputs.lines << Line.new(x: 0, y: grid.center_y, x2: grid.w, y2: grid.center_y)
outputs.lines << Line.new(x: grid.center_x, y: 0, x2: grid.center_x, y2: grid.h)
end
Jetzt, wo ich eine Punktzahl habe, kann ich (vorerst) spielen.
Ich bin einsam, wenn es quadratisch bleibt, also werde ich ein Bild verwenden. (Das Bild ist das, das ich zuvor gezeichnet habe, also ist die Qualität, dass ...)
Platziere player.png
, feind.png
und bull.png
in mygame / sprites
.
Ändern Sie danach den Code, um "Sprite" anstelle von "Solid" zu verwenden. Ich brauche die Querlinie nicht mehr, also werde ich sie löschen.
mygame/app/primitives.rb
class Sprite < Primitive
@@attr_keys = %i[
x y w h path angle a r g b
source_x source_y source_w source_h
flip_horizontally flip_vertically
angle_anchor_x angle_anchor_y
tile_x tile_y tile_w tile_h
]
attr_accessor(*@@attr_keys)
end
mygame/app/main.rb
def handle_inputs
if inputs.keyboard.right
state.player_dx = 5
elsif inputs.keyboard.left
state.player_dx = -5
else
state.player_dx = 0
end
if inputs.keyboard.key_up.space
state.bullets << state.new_entity(:bullet) do |bullet|
bullet.y = player_rect[:y]
bullet.x = player_rect[:x] + 16
bullet.size = 32
bullet.dy = 10
- bullet.solid = { x: bullet.x, y: bullet.y, w: bullet.size, h: bullet.size, r: 255, g: 100, b: 100 }
+ bullet.sprite = { x: bullet.x, y: bullet.y, w: bullet.size, h: bullet.size, r: 255, g: 100, b: 100, path: 'sprites/bullet.png' }
end
end
end
def update_state
state.player_x += state.player_dx
state.enemy_x += state.enemy_dx
if state.enemy_x < 0 || state.enemy_x > grid.w - 64
state.enemy_dx *= -1
end
state.bullets.each do |bullet|
bullet.y += bullet.dy
- bullet.solid[:y] = bullet.y
+ bullet.sprite[:y] = bullet.y
if bullet.y > grid.h
bullet.dead = true
state.score -= 1
end
- if bullet.solid.intersect_rect?(enemy_rect)
+ if bullet.sprite.intersect_rect?(enemy_rect)
bullet.dead = true
state.score += 2
end
end
state.bullets = state.bullets.reject(&:dead)
end
def output
- outputs.solids << Solid.new(player_rect)
+ outputs.sprites << Sprite.new(player_rect.merge(path: 'sprites/player.png'))
- outputs.solids << Solid.new(enemy_rect.merge(r: 150, g: 150, b: 150))
+ outputs.sprites << Sprite.new(enemy_rect.merge(r: 150, g: 150, b: 150, path: 'sprites/enemy.png'))
- outputs.solids << state.bullets.map(&:solid)
+ outputs.sprites << state.bullets.map(&:sprite)
outputs.labels << Label.new(
x: grid.w * 0.99,
y: grid.h * 0.98,
text: state.score,
alignment_enum: 2,
font: 'fonts/Press_Start_2P/PressStart2P-Regular.ttf'
)
- outputs.lines << Line.new(x: 0, y: grid.center_y, x2: grid.w, y2: grid.center_y)
- outputs.lines << Line.new(x: grid.center_x, y: 0, x2: grid.center_x, y2: grid.h)
end
Im Vergleich zum Anfang sieht es sehr ähnlich aus!
Bereiten Sie die Metadaten vor.
Kopieren Sie als Symbol player.png
.
mygame/metadata/game_metadata.txt
devid=hello-dragonruby-gtk
devtitle=Hello DragonRuby GTK
gameid=hello-dragonruby-gtk
gametitle=Hello DragonRuby GTK
version=0.1
icon=metadata/icon.png
Ich habe Dragonruby-Publish kopiert, aber es hat aus irgendeinem Grund nicht funktioniert Tun Sie dies in dem Verzeichnis, in das Sie DragonRuby heruntergeladen und entpackt haben. (Informationen zum Kopieren und Verschieben finden Sie im folgenden Postskriptum.)
$ cp mygame/sprites/player.png mygame/metadata/icon.png
$ cp -r mygame/ ~/Downloads/dragonruby-macos/hello-dragonruby-gtk
$ cd ~/Downloads/dragonruby-macos
$ ./dragonruby-publish --only-package hello-dragonruby-gtk
Dadurch wird die HTML5-Version zusammen mit den Dateien für andere Plattformen ausgegeben.
(builds/hello-dragonruby-gtk-html5-0.1
)
Wenn Sie dies veröffentlichen, können Sie es in Ihrem Browser abspielen. Da es eine große Sache ist, habe ich es auf GitHub Pages gestellt.
https://tnantoka.github.io/hello-dragonruby-gtk/
Es hat funktioniert, als ich verschiedene andere Dinge als "Dragonruby-Publish" kopiert habe.
$ cp ~/Downloads/dragonruby-macos/dragonruby-publish .
$ cp ~/Downloads/dragonruby-macos/.dragonruby .
$ cp ~/Downloads/dragonruby-macos/*.png .
$ cp ~/Downloads/dragonruby-macos/open-source-licenses.txt .
$ ./dragonruby-publish --only-package
```
Es gibt noch mehr Dinge zu tun ".gitignore".
#### **`.gitignore`**
```python
# DragonRuby
/dragonruby*
/font.ttf
/logs
/tmp
/exceptions
/console_history.txt
/.dragonruby
/builds
/console-logo.png
/open-source-licenses.txt
```
# Quellcode
Es wird unten veröffentlicht.
(DragonRuby wird separat benötigt)
https://github.com/tnantoka/hello-dragonruby-gtk/
# Impressionen
Ich konnte ohne große Sucht spielen.
Kann es in der Produktion verwendet werden? Ich weiß nicht was es ist, aber
Es schien brauchbar genug zu sein, um ein kleines Ding zu machen.
Ich wollte mit Ruby kreativ codieren, was ich gewohnt bin zu schreiben. Kann ich es also als Werkzeug verwenden? Ich denke, dass.
(Zu diesem Zweck möchte ich, dass Sie eine physische Engine installieren und das Zeichnen verbessern.)
Ich werde versuchen, Zeit zu finden und sie erneut zu berühren.
# Verweise
Es gibt keine API-Referenz (?), Also habe ich mich umgesehen, während ich mich umgesehen habe.
- README.md
――Lesen Sie zuerst hier
- CHEATSHEET.md
――Lesen Sie das auch
- [DragonRuby Game Toolkit by DragonRuby](https://dragonruby.itch.io/dragonruby-gtk)
- Es gibt eine Beschreibung wie Entity, die nicht in README enthalten ist
- mygame/documantion
- Solid, Sprite usw. erklären jedes Element so wie es ist
- samples
- Es gibt 67 Muster (MIT-Lizenz!)
Recommended Posts