This is a mobile optimized page that loads fast, if you want to load the real page, click this text.

Мануал Урок FAQ Система Секретных Пакетов для Rage MP

nettkom

Специалист
Автор темы
14 Сен 2020
58
42
82



В этом уроке напишем с нуля систему секретных пакетов. Подобная система есть во всех играх серии GTA. Идея простая: по карте разбросаны пикапы и когда игрок подбирает их все, то получает какую-то награду.

Видео часть с подробным описанием:

Условия:
  • Нужно запоминать какие пакеты уже нашел игрок и при перезаходе их больше уже не показывать ему
  • Когда игрок подбирает пакет, нужно показывать ему уведомление в котором будет указано сколько пакетов он уже нашел и сколько их всего
  • Когда игрок подбирает все пакеты - выдать награду и соответствующее уведомление

Для начала нам понадобится список координат для пикапов де будут размещаться секретные пакеты. Для урока я взял 4 точки, которые находятся недалеко друг от друга.

JavaScript:
const packages = [
    { x: -422.77093505859375, y: 1166.211669921875, z: 325.973876953125},
    { x: -404.05560302734375, y: 1161.9130859375, z: 325.98529052734375},
    { x: -410.40142822265625, y: 1134.956298828125, z: 325.973297119140},
    { x: -428.8808288574219, y: 1138.2325439453125, z: 325.9739685058594}
];

При входе игрока на сервер будем отправлять ему этот список

JavaScript:
mp.events.add("playerReady", player => {
    player.call('playerInitSecretPackages', [packages]);
});

На клиентской стороне будем создавать пикапы по этому списку координат. Кроме пикапа создаем еще и колшейп.

JavaScript:
const pickupHash = 3732468094;


mp.events.add('playerInitSecretPackages', (packages)=> {
    packages.forEach((package, id) => {
        let colshape = mp.colshapes.newSphere(package.x, package.y, package.z, 1);
        colshape.secretPackageId= id;
        colshape.secretPickup = mp.game.object.createPickupRotate(pickupHash, package.x, package.y, package.z, 0, 0, 0, 512, 0, 0, true, pickupHash);
    });
});




Благодаря наличию колшейпов мы можем определять когда игрок подбирает пикап.
Примечание: Возможно для этого есть более простой способ и без колшейпа, но я честно его не нашел. По логике должен быть event когда игрок подбирает пикап, но на вики ничего нет.

JavaScript:
mp.events.add("playerEnterColshape", (colshape) => {
    if(colshape.secretPickup){
        mp.events.callRemote('playerCollectedPackage', colshape.secretPackageId ); // отправляем id пакета на сервер
        mp.game.object.removePickup(colshape.secretPickup);
        colshape.destroy();
    }
});

Когда игрок подбираем пикап мы будем отправлять на сервер событие playerCollectedPackage в котором будем передавать id этого пакета.
На сервере мы будем запоминать какие пакеты подобрал игрок, сохранять их в файл. Когда игрок заходит на сервер мы будем загружать список с id найденный пикапов и передавать на клиент не весь список packages, а только те, которые еще не были найдены.
Для этого модифицируем на серверный код

JavaScript:
var fs = require('fs'); // подключим модуль для работы с файлами

В папке packages/sevret-packages создадим папку data. В ней мы будем сохранять в файлах список id найденных пакетов для каждого игрока в отдельном файле. Название файла должно быть уникально и как-то связанно с игроком, чтобы при повторном заходе мы могли его найти и правильно определить. В этом уроке для простоты мы будем использовать ник игрока, но в реальном проекте советую использовать что-то другое, например, серийный номер клиента.
В самом файле мы будем хранить массив с id в виде JSON строки.

JavaScript:
mp.events.add("playerReady", player => {


    fs.readFile( __dirname + `/data/${player.name}.txt`, function(err,data){ // загружаем список найденный пакетов для игрока
        let collectedPackages = new Array();


        if(!err){
            collectedPackages = JSON.parse(data);
        }
        // если файла нет или возникла другая ошибка то collectedPackages будет просто пустым массивом


        player.packagesCollected = collectedPackages;


        let playerPackages = new Array(); // в этот массив запишем все координаты которые игрок еще не нашел


        packages.forEach((package, packageId) => {
            if (player.packagesCollected.indexOf(packageId) == -1){
                package.id = packageId // обязательно добавляем к координатам порядковый id пакета в массиве packages, т. к. в playerPackages порядок координат будет другой
                playerPackages.push(package);
            }
        });


        player.call('playerInitSecretPackages', [playerPackages]);


    });
});

Когда формируем массив playerPackages, то в него не попадут уже найденные ранее игроком координаты. Соответственно в самом playerPackages нумерация координат будет отличаться от исходной в packages. Когда мы сохраняем список id найденных игроком, то они соответствуют порядковым номерам в массиве packages. Поэтому чтобы с клиента нам приходили верные id - мы добавляем к координатам еще и id.
package.id = packageId

Клиентский код тоже немного модифицируем, чтобы учитывать наличие id в самом объекте с координатами.

JavaScript:
mp.events.add('playerInitSecretPackages', (packages)=> {
    packages.forEach((package) => {
        let colshape = mp.colshapes.newSphere(package.x, package.y, package.z, 1);
        colshape.secretPackageId= package.id;
        colshape.secretPickup = mp.game.object.createPickupRotate(pickupHash, package.x, package.y, package.z, 0, 0, 0, 512, 0, 0, true, pickupHash);
    });
});

Когда игрок подбирает пикам мы будем добавлять его в список найденных и сохранять его сразу в файл на сервере.

JavaScript:
mp.events.add("playerCollectedPackage", (player, packageId) => {
    player.packagesCollected.push(packageId);
    playerStorePackagesData(player);
    console.log(`${player.name} collected secret package id: ${packageId}`);
});


function playerStorePackagesData(player){
    fs.writeFile(__dirname + `/data/${player.name}.txt`, JSON.stringify(player.packagesCollected), () => {});
}

На клиент обратно будем слать событие с подтверждением. В нем мы отправим число - сколько всего пакетов и сколько из них нашел игрок

JavaScript:
mp.events.add("playerCollectedPackage", (player, packageId) => {
    ...
 
    player.call('playerSecretPackageInfo', [packages.length, player.packagesCollected.length]);
});

Для того чтобы показывать красивые уведомления мы будем использовать библиотеку scaleform_messages

JavaScript:
mp.events.add('playerSecretPackageInfo', (totalPackages, collectedPackages)=> {
    let title = "Секретный пакет найден";
    if(collectedPackages == totalPackages){
        title = "Вы нашли все Секретные пакеты";
    }


    mp.events.call("ShowShardMessage", title, `Найдено пакетов: ${collectedPackages}/${totalPackages} `);
});



Также на серверной стороне мы будем выдавать какую-то награду когда игрок найдет все секретные пакеты. В нашем случае это будет оружием миниган
JavaScript:
mp.events.add("playerCollectedPackage", (player, packageId) => {
    ...


    if( player.packagesCollected.length == packages.length){
        playerCollectAllPackages(player);
    }
});




function playerCollectAllPackages(player){
    console.log(`${player.name} collected all secret packages`);
    player.giveWeapon(mp.joaat('weapon_minigun'), 10000);
}



Таким образом получаем полностью функциональный скрипт. Для работы нужно будет добавить больше координат пикапов и использовать более надежные идентификаторы в названиях файлов.

Автор:
Lev Angel
 

Вложения

  • secret-packages.zip
    5.3 KB · Просмотры: 218
Последнее редактирование модератором:
Реакции: Evbej