Mapping ve Hammer

Hammer'da input ve output: bir butonu kapıya bağlamak

Hammer'da input ve output'lar: Outputs sekmesinin alanları, buton ve kapı örneği, !activator, logic_relay ve ent_fire ile hata ayıklama.

Hammer'da entity'leri output'lar ve input'lar üzerinden birbirine bağlarsın: bir entity'nin output'u başka bir entity'nin input'unu tetikler ve hedef, adına (targetname) göre bulunur. Kapı açan bir buton için kapıya bir ad verirsin ve func_button entity'sine, kapının Open input'uyla birlikte OnPressed output'unu eklersin. Böyle bir bağlantı çoğunlukla yanlış yazılmış ya da iki kez kullanılmış bir ad, kaldırılmış bir hedef ya da aynı anda ulaşan iki output yüzünden bozulur.

Output'lar ve input'lar birlikte nasıl çalışır

Output, bir entity'nin bildirdiği bir olaydır: bir butona basıldı, bir kapı tamamen açıldı, biri bir trigger'a girdi. Input ise bir entity'nin kabul ettiği bir komuttur; örneğin Open, Close ya da Kill. Bir sınıfın hangi output'lara ve input'lara sahip olduğu FGD'de tanımlıdır.

Tetiklenen her output, motorun içindeki bir olay kuyruğuna yerleştirilir ve ayarladığın gecikmeden sonra teslim edilir. Motor hedefi ada göre ancak o anda arar. Yanında iki bilgi taşınır: activator, yani çoğunlukla zinciri başlatan entity (butonda oyuncu), ve caller, yani output'u tetiklenmekte olan entity.

Adı, Object Properties penceresindeki (Alt+Enter) Name alanında verirsin. Adı olmayan bir entity output gönderebilir, ama hedef olarak ona yalnızca classname'i ya da !activator gibi özel bir hedef üzerinden ulaşılabilir. Editörün temelleri Hammer Editor'e başlangıç yazısında anlatılıyor.

Outputs sekmesinin alanları

Object Properties penceresinin Outputs sekmesinde Add... ile bir bağlantı oluşturursun. GMod ile gelen Hammer'da düzenleme alanları ile listedeki sütunlar biraz farklı adlandırılmıştır:

AlanSütunAnlamı
My output namedMy OutputBu entity'nin, bağlantıyı tetikleyen olayı
Targets entities namedTarget EntityHedefin adı; alternatif olarak classname, wildcard ya da özel hedef
Via this inputTarget InputHedefin yerine getirdiği komut
With a parameter override ofParameterInput bir değer bekliyorsa o değer
After a delay in seconds ofDelayOlay ile teslim arasındaki bekleme süresi
Fire once onlyOnceBağlantı bir kez tetiklendikten sonra silinir

Hammer++, onay kutusunun yerine Limit to this many fires ( -1 = infinite ) alanını ve "Refires" sütununu koyar. Inputs sekmesi ters yönü, yani bu entity'yi gösteren tüm bağlantıları gösterir. Mark diğer uca atlar.

Örnek: bir buton kapıyı açar ve yeniden kapatır

  1. Kapıyı brush olarak yap, Ctrl+T tuşlarına bas ve func_door seç. Adını door_1 koy.
  2. Move Direction (Pitch Yaw Roll) değerini açılma yönüne, Delay Before Reset (-1 stay) değerini -1 olarak ayarla. Kapı o zaman açık kalır.
  3. Flags sekmesinde Touch Opens işaretini kaldır. Varsayılan olarak işaretlidir ve kapıyı dokunulduğunda açardı.
  4. Butonu brush olarak yap ve func_button entity'sine çevir. Use Activates flag'i zaten ayarlıdır. Delay Before Reset (-1 stay) değeri 5 olduğunda butona en az beş saniye boyunca yeniden basılamaz.
  5. Butonun Outputs sekmesinde iki bağlantı ekle:
My Output   Target Entity   Target Input   Parameter   Delay
OnPressed   door_1          Open                       0.00
OnPressed   door_1          Close                      5.00

Kapı hemen açılır ve basıştan beş saniye sonra kapanır. İkinci bağlantı olmadan da olur: Delay Before Reset değeri 5 olan bir kapı kendiliğinden kapanır. Aynı düzenle bir asansörün nasıl çağrıldığı asansörler ve trenler yazısında anlatılıyor.

Özel hedefler ve mantık yapı taşları

Hedef alanında ad yerine özel bir hedef de bulunabilir:

HedefAnlamı
!activatorZinciri başlatan entity, örneğin butondaki oyuncu
!callerOutput'u tetiklenmekte olan entity
!selfHedef olarak !caller ile aynıdır, parametre olarak ise input'u alan entity'dir
!playerOyuncu; çok oyunculu modda sunucuya ilk katılan oyuncu
!pickerNişangâhın altındaki entity; hata ayıklama için düşünülmüştür

Bu yüzden bir sunucuda !player neredeyse hiçbir zaman doğru değildir. Zinciri tetikleyen oyuncu için !activator, herkes için ise player classname'ini kullan. Wildcard'lar yalnızca sonda çalışır: door_*, door_ ile başlayan her adla eşleşir. *_door gibi bir kalıp çalışmaz, çünkü motor * işaretinden sonraki her şeyi yok sayar. func_door gibi bir classname de geçerli bir hedeftir; yeter ki tam olarak bu metni ad olarak taşıyan bir entity olmasın.

Birkaç mantık entity'si bunu daha büyük devrelere dönüştürür:

  • logic_relay birden çok output'u tek bir ad altında toplar: input Trigger, output OnTrigger. Disable zinciri keser, CancelPending relay'in hâlâ bekleyen olaylarını iptal eder. Allow fast retrigger flag'i ayarlı değilse, gecikmeli output'lar beklerken yeniden tetiklenemez.
  • logic_timer, Refire Interval değerinin temposunda OnTimer tetikler.
  • math_counter, Add ve Subtract ile sayar ve bir sınıra ulaşıldığında OnHitMax ya da OnHitMin tetikler.
  • trigger_multiple; OnStartTouch, OnEndTouch ve OnTrigger içeren bir hacimdir. Onu kimin tetikleyebileceğini flag'ler ve bir filter_activator_name ya da filter_activator_class ile birlikte Filter Name belirler.

Oyunda hata ayıklama

Derlemeden önce Map > Check for Problems (Alt+P), geçersiz bağlantıları olan entity'leri listeler. Oyunda şu konsol komutları işe yarar:

developer 2
ent_messages_draw 1
ent_fire door_1 Open
ent_fire !picker Kill
  • developer 2, her output'u ve her input'u konsola yazar. dumpeventqueue, gecikmesinin dolmasını hâlâ bekleyen olayları listeler.
  • ent_messages_draw 1, aynı mesajları 3D dünyada entity'lerin üzerinde gösterir.
  • ent_fire <target> <input> [parameter] [delay], bir input'u elle tetikler. Böylece hedefi, onu tetikleyen şeyden bağımsız olarak test edebilirsin.

Tek oyunculu modda ya da host olarak test et, çünkü Valve wiki'sine göre bir sunucuya bağlı olan client ent_fire kullanamaz. Konsol cheat isterse önce sv_cheats 1 yaz. developer 2 ile konsol satırları aşağıdaki kalıbı izler. Blok, GMod'un server.dll dosyasındaki mesaj biçimlerinden, örnekteki adlarla ve uydurma bir zamanla bir araya getirilmiştir. Gerçek bir oturumun kaydı değildir:

(12.50) output: (func_button,button_1) -> (door_1,Open)()
(12.50) input button_1: door_1.Open()
unhandled input: (Open) -> (door_2), from (func_button,button_1); target entity not found

İlk satır tetiklenen output, ikincisi onun teslimidir. Asıl bakman gereken üçüncüsüdür: teslim anında hiçbir entity hedef adını taşımıyorsa görünür; bu örnekte hedef adı door_2.

Tipik hatalar

  • Ad eksik ya da yanlış yazılmış: Hammer hedefi kırmızı gösterir ve "Check for Problems" bağlantıyı bildirir. Orada "Fix" seçeneğini körü körüne kullanma: hata metnine göre Hammer hatalı bağlantıları onarmak yerine siler. Wildcard'lar ve classname'ler de oyunda çalıştıkları hâlde kırmızı görünür.
  • Ad iki kez kullanılmış: Hammer hedefi kalın gösterir. Input, bu ada sahip her entity'ye gider. Bu, iki kapı kanadı için istenen bir şeydir; yan odadaki kopyalanmış bir kapı için değil.
  • Hedef kaldırılmış: Kill, bir entity'yi parent hiyerarşisindeki çocuklarıyla birlikte siler. Sonrasında ulaşan gecikmeli output'lar boşa gider ve kaldırılan entity yeni output tetiklemez. Oyuncu sunucudan daha önce ayrılırsa aynısı !activator için de olur.
  • Zamanlama yarışları: Aynı gecikmeye sahip iki output aynı tick'te ulaşır. Sıralarına güvenme. B, A'ya bağlıysa B'ye küçük bir gecikme ver. Valve wiki'si böyle bir durumda en az 0,02 saniye kullanır.

Output'lar bir lua_run entity'sini de tetikleyebilir; o da Lua kodu çalıştırır. Map Scanner, bir BSP'deki bu tür riskli entity'leri bulur. Başka kontroller yayın öncesi BSP kontrolü yazısında sıralanıyor.

Sık sorulan sorular

Bir output aynı anda birden çok entity'ye gidebilir mi?

Evet. Input, hedefin eşleştiği her entity'ye gider: ortak bir ad, door_* gibi bir wildcard ya da bir classname.

func_button'da OnPressed ile OnIn arasındaki fark nedir?

OnPressed, butona basılır basılmaz tetiklenir. OnIn ancak buton basılı son konumuna ulaştığında, OnOut ise başlangıç konumuna döndüğünde tetiklenir.

Oyun çalışırken output'ları değiştirebilir miyim?

Evet, AddOutput input'uyla. Biçimi şöyledir: <output> <target>:<input>:<parameter>:<delay>:<max times to fire>. FGD bunu "very dangerous, use with care" diye niteler ve oyun içinde kendi kendini yeniden bağlayan devreleri sonradan takip etmek zordur.