קוד רשת לסנכרון שחקנים: חיזוי בצד הלקוח ופיצוי השהיה

סנכרון שחקנים בזמן אמת הוא אתגר שהופך משחק מרובה משתתפים מבטיח למקור של באגים ותסכול לשחקנים. אנחנו מפתחים קוד רשת עם client-side prediction ושרת סמכותי כך שכל ירייה ותנועה יהיו הוגנים ומגיבים. הצוות שלנו מספק את הפרויקט במפתח מלא—מארכיטקטורה ועד תמיכה—ומבטיח משחקיות יציבה גם בחיבורים לא יציבים.

היכולות שלנו

שירותי סטודיו אחרים

יישומי VR/AR/MR מותאמים אישית

טבלו לקוחות וצוותים בחוויות דיגיטליות חדשות

פיתוח משחקי Unity

מקונספט לשחרור — משחקים שאנשים זוכרים

מידול ואנימציה בתלת-ממד

החיו את המוצר שלכם בגרפיקת תלת-ממד ואנימציה

סימולטורי ציוד VR תעשייתיים

אמנו מפעילים על ציוד בבטחה, ללא השבתה

הוראות AR לייצור

הנחיות שלב-אחר-שלב ישירות על הציוד — ללא נייר

סימולטורי VR לבטיחות

תרגול תגובה לשעת חירום ללא צורך בהגעה לשטח

תוכניות הכשרה ב-VR/AR

הכשרת עובדים בשירות, קליטה ומיומנויות רכות ב-VR

חידוני הכשרה לעובדים

בדיקת ידע באמצעות משחקים — בקלות וללא לחץ

הוראות וידאו ארגוניות

סרטונים ברורים להכשרת העובדים והלקוחות שלכם

גיימיפיקציה עסקית

הניעו צוותים עם מכניקת משחק ב-KPI ובמשאבי אנוש

יישומי קיוסק אינטראקטיביים

מסכים אינטראקטיביים לקמעונאות, תערוכות ומשרדים

מתקני VR/AR

אפקט וואו למותגים בתערוכות, אירועים וחדרי תצוגה

תערוכות ומוזיאונים וירטואליים

התערוכות שלכם מגיעות לכל פינה בעולם, 24/7

מסעות אירועים ומשחקי מותג

משחקים בלתי נשכחים לכנסים ולאירועי לקוחות

שאלות נפוצות

העבודות האחרונות

  • פיתוח משחקים עבור Mortal Motors
    פיתוח משחקים עבור Mortal Motors
    1638
  • משחק אסטרטגיה מבוסס תורות המתרחש בעולם פנטזיה, With Fire and Sword
    משחק אסטרטגיה מבוסס תורות המתרחש בעולם פנטזיה, With Fire and Sword
    1123
  • פיתוח משחק עבור חברת Second term
    פיתוח משחק עבור חברת Second term
    751
  • אנימציית תלת-ממד - טיזר למשחק Phoenix 2.
    אנימציית תלת-ממד - טיזר למשחק Phoenix 2.
    830

השהיה של 100 ms אינה עיכול בלתי מורגש. במשחק יריות מגוף ראשון, תוך 100 ms יריב נע 30–50 סנטימטרים. ללא חיזוי צד לקוח, ירי לעבר מטרות נעות הופך לבלתי נוח פיזית. בניסיון שלנו, אנו רואים לעיתים קרובות צוותים שמבזבזים חודשים בתיקון ההשלכות של בחירות ארכיטקטורת סנכרון שגויות. לכן עבור משחקי מרובי משתתפים תחרותיים אין אופציה של 'רק לסנכרן מיקומים באמצעות RPC'—אתה צריך ארכיטקטורה מלאה עם חיזוי צד לקוח ושרת סמכותי. זה החלק הטכני המאתגר ביותר בפיתוח משחקים, ואנחנו מתמחים בו. יישום נכון של חיזוי צד לקוח ופיצוי השהיה יכול להפחית את ההשהיה הנתפסת ב-20–30%.

למה סנכרון נאיבי לא עובד

הגישה הפשוטה: השרת שולח מיקומים לכל הלקוחות. הלקוח מקבל את עדכון המיקום ומזיז את האובייקט. עם RTT של 100 ms, האובייקט תמיד יפגר אחרי המיקום האמיתי שלו בשרת. בעת תנועה—נראה עיכוב; בעת קפיצה—'ריצוד'. סיבוך נוסף: עם אובדן מנות של 5%, הסנכרון מתפרק לחלוטין, ושחקנים רואים טלפורטציה.

NetworkTransform עם אינטרפולציה (מובנה ב-Netcode for GameObjects) הוא הרמה הבאה. הלקוח לא מטלפורט את האובייקט; הוא מבצע אינטרפולציה בין שני מיקומים ידועים. זה מסיר את הריצוד החזותי אך לא פותר את בעיית הסמכות: הלקוח שולט בדמות שלו, השרת סומך על הלקוח. זה פותח אפשרויות לרמאות ולא מתקן פיצוי השהיה.

