26DiDi12
@26DiDi12
Энтузиаст с суицидальными наклонностями :3

Как синхронизировать пулю с сервером?

Я пытаюсь синхронизировать пулю клиента с сервером, вот код:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

public class PlayerShoot : NetworkBehaviour {

    public PlayerShoot PlayerShootScript;
    public Player PlayerScript;
    public LayerMask WeaponEnemyLayers;
    [Space]
    public Transform[] WeaponfirePoints;
    public GameObject[] WeaponBulletPrefab;
    [Space]
    public float WeaponScatter;
    public float WeaponBulletForce;
    [Space]
    public int WeaponMinDamage;
    public int WeaponMaxDamage;
    public int WeaponChanceCritDamage;
    public int WeaponCritDamage;
    [Space]
    public int WeaponOtskoks = 0;
    public int WeaponProshivanies = 0;

    void Update() {

        if(isLocalPlayer)
        if(PlayerScript.currentWeaponScript == null) { return; }

        WeaponfirePoints = PlayerScript.currentWeaponScript.firePoints;
        WeaponScatter = PlayerScript.currentWeaponScript.scatter;
        WeaponBulletForce = PlayerScript.currentWeaponScript.bulletForce;
        WeaponBulletPrefab = PlayerScript.currentWeaponScript.bulletPrefab;

        WeaponMinDamage = PlayerScript.currentWeaponScript.minDamage;
        WeaponMaxDamage = PlayerScript.currentWeaponScript.maxDamage;
        WeaponChanceCritDamage = PlayerScript.currentWeaponScript.chanceCritDamage;
        WeaponCritDamage = PlayerScript.currentWeaponScript.critDamage;

        WeaponOtskoks = PlayerScript.currentWeaponScript.otskoks;
        WeaponProshivanies = PlayerScript.currentWeaponScript.proshivanies;

        WeaponEnemyLayers = PlayerScript.currentWeaponScript.enemyLayers;

        if(Input.GetButtonDown("Fire1")) { PlayerScript.currentWeaponScript.mouseHide = true; }
        if(Input.GetButtonUp("Fire1")) { PlayerScript.currentWeaponScript.mouseHide = false; }

        if(PlayerScript.currentWeaponScript.weaponReloadnig) { return; }
        if(!PlayerScript.currentWeaponScript.weaponReadyToShoot) { return; }

        if(PlayerScript.currentWeaponScript.categoryWeapon == "Огнестрельное") { 

            if(PlayerScript.currentWeaponScript.mouseHide) {

                Shoot();
        
            }
                
        }
        
    }

    [Client]
    void Shoot() {

        CmdSpawnBullet();
        if(!PlayerScript.currentWeaponScript.infiniteMode) { PlayerScript.currentWeaponScript.currentAmmo -= 1; }

    }
    
    [Command]
    void CmdSpawnBullet() {

        for (int i = 0; i < WeaponfirePoints.Length; i++) {

            Vector3 Angle = WeaponfirePoints[i].eulerAngles;
            Angle.z += Random.Range(-WeaponScatter, WeaponScatter);
            GameObject bullet = GameObject.Instantiate(WeaponBulletPrefab[Random.Range(0, WeaponBulletPrefab.Length)], WeaponfirePoints[i].position, Quaternion.Euler(Angle));

            Rigidbody2D rb = bullet.GetComponent<Rigidbody2D>();
            rb.velocity = bullet.transform.right * WeaponBulletForce;
            
            int damage = Random.Range(WeaponMinDamage, WeaponMaxDamage+1);
            bool CRIT = false;

            NetworkServer.Spawn(bullet);
            
            Bullet bulletScript = bullet.GetComponent<Bullet>();
            bulletScript.EarlyShoot(PlayerShootScript);
            bulletScript.DamageMastery(WeaponOtskoks, WeaponProshivanies, damage, WeaponCritDamage, WeaponChanceCritDamage, WeaponEnemyLayers);

        }

    }

    [Command]
    public void CmdHitOn(string _playerTag, string _playerID, int _damage, bool CRITICAL_DAMAGE) {

        if(CRITICAL_DAMAGE) {

            if(_playerTag == "Player") {

                Player _player = GameManager.GetPlayer(_playerID);
                _player.TakeCritDamage(_damage);

            }

        } else {

            if(_playerTag == "Player") {

                Player _player = GameManager.GetPlayer(_playerID);
                _player.TakeDamage(_damage);

            }

        }

    }

}


Когда сервер делает выстрелы, то клиент видит их, но сам клиент не может стрелять, я частично понимаю почему, но я не понимаю как сделать так, чтобы клиент мог стрелять и сервер видел его выстрелы.
  • Вопрос задан
  • 86 просмотров
Пригласить эксперта
Ответы на вопрос 2
dollar
@dollar
Делай добро и бросай его в воду.
Это очень сложная задача (с точки зрения геймдизайна).

Решение обычно сводится либо к отсутствию пули, либо к самонаводящейся пуле, либо к отсутствию точной синхронизации пули между клиентом и сервером. Ну либо в требованиях к игре нужно прописать крайне низкий пинг и отсутствие потерь пакетов.
Ответ написан
@rPman
Конкретно по вопросу почему 'клиент не может стрелять' хз, надо отладкой заниматься, или хотя бы расставь логирование по коду

А вот реализация правильной синхронизации клиент сервера действительно очень сложная задача.

Один из способов ее решения, реализовывать всю логику всей динамики только на сервере, а клиенты работают исключительно на отображение. Т.е. когда клиент передает на сервер буквально нажатия кнопок (точнее первичные действия), они отправляются на сервер, он их обрабатывает и любые изменения (изменения состояний, перемещения, создание и удаление объектов) уже сервером рассылаются на клиенты.

Достоинство - простота реализации, автосинхранизация, упрощение создания античитов (клиент к примеру не может в такой ситуации выдать неправильную скорость или неверное применить действия), низкий сетевой трафик от клиента к серверу.

Недостаток подхода - ощутимые лаги, когда скорость интернета низкая, с ними тоже можно 'бороться', исключительно визуально скрывать задержку, если для отображения информации о критичных объектах клиент дублирует их обработку параллельно с сервером, но итоговый результат все равно принимается от сервера (в результате пуля может 'отскочить назад' во время прямолинейного полета или исчезнуть, если окажется что под нее подъехала цель а клиент посчитал что промахнулся и т.п.)

Еще недостатком является высокая нагрузка на сервер (а она по любому такова должна быть, для борьбы с читами сервер обязан обслуживать все объекты централизовано), высокая нагрузка на сеть сервера (сервер постоянно рассылает информацию всем своим клиентам, а это квадрат от количества игроков).

Хорошим способом борьбы с нагрузкой на сервер может являться p2p, когда данные об изменения, паралеллельно с сервером обрабатываемые клиентами, рассылаются не через сервер, а напрямую клиентам, а сервер рассылает только хеши результата. Это сильно усложнит код (я не слышал чтобы крупные проекты так делали) но позволит решить кучу проблем как с лагами так и с высокой стоимостью сервера.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы