Andy Maleh
Posted on August 7, 2021
Glimmer DSL for SWT 4.20.13.15 just shipped with Glimmer Battleship.
Mid-game battle
Placing ships on grid using drag and drop
All ships placed. Ready for battle.
Finished game, beating the enemy.
Game over message box dialog.
You may check out the code over here.
# From: https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/docs/reference/GLIMMER_SAMPLES.md#battleship
require 'glimmer-dsl-swt'
require 'facets/string/titlecase'
require 'facets/string/underscore'
require_relative 'battleship/model/game'
require_relative 'battleship/view/grid'
require_relative 'battleship/view/ship_collection'
require_relative 'battleship/view/action_panel'
class Battleship
include Glimmer::UI::CustomShell
COLOR_WATER = rgb(156, 211, 219)
COLOR_SHIP = :dark_gray
before_body do
@game = Model::Game.new
end
after_body do
observe(@game, :over) do |game_over_value|
if game_over_value
game_over_message = if game_over_value == :you
"Game over!\nYou Won!"
else
"Game over!\nYou Lost!"
end
message_box {
text 'Game Over!'
message game_over_message
}.open
end
end
end
body {
shell(:no_resize) {
grid_layout(2, false) {
horizontal_spacing 15
vertical_spacing 15
}
text 'Glimmer Battleship'
@enemy_grid = grid(game: @game, player: :enemy)
@enemy_ship_collection = ship_collection(game: @game, player: :enemy)
@player_grid = grid(game: @game, player: :you)
@player_ship_collection = ship_collection(game: @game, player: :you)
action_panel(game: @game)
}
}
end
Battleship.launch
# From: https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/docs/reference/GLIMMER_SAMPLES.md#battleship
require_relative '../model/grid'
require_relative 'cell'
class Battleship
module View
class Grid
include Glimmer::UI::CustomWidget
options :game, :player
body {
composite {
grid_layout(Model::Grid::WIDTH + 1, true) {
margin_width 0
margin_height 0
horizontal_spacing 0
vertical_spacing 0
}
label(:center) {
layout_data(:fill, :center, true, false) {
horizontal_span (Model::Grid::WIDTH + 1)
}
text player.to_s.capitalize
font height: 20, style: :bold
}
label # filler
Model::Grid::WIDTH.times do |column_index|
label {
text (column_index + 1).to_s
font height: 16
}
end
Model::Grid::HEIGHT.times do |row_index|
label {
text Model::Grid::ROW_ALPHABETS[row_index]
font height: 16
}
Model::Grid::WIDTH.times do |column_index|
cell(game: game, player: player, row_index: row_index, column_index: column_index) {
layout_data {
width_hint 25
height_hint 25
}
}
end
end
}
}
end
end
end
# From: https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/docs/reference/GLIMMER_SAMPLES.md#battleship
class Battleship
module View
class Cell
include Glimmer::UI::CustomWidget
class << self
attr_accessor :dragging
alias dragging? dragging
end
COLOR_WATER = rgb(156, 211, 219)
COLOR_SHIP = :gray
COLOR_PLACED = :white
COLOR_EMPTY = :black
COLOR_NO_HIT = :white
COLOR_HIT = :red
options :game, :player, :row_index, :column_index, :ship
option :type, default: :grid # other type is :ship
body {
canvas {
if type == :grid
if player == :you
background <= [model, :ship, on_read: ->(s) {s ? COLOR_SHIP : COLOR_WATER}]
else
background COLOR_WATER
end
else
background <= [ship, :sunk, on_read: ->(s) {s ? COLOR_HIT : COLOR_PLACED}]
background <= [ship, :top_left_cell, on_read: ->(c) {c ? COLOR_PLACED : COLOR_SHIP}]
end
rectangle(0, 0, [:max, -1], [:max, -1])
oval(:default, :default, 10, 10) {
foreground <= [model, :hit, on_read: ->(h) {h == nil ? COLOR_EMPTY : (h ? COLOR_HIT : COLOR_NO_HIT)}]
}
oval(:default, :default, 5, 5) {
background <= [model, :hit, on_read: ->(h) {h == nil ? COLOR_EMPTY : (h ? COLOR_HIT : COLOR_NO_HIT)}]
}
on_mouse_move do |event|
if game.started?
if type == :grid
if player == :enemy
body_root.cursor = :cross
else
body_root.cursor = :arrow
end
else
body_root.cursor = :arrow
end
end
end
if player == :enemy
on_mouse_up do
game.attack!(row_index, column_index)
end
end
if player == :you
on_drag_detected do |event|
unless game.started? || game.over?
Cell.dragging = true
body_root.cursor = :hand if type == :grid
end
end
on_drag_set_data do |event|
the_ship = ship || model&.ship
if the_ship && !game.started? && !game.over? && !(type == :ship && the_ship.top_left_cell)
event.data = the_ship.name.to_s
else
event.doit = false
Cell.dragging = false
end
end
on_mouse_up do
unless game.started? || game.over?
Cell.dragging = false
change_cursor
end
end
if type == :grid
on_mouse_move do |event|
unless game.started? || game.over?
change_cursor
end
end
on_mouse_hover do |event|
unless game.started? || game.over?
change_cursor
end
end
on_mouse_up do |event|
unless game.started? || game.over?
begin
model.ship&.toggle_orientation!
rescue => e
Glimmer::Config.logger.debug e.full_message
end
change_cursor
end
end
on_drop do |event|
unless game.started? || game.over?
ship_name = event.data
place_ship(ship_name.to_s.to_sym) if ship_name
Cell.dragging = false
change_cursor
end
end
end
end
}
}
def model
game.grids[player].cell_rows[row_index][column_index] if type == :grid
end
def place_ship(ship_name)
ship = game.ship_collections[player].ships[ship_name]
model.place_ship!(ship)
end
def change_cursor
if type == :grid && model.ship && !Cell.dragging?
body_root.cursor = model.ship.orientation == :horizontal ? :sizens : :sizewe
elsif !Cell.dragging?
body_root.cursor = :arrow
end
end
end
end
end
# From: https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/docs/reference/GLIMMER_SAMPLES.md#battleship
require_relative '../model/game'
require_relative '../model/ship_collection'
require_relative 'ship'
class Battleship
module View
class ShipCollection
include Glimmer::UI::CustomWidget
options :game, :player
body {
composite {
row_layout(:vertical) {
fill true
margin_width 0
margin_height 0
}
Model::ShipCollection::BATTLESHIPS.each do |ship_name, ship_length|
ship(game: game, player: player, ship_name: ship_name, ship_length: ship_length)
end
}
}
end
end
end
# From: https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/docs/reference/GLIMMER_SAMPLES.md#battleship
require_relative 'cell'
class Battleship
module View
class Ship
include Glimmer::UI::CustomWidget
options :game, :player, :ship_name, :ship_length
body {
composite {
row_layout(:vertical) {
fill true
margin_width 0
margin_height 0
}
label {
text ship_name.to_s.titlecase
font height: 16
}
composite {
grid_layout(ship_length, true) {
margin_width 0
margin_height 0
horizontal_spacing 0
vertical_spacing 0
}
ship_length.times do |column_index|
cell(game: game, player: player, type: :ship, column_index: column_index, ship: game.ship_collections[player].ships[ship_name]) {
layout_data {
width_hint 25
height_hint 25
}
}
end
}
}
}
end
end
end
# From: https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/docs/reference/GLIMMER_SAMPLES.md#battleship
class Battleship
module View
class ActionPanel
include Glimmer::UI::CustomWidget
options :game
body {
composite {
row_layout(:horizontal) {
margin_width 0
margin_height 0
}
layout_data(:center, :center, true, false)
@battle_button = button {
text 'Battle!'
enabled <= [game.ship_collections[:you], :placed_count, on_read: ->(c) {c == 5}]
on_widget_selected do
game.battle!
@battle_button.enabled = false
end
}
button {
text 'Restart'
on_widget_selected do
game.reset!
end
}
}
}
end
end
end
This is another reminder that Glimmer DSL for SWT lets you build apps that normally take months and years in just days and weeks.
Happy Glimmering!
💖 💪 🙅 🚩
Andy Maleh
Posted on August 7, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
ruby Glimmer DSL for SWT Table Cell Data-Binding of Background/Foreground/Font/Image
September 2, 2022