XNA aramayı durdurur Update
ve Draw
oyun penceresi yeniden boyutlandırılırken veya taşınırken.
Neden? Bu davranışı önlemenin bir yolu var mı?
(Ağ mesajlarının pompalanmaması nedeniyle ağ kodumun senkronize olmamasına neden oluyor.)
XNA aramayı durdurur Update
ve Draw
oyun penceresi yeniden boyutlandırılırken veya taşınırken.
Neden? Bu davranışı önlemenin bir yolu var mı?
(Ağ mesajlarının pompalanmaması nedeniyle ağ kodumun senkronize olmamasına neden oluyor.)
Yanıtlar:
Evet. XNA'nın iç kısımları ile az miktarda karışıklık içerir. Bu videonun ikinci yarısında bir düzeltme gösterdim .
Arka fon:
Bunun nedeni, XNA'nın Game
altında yatan Form
boyut yeniden boyutlandırıldığında (veya taşındığında, olaylar aynı olduğunda) oyun saatini askıya almasıdır . Bu da oyun döngüsünü harekete geçirmesidir Application.Idle
. Bir pencere yeniden boyutlandırıldığında, Windows, ateş etmeyi önleyen çılgın win32 mesaj döngüsü öğelerini yaparIdle
.
Yani, Game
saatini askıya almadıysa, bir yeniden boyutlandırmadan sonra, tek bir patlamada güncellemesi gereken muazzam bir süre birikmiş olacak - açıkça istenmiyor.
Nasıl düzeltilir?
XNA olaylar uzun zincirli (kullanırsanız Orada Game
temelde yatan resize olayı birbirine bağlayan bu özel pencereler için geçerli değildir) Form
, karşı Suspend
ve Resume
oyun saatinin yöntemleri.
Eğer gerekir böylece Bunlar, özeldir yansıması kullanmak (burada olayları unhook this
bir olduğunu Game
):
this.host.Suspend = null;
this.host.Resume = null;
İşte gerekli büyüleme:
object host = typeof(Game).GetField("host", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this);
host.GetType().BaseType.GetField("Suspend", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(host, null);
host.GetType().BaseType.GetField("Resume", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(host, null);
(Zincirin başka bir yerde bağlantısını kesebilirsiniz, bunu anlamak için ILSpy'yi kullanabilirsiniz. Ama pencereyi yeniden boyutlandırmanın yanında zamanlayıcıyı askıya alan başka bir şey yok - bu yüzden bu olaylar herhangi bir şey kadar iyi.)
O zaman XNA işaretlemediği zaman kendi kene kaynağınızı sağlamanız gerekir Application.Idle
. Ben sadece bir System.Windows.Forms.Timer
:
timer = new Timer();
timer.Interval = (int)(this.TargetElapsedTime.TotalMilliseconds);
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
Şimdi, timer_Tick
sonunda arayacak Game.Tick
. Artık saat askıya alınmadığından, XNA'nın kendi zamanlama kodunu kullanmaya devam etmekte özgürüz. Kolay! Tam olarak değil: manuel işaretlememizin yalnızca XNA'nın yerleşik işaretlemesi gerçekleşmediğinde olmasını istiyoruz. İşte bunu yapmak için bazı basit kod:
bool manualTick;
int manualTickCount = 0;
void timer_Tick(object sender, EventArgs e)
{
if(manualTickCount > 2)
{
manualTick = true;
this.Tick();
manualTick = false;
}
manualTickCount++;
}
Ve sonra, Update
XNA normal olarak işaretliyorsa sayacı sıfırlamak için bu kodu girin.
if(!manualTick)
manualTickCount = 0;
Bu işaretlemenin XNA'lardan çok daha az doğru olduğuna dikkat edin. Bununla birlikte, gerçek zamanlı olarak aşağı yukarı dizilmiş olarak kalmalıdır.
Bu kodda hala küçük bir kusur var. Aptal çirkin yüzünü korusun Win32, fare gerçekten hareket etmeden önce bir pencerenin başlık çubuğunu tıklattığınızda tüm mesajları birkaç yüz milisaniye boyunca durdurur ( aynı bağlantıya tekrar bakın ). Bu, Timer
(mesaj tabanlı olan) işaretlememizi önler .
Şimdi XNA'nın oyun saatini askıya almadığımız için, zamanlayıcımız sonunda tekrar işaretlemeye başladığında, bir güncelleme patlaması alacaksınız. Ve ne yazık ki, XNA, biriktirilebilir süreyi , başlık çubuğunu tıklattığınızda Windows'un iletileri durdurma süresinden biraz daha düşük bir miktarla sınırlar . Dolayısıyla, bir kullanıcı başlık çubuğunuzu tıklayıp basılı tutarsa, taşımadan güncellemeler patlar ve gerçek zamanlı olarak birkaç kare düşer.
(Ancak bu çoğu durumda hala yeterince iyi olmalıdır . XNA'nın zamanlayıcısı, kekemeliği önlemek için doğruluktan zaten fedakarlık yapar, bu nedenle mükemmel zamanlamaya ihtiyacınız varsa , başka bir şey yapmalısınız.)