EN /HU | Belépés

Rajzok és grafikus képernyők

Egy képekre épülő board darabjai, mint a Teletype BBS TTG Klubház külseje: olvasható YAML-ben tartott rajzok, a modern arcon 256 színű ANSI-val, a Commodore 64-arcon nyers PETSCII-vel rajzolva; kurzoros menü a C64-es képen; widgetek, amelyek hotspotjai a board életét mutatják; és a napszak meg az évszak a kép rétegeinek kiválasztásához. A 0.30.0 óta érhető el; minden osztály benne van az API-referenciában.

Darab Mit csinál
BBS::Petscii::Canvas A C64 képernyője 40×25 cellaként a nagybetűs/grafikus készletben, nyers PETSCII-ként ki: egy teljes kép, aztán foltok
BBS::Art YAML-rajz: karakterek, színek, reverse, hátterek, hotspotok, rétegek; ki ANSI-ra, FrameBufferre vagy Canvasra
BBS::Petscii::CanvasMenu A BBS::Selector billentyűi és elemei Canvasra rajzolva
BBS::Widgets::Scene Egy Art widgetként a modern arcon, a hotspotjai adatból kitöltve
BBS::Season Hajnal, nappal, alkony vagy éjjel a nap szerint; hó, tök, tűzijáték, zászlófüzér
art-preview Ellenőrzi és megmutatja a rajzot: ANSI, PETSCII-bájtok, C64-képernyőkép

A C64-vászon

A C64-nek két karakterkészlete van. A kisbetűsben, amelyet a session.petscii! és a BBS::Petscii::Screen beszél, mindkét betűméret megvan, de grafika nincs. A nagybetűsben vannak a kártyaszínek, golyók, lekerekített sarkok, átlók és negyedblokkok, ezért a kép ott készül. A BBS::Petscii::Canvas cellákként tartja a képernyőt és nyers PETSCII-t ír, amely a session.write_raw-val megy ki, a kisbetűs enkóder mellett:

RUBY
C = BBS::Petscii::Canvas
canvas = C.new
canvas.text(0, 1, 'TTG CLUBHOUSE', :yellow)
canvas.text(2, 1, '╭──╮', :light_blue)
canvas.text(3, 1, '█▀▀█', :orange)                 # reversed glyphs work too
session.write_raw(canvas.frame)                    # the whole screen

before = canvas.dup
canvas.text(2, 2, '●', :red)
session.write_raw(canvas.update(before))           # a patch: only the cell that changed
  • A cellák Unicode-ból rajzolódnak: a betűk (nagybetűként), számjegyek és jelek úgy, ahogy vannak, a grafika aszerint, aminek látszik (Canvas::GLYPHS); a █ ▀ ▐ ◢ ◣ fordított kódok (GLYPHS_REVERSED). A Canvas.glyph?(ch) megmondja, meg tudja-e mutatni a készlet a karaktert.
  • A színek kódok (Canvas::YELLOW), nevek (:light_blue, 'dark grey'), vagy az 1.0.0 óta a paletta színei is: Canvas.color(YE) == Canvas::YELLOW, így ugyanazok a BBS::Petscii::Colors konstansok szolgálnak ki egy Screent és egy vásznat.
  • Az 1.0.0 óta egyetlen PETSCII-jeltábla van: a lekerekített sarkok (╭╮╰╯) ebben a nagybetűs készletben a Petscii::ROUNDED_CORNERS, és a negyedblokkokat (▖▗▘▝▚) is megrajzolja; egy Screen kisbetűs készlete a sarkokat szögletesen mutatja.
  • A frame egyszer küldi el a képernyőt, minden sort az utolsó látható cellája után vágva; a span(row, col, width) egy sor egy szakaszát; a patch(positions) szétszórt cellákat, a kurzor a legközelebbihez lépve; az update(before) a folt és a teljes kép közül az olcsóbbat. Lassú vonalon cél: kb. 1,2 KB egy képernyő, 200 bájt alatt egy animációs lépés.
  • A feed(bytes) úgy játssza rá a PETSCII-t a vászonra, ahogy a C64 képernyőszerkesztője kiírja: tesztben az, amit a hívó lát a bájtjaid után (a canvas.changes(seen) üres, ha egyeznek).

A vászon a TTG Gate BBS-ből jött; a bájtjai ugyanazok, mint a gate saját osztályáéi voltak.