חיזוי צד לקוח + פיוס שרת הוא הפתרון הנכון למשחקי פעולה. הלקוח מיישם מיד את הקלט מקומית. במקביל, הוא שולח את הקלט לשרת. השרת מעבד את הקלט ומחזיר את המצב הסמכותי. הלקוח משווה את המצב החזוי שלו למצב השרת, ואם יש אי-התאמה, מבצע rollback + replay. עם יישום נכון, השחקן לא מבחין בעיכוב—הדמות שלו מגיבה מיידית.

ב-Unity NGO (Netcode for GameObjects), זה ממומש באמצעות NetworkRigidbody עם NetworkTransform במצב Interpolate או באמצעות ClientNetworkTransform מותאם אישית. ב-Photon Fusion, יש NetworkMecanimAnimator ו-KCC (Kinematic Character Controller) מובנים עם חיזוי מובנה מראש.

דוגמת יישום של חיזוי צד לקוח ב-Unity
public class PlayerController : NetworkBehaviour
{
    private Rigidbody rb;
    private InputState currentInput;
    private List<InputState> inputHistory = new List<InputState>();

    void Start()
    {
        rb = GetComponent<Rigidbody>();
    }

    void Update()
    {
        if (!IsOwner) return;

        // Собираем ввод и применяем локально
        currentInput = GatherInput();
        ApplyInput(currentInput);
        inputHistory.Add(currentInput);

        // Отправляем на сервер
        CmdSendInput(currentInput);
    }

    [Command]
    void CmdSendInput(InputState input)
    {
        // Сервер обрабатывает и отправляет авторитетное состояние обратно
        ApplyInputAuthoritative(input);
        TargetReceiveState(GetComponent<NetworkTransform>().Position);
    }

    [TargetRpc]
    void TargetReceiveState(Vector3 serverPosition)
    {
        // Rollback и replay при расхождении
        if (Vector3.Distance(transform.position, serverPosition) > 0.1f)
        {
            transform.position = serverPosition;
            // Replay inputs after correction
        }
    }
}

איך ליישם פיצוי השהיה לפגיעות

בעיה קשה נפרדת: השחקן יורה ורואה פגיעה, אבל בזמן הירי בשרת המטרה כבר הייתה במיקום אחר. פיצוי השהיה הוא טכניקה שבה השרת 'מחזיר לאחור' את מצב סצנת המשחק בזמן (לפי ההשהיה של הלקוח) כדי לבדוק את הפגיעה.

זה ממומש באמצעות History Buffer בשרת: בכל tick אנחנו שומרים snapshot של מיקומי כל השחקנים. בעת עיבוד בקשת ירי מהלקוח, אנחנו משחזרים את ה-snapshot מהעבר, מבצעים raycast, ואז חוזרים למצב הנוכחי.

ב-Mirror זה נעשה ידנית באמצעות public class PlayerController : NetworkBehaviour { private Rigidbody rb; private InputState currentInput; private List<InputState> inputHistory = new List<InputState>(); void Start() { rb = GetComponent<Rigidbody>(); } void Update() { if (!IsOwner) return; // Собираем ввод и применяем локально currentInput = GatherInput(); ApplyInput(currentInput); inputHistory.Add(currentInput); // Отправляем на сервер CmdSendInput(currentInput); } [Command] void CmdSendInput(InputState input) { // Сервер обрабатывает и отправляет авторитетное состояние обратно ApplyInputAuthoritative(input); TargetReceiveState(GetComponent<NetworkTransform>().Position); } [TargetRpc] void TargetReceiveState(Vector3 serverPosition) { // Rollback и replay при расхождении if (Vector3.Distance(transform.position, serverPosition) > 0.1f) { transform.position = serverPosition; // Replay inputs after correction } } } ו-buffer טבעתי של snapshots. ב-Photon Fusion, זה זמין חלקית דרך ה-API המובנה NetworkTime.time.

תיאור של טכניקת פיצוי ההשהיה ניתן למצוא בתיעוד של Source Engine.

מקרה מהפרקטיקה: משחק יריות טקטי למובייל, 4 שחקנים למשחק. היישום הראשוני השתמש ב-NetworkTransform פשוט + RPC לירי. במכשירים עם השהיה של 80–120 ms, החטאות היו ברורות ויזואלית—השחקן כיוון ליריב אבל לא נרשמו פגיעות. לאחר יישום חיזוי צד לקוח לתנועה + פיצוי השהיה בהשהיית שרת של 150 ms, 'הוגנות' הפגיעות הפכה למקובלת עבור קהל מזדמן. שימור השחקנים עלה ב-30%. בנוסף, חריגת תקציב הפיתוח הופחתה ב-25% הודות לזיהוי מוקדם של בעיות.

מה זה סנכרון מצב ולמה הוא נחוץ

סנכרון מצב חורג הרבה מעבר לתנועת דמות. HP, מלאי, מצב של אובייקטי משחק (דלתות, מלכודות, קליעים)—כל אלה דורשים סנכרון. שתי גישות עיקריות:

  • סנכרון מצב: השרת שולח מעת לעת את המצב המלא (או delta) לכל הלקוחות. אמין אבל צורך רוחב פס רב עם אובייקטים רבים.
  • מונע אירועים: לקוחות שולחים אירועים (השחקן פתח את הדלת), לקוחות אחרים מיישמים את האירוע מקומית. זול יותר ברוחב פס אבל דורש אירועים אידמפוטנטיים וטיפול באובדן מנות.

רוב הפרויקטים משתמשים בגישה היברידית: אירועים נדירים דרך RPC אמין, עדכונים תכופים (מיקומים, אנימציות) דרך ערוץ לא אמין עם אינטרפולציה.

LagCompensatedHit ב-NGO הוא הפשטה נוחה לסנכרון ערכים: NetworkVariable. הוא מסנכרן אוטומטית בעת שינוי ותומך ב-callback מסוג NetworkVariable<int> Health. עבור HP, ניקוד, מצב משחק—אידיאלי. עבור נתונים המשתנים במהירות (מיקום בכל פריים)—זה מוגזם.

גישה רוחב פס אמינות מורכבות יישום
סנכרון מצב גבוה גבוהה בינונית
מונע אירועים נמוך בינונית גבוהה

מה כלול בפיתוח קוד רשת

פיתוח קוד רשת כולל מספר שלבים:

  1. ניתוח משחק — קביעת ז'אנר, מספר שחקנים (2 עד 64), דרישות דיוק סנכרון וצרכי אנטי-צ'יט.
  2. עיצוב ארכיטקטורה — יצירת דיאגרמת רשת המציינת סמכות לכל רכיב.
  3. בחירת מחסנית טכנולוגית — בחירה בין NGO עם UGS Relay, Mirror עם שרת ייעודי, Photon Fusion, או Nakama.
  4. יישום — כתיבת קוד לחיזוי צד לקוח, פיצוי השהיה, סנכרון מצב.
  5. בדיקות — בדיקה בסימולטור רשת עם עיכובים של 50/100/200 ms ואובדן מנות של 1–5%.
  6. אופטימיזציה — הפחתת רוחב פס ב-30%, מזעור draw calls, הגדרת LOD.
  7. תיעוד והדרכה — מסירת קוד, תיאור ארכיטקטורה, הדרכת הצוות.
  8. תמיכה — תחזוקה בפרודקשן, תיקון באגים.

איך אנחנו בונים קוד רשת

אנחנו מתחילים עם דיאגרמת רשת—סכמה של כל מערכות המשחק המציינת מה סמכותי בשרת, מה בלקוח, אילו נתונים מסונכרנים ובאיזה תדירות. זה הבסיס של הארכיטקטורה.

אנחנו בוחרים את מחסנית הרשת לפרויקט: NGO עבור Unity עם UGS Relay, Mirror + שרת ייעודי מותאם אישית, Photon Fusion לפעולה תחרותית, Nakama לקז'ואל עם backend למשחק.

הפיתוח מתבצע בסימולטור רשת—אנחנו בודקים עם עיכובים מלאכותיים של 50/100/200 ms ואובדן מנות של 1–5%. בעיות סנכרון מתגלות רק בתנאי רשת אמיתיים.

היקף משימה לוח זמנים משוער
סנכרון מיקום בסיסי (2–8 שחקנים) 2–4 שבועות
חיזוי צד לקוח + פיצוי השהיה 4–8 שבועות
ארכיטקטורת רשת מלאה עם סנכרון מצב משחק 6–12 שבועות
אופטימיזציה של קוד רשת קיים 2–4 שבועות

העלות נקבעת לאחר ניתוח ז'אנר המשחק, מספר השחקנים ודרישות דיוק הסנכרון.

עם 5 שנים בשוק, השלמנו מעל 10 פרויקטים עם סנכרון ל-2 עד 64 שחקנים, כולל משחקי יריות למובייל, משחקי פעולה למחשב ומשחקי VR. למהנדסים שלנו יש ניסיון מוכח עם Unity ו-Unreal Engine.

קבלו ייעוץ על ארכיטקטורת סנכרון למשחק שלכם—נכין תוכנית מפורטת והערכת עלות. הזמינו ביקורת על קוד הרשת הקיים שלכם כדי לזהות צווארי בקבוק לפני השחרור.