В этом уроке напишем с нуля систему секретных пакетов. Подобная система есть во всех играх серии GTA. Идея простая: по карте разбросаны пикапы и когда игрок подбирает их все, то получает какую-то награду.
Видео часть с подробным описанием:
Условия:
- Нужно запоминать какие пакеты уже нашел игрок и при перезаходе их больше уже не показывать ему
- Когда игрок подбирает пакет, нужно показывать ему уведомление в котором будет указано сколько пакетов он уже нашел и сколько их всего
- Когда игрок подбирает все пакеты - выдать награду и соответствующее уведомление
Для начала нам понадобится список координат для пикапов де будут размещаться секретные пакеты. Для урока я взял 4 точки, которые находятся недалеко друг от друга.
При входе игрока на сервер будем отправлять ему этот список:
На клиентской стороне будем создавать пикапы по этому списку координат. Кроме пикапа создаем еще и колшейп.
Благодаря наличию колшейпов мы можем определять когда игрок подбирает пикап.
Примечание: Возможно для этого есть более простой способ и без колшейпа, но я честно его не нашел. По логике должен быть event когда игрок подбирает пикап, но на вики ничего нет.
Когда игрок подбираем пикап мы будем отправлять на сервер событие playerCollectedPackage в котором будем передавать id этого пакета.
На сервере мы будем запоминать какие пакеты подобрал игрок, сохранять их в файл. Когда игрок заходит на сервер мы будем загружать список с id найденный пикапов и передавать на клиент не весь список packages, а только те, которые еще не были найдены.
Для этого модифицируем на серверный код
В папке packages/secret-packages создадим папку data. В ней мы будем сохранять в файлах список id найденных пакетов для каждого игрока в отдельном файле. Название файла должно быть уникально и как-то связанно с игроком, чтобы при повторном заходе мы могли его найти и правильно определить. В этом уроке для простоты мы будем использовать ник игрока, но в реальном проекте советую использовать что-то другое, например, серийный номер клиента.
В самом файле мы будем хранить массив с id в виде JSON строки.
Когда формируем массив playerPackages, то в него не попадут уже найденные ранее игроком координаты. Соответственно в самом playerPackages нумерация координат будет отличаться от исходной в packages. Когда мы сохраняем список id найденных игроком, то они соответствуют порядковым номерам в массиве packages. Поэтому чтобы с клиента нам приходили верные id - мы добавляем к координатам еще и id.
package.id = packageId
Клиентский код тоже немного модифицируем, чтобы учитывать наличие id в самом объекте с координатами.
Когда игрок подбирает пикам мы будем добавлять его в список найденных и сохранять его сразу в файл на сервере.
На клиент обратно будем слать событие с подтверждением. В нем мы отправим число - сколько всего пакетов и сколько из них нашел игрок
Для того чтобы показывать красивые уведомления мы будем использовать библиотеку scaleform_messages
Также на серверной стороне мы будем выдавать какую-то награду когда игрок найдет все секретные пакеты. В нашем случае это будет оружиме миниган
Таким образом получаем полностью функциональный скрипт. Для работы нужно будет добавить больше координат пикапов и использовать более надежные идентификаторы в названиях файлов.
Автор: Lev Angel
Видео часть с подробным описанием:
Условия:
- Нужно запоминать какие пакеты уже нашел игрок и при перезаходе их больше уже не показывать ему
- Когда игрок подбирает пакет, нужно показывать ему уведомление в котором будет указано сколько пакетов он уже нашел и сколько их всего
- Когда игрок подбирает все пакеты - выдать награду и соответствующее уведомление
Для начала нам понадобится список координат для пикапов де будут размещаться секретные пакеты. Для урока я взял 4 точки, которые находятся недалеко друг от друга.
JavaScript:
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/secret-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