Rajzok YAML-ben

A rajz szöveg, kódként írjuk és nézzük át. A chars a kép, a colors cellánként egy palettabetű (. = nincs szín), a reverse opcionális R-ek, a background opcionális (csak cp437: a félblokk második színe), a hotspots a cellák, amelyeket a board az adataiból tölt ki, a layers a ráhelyezhető további fájlok. Minden sor pontosan size[0] széles, a sorvégi szóközökkel együtt. A rácsokat |2-vel írd: behúzásjelző nélkül a YAML az első sorból veszi a behúzást, és a szóközzel kezdődő sor szétveri a blokkot.

PETSCII-rajz a C64-arcra:

YAML
# art/house.yml
size: [20, 6]
charset: petscii-upper     # only glyphs the uppercase set shows
palette:                   # C64 colour names, 256-colour indexes or '#rrggbb'
  y: yellow
  r: red
  b: brown
  g: dark grey
  w: white
chars: |2
       ◢████◣    ●    
      ◢██████◣        
      │ ▒  ▒ │        
      │ ▒  █ │  TTG   
  ▁▁▁▁│▁▁▁▁█▁│▁▁▁▁▁▁▁ 

colors: |2
  .....rrrrrr....y....
  ....rrrrrrrr........
  ....b.y..y.b........
  ....b.y..b.b..www...
  ggggbggggbgbggggggg.
  ....................
hotspots:
  window_1: [6, 2]         # [col, row], 0-based
  window_2: [9, 2]
  sign: [14, 3, 3, 1]      # [col, row, width, height]
layers: [snow]             # art/snow.yml

Egy réteg: a szóköz átlátszó, az at helyezi el, a palettája és a hotspotjai hozzáadódnak a rajzéhoz.

YAML
# art/snow.yml: a layer; spaces are transparent, 'at' places it
size: [10, 1]
at: [4, 0]
palette:
  w: white
chars: |2
   ▄▄▄▄▄▄   
colors: |2
  .wwwwww...

cp437-rajz a modern arcra, hátterekkel:

YAML
size: [24, 4]
charset: cp437
palette: { y: yellow, o: 208, n: '#203060', w: white }
chars: |2
  ╔══════════════════════╗
  ║ ▄▀▀▄ TTG CLUBHOUSE ☼ ║
  ║ ▀▄▄▀  open tonight   ║
  ╚══════════════════════╝
colors: |2
  oooooooooooooooooooooooo
  oyyyyywwwwwwwwwwwwwwwyyo
  oyyyyyyyyyyyyyyyyyyyyyyo
  oooooooooooooooooooooooo
background: |2
  ........................
  .nnnnnnnnnnnnnnnnnnnnnn.
  .nnnnnnnnnnnnnnnnnnnnnn.
  ........................
hotspots:
  tonight: [8, 2, 13, 1]

Használat:

RUBY
house = BBS::Art.load('art/house.yml').with(*BBS::Season.now.layers)  # only the layers it lists
session.write(house.ansi)                        # modern: 256-colour ANSI lines
house.draw(frame, x: 1, y: 2)                    # … or into a BBS::FrameBuffer
session.write_raw(house.petscii)                 # C64: a whole frame
house.draw_canvas(canvas, row: 1, col: 10)       # … or onto a canvas
house.hotspot(:window_1)                         # => Art::Hotspot col=6 row=2 …

A with csak a fájlban felsorolt rétegeket rakja rá, így a with(*season.layers) bármely rajznál biztonságos. A hiba BBS::Art::Error-t dob a fájl, a rács, a sor és az oszlop nevével: rossz szélességű sor, a palettában nem szereplő betű, a karakterkészletben nem megjeleníthető jel, a rajzon kívüli hotspot. A palettaszínek C64-nevek, 256-os indexek vagy #rrggbb; mindegyikhez a másik arc legközelebbi színe tartozik, így a PETSCII-rajz ANSI-ban is megnézhető, és fordítva.

Kurzoros menü a vásznon

A BBS::Petscii::CanvasMenu egy vászonra rajzoló BBS::Selector: ugyanazok az elemek, billentyűk és opciók (CRSR, RETURN, az elem betűje, RUN/STOP vagy ← vissza, számok, oszlopok, lapok, az about- és a hint-sor), a kiválasztott elem fordított sáv a saját színében. Minden lépés a megváltozott cellák foltjaként megy ki: egy 16 elemes, kétoszlopos menüben kb. 140 bájt.

RUBY
S = BBS::Selector
items = [S.item('CORK BOARD', key: 'm', value: :boards, color: :light_blue, about: 'READ AND POST'),
         S.item('GAMES ROOM', key: 'r', value: :doors, color: :orange),
         S.item('LEAVE',      key: 'q', value: :quit)]
menu = BBS::Petscii::CanvasMenu.new(session, items, canvas: canvas, row: 12, col: 1, width: 36,
                                    columns: 2, hint: 'CRSR: CHOOSE  RETURN: OPEN', idle: 0.5) do
  smoke.step(canvas)                 # bytes for an animation step while the caller thinks
end
menu.paint
session.write_raw(canvas.frame)      # the picture with the menu on it
choice = menu.run(drawn: true)       # without drawn: it paints and sends its rows itself

Az idle: másodperccel és egy blokkal a blokk akkor fut, amíg a hívó gondolkodik, és egy animációs lépés bájtjait adja vissza; egy leütés azonnal véget vet a várakozásnak.

A menü színszerepei a Selectoréi, a BBS::Selector::COLORS (text key bar heading about hint), amelyeket a vásznon C64-kódokká alakít; a colors: ezek közül írhat felül néhányat. (A CanvasMenu::COLORS az 1.0.0-ban megszűnt.)

Jelenetek a modern arcon

A BBS::Widgets::Scene egy rajz widgetként: a rajz, majd minden hotspot a blokkjával kitöltve minden renderkor. A blokk Stringet ad (ANSI-színekkel, magasabb hotspotnál sorokkal) vagy nil-t, ha marad a rajz; amit visszaad, a hotspotjára vágódik.

RUBY
scene = BBS::Widgets::Scene.new(art: house, align: :center)
scene.fill(:window_1) { node_busy?(1) ? "\e[38;5;220m▓" : nil }
scene.fill(:sign)     { |spot| "\e[1;37m#{inside_count}".ljust(spot.width) }

A rajznál kisebb terminálon a jelenet a határaira vágódik; crop: false-szal semmit sem rajzol, és a fits? megmondja egy dashboardnak, mutassa-e egyáltalán a képet.

Napszak és évszak

A BBS::Season.now(tz: 'Europe/Budapest', at: Time.now, jam: nil) megadja a napszakot a nap állása szerint (a :dawn és a :dusk a napkelte és napnyugta körüli 45-45 perc, a latitude: és longitude: helyre számolva, alapból Budapest), az évszakot és az érvényes rétegeket:

Réteg Mikor
:snow decembertől februárig
:pumpkin október 24–31.
:fireworks december 31., és újév napján 6:00-ig
:bunting a jam: napjain (Date-ek Range-e)
RUBY
s = BBS::Season.now(jam: Date.new(2027, 1, 8)..Date.new(2027, 1, 10))
s.time_of_day          # => :night
s.layers               # => [:snow]
art = BBS::Art.load("art/house_#{s.night? ? 'night' : 'day'}.yml").with(*s.layers)

Tiszta függvény: a teszt átadja az at:-et. Az EU-s időzónák és a fix eltolások ('+01:00') más gem nélkül működnek; más IANA-névhez a tzinfo kell.

art-preview

A gem futtatható programja (bundle exec art-preview, vagy rubbs-checkoutban bin/art-preview) a rajz ellenőrzésére rajzolás közben:

TXT
art-preview art/house.yml                   # ANSI here, then size, palette, hotspots, PETSCII bytes
art-preview art/house.yml -l snow -s        # a layer stacked, the hotspots marked
art-preview art/house.yml --hex             # the PETSCII frame as a hex dump
art-preview art/house.yml --petscii h.seq   # the raw frame, e.g. for a C64 terminal program
art-preview art/house.yml --png h.png       # a C64 screenshot of the frame (VICE's character ROM)

A --png a PETSCII-képet egy vászonra játssza, és a VICE által telepített C64-karakter-ROM-mal rajzolja ki (más ROM: --chargen FILE vagy $C64_CHARGEN); a ROM nem része a gemnek. Az emulátoron belüli ellenőrzéshez töltsd be a --petscii fájlt egy C64-es terminálprogramba, vagy nézd a boardot VICE-ban.