[Tutorial] Снег на сервере
#1

В канун Нового Года данная тема как нельзя лучше пригодится держателям серверов. Конечно, а кто не хочет снег зимой? Изучив много тем про снег я понял, что вариантов масса. Предлагаю рассмотреть самые распространённые 4 из них.



Заведём переменную, отвечающую за этот объект:
pawn Code:
new snowobj[MAX_PLAYERS];
Теперь разберём 3 случая реализации снегопада. Я думаю, каждый подберёт вариант по себе.

Вариант № 1 - Перемещающийся объект

Данный вид показал Kwarde 13.11.2011 на оф. форуме и модифицировал спустя год, 26.11.2012. Суть этого варианта заключается в том, что снегу нативно устанавливается позиция по таймеру. Создаётся 8 объектов снега на каждого игрока (всего до 8000) и переменная таймера:
pawn Code:
new snowObject[MAX_PLAYERS][8], updateTimer[MAX_PLAYERS];
Затем, в нужный момент, создаётся сам снег:
pawn Code:
new Float:pPos[3];
GetPlayerPos(playerid, pPos[0], pPos[1], pPos[2]);
for(new i = 0; i < MAX_SNOW_OBJECTS; i++) snowObject[playerid][i] = CreateDynamicObject(18864, pPos[0] + random(25), pPos[1] + random (25), pPos[2] - 5 + random(10), random(280), random(280), 0, -1, -1, playerid);
updateTimer[playerid] = SetTimerEx("UpdateSnow", 750, true, "i", playerid);
Снег создан, таймер запущен. По этому таймеру будет меняться позиция, в зависимости от позиции игрока:
pawn Code:
forward UpdateSnow(playerid);
public UpdateSnow(playerid)
{
    new Float:pPos[3];
    GetPlayerPos(playerid, pPos[0], pPos[1], pPos[2]);
    for(new i = 0; i < 8; i++) SetDynamicObjectPos(snowObject[playerid][i], pPos[0] + random(25), pPos[1] + random(25), pPos[2] - 5 + random(10));
    return 1;
}
Строго говоря, с такой частотой обновления, я бы лучше использовал OnPlayerUpdate, чтобы не было лишних таймеров.

Плюсы: объекты не зависят от игрока и присутствуют на сервере нативно.
Минусы: необходим стример, жутко лагает от такого кол-ва объектов.

Вариант № 2 - Движущийся объект

Предложен Dav1dBlane 12.12.2010 на форуме SRC. Его суть заключается в том, что объект снега двигается туда, куда смотрит камера игрока.

Создаём объект по положению камеры:
pawn Code:
new Float:pPos[3];
GetPlayerCameraPos(playerid, pPos[0], pPos[1], pPos[2]);
snowobj[playerid] = CreatePlayerObject(playerid, 18864, pPos[0], pPos[1], pPos[2] - 5.0, 0.0, 0.0, 0.0, 300.0);
А затем двигаем туда, куда смотрит камера игрока:
pawn Code:
public OnPlayerUpdate(playerid)
{
    new Float:pPos[3];
    GetPlayerCameraPos(playerid, pPos[0], pPos[1], pPos[2]);
    MovePlayerObject(playerid, snowobj[playerid], pPos[0], pPos[1], pPos[2] - 5.0, 9999.0);
    return 1;
}
Плюсы: нет большой нагрузки на клиента.
Минусы: снижается кол-во возможных объектов для игрока на 1 (с 1000 до 999).

Третий способ - Приаттаченный объект. Есть информация, что автор способа - Xenus. Упомянут способ 22.01.2011 на PI.

Выбираем кость (я советую торс) и аттачим снег:
pawn Code:
SetPlayerAttachedObject(playerid, 9, 18864, 1, 1.5, 0.5, 0.0, 0.0, 0.0, 1.5, 1.0, 1.0, 1.0, 0, 0);
И всё. Обновлять ничего не нужно.

Плюсы: нет большой нагрузки на клиента, снег "ходит" вместе с игроком.
Минусы: число возможных приаттаченных объектов уменьшается на 1, вместо 10 станет 9.

Последний вариант вообще не зависит от игроков - Глобальный объект. По разным данным White_116 был его инициатором. Если у вас есть более полная информация - пишите, исправим. В этом методе мы просто создадим 3600(!) динамических объектов (т.к. статических создать можно только 1000).

pawn Code:
for(new x = -3000; x < 3000; x += 100)
    for(new y = -3000; y < 3000; y += 100)
        CreateDynamicObject(18864, x, y, 2.0, 0.0, 0.0, 1.0);
Плюсы: нет участия игроков в процессе, проверок и таймеров.
Минусы: очень много объектов, ужасно лагает.

Прикладываю ФС, где в равных условиях (по 1 объекту) были добавлены все 3 варианта - пробуйте и забирайте тот, который для вас более комфортный и/или интересный.

[spoiler=Полный листинг кода]
pawn Code:
#include <a_samp>
#include <streamer>
// Snow by Xenus, Kwarde, Dav1dBlane, OKStyle
new snowobj[MAX_PLAYERS];
public OnPlayerUpdate(playerid)
{
    new Float:pPos[3];
    if(GetPVarInt(playerid, "Snow_Kwarde") == 1)
    {
        GetPlayerPos(playerid, pPos[0], pPos[1], pPos[2]);
        SetDynamicObjectPos(snowobj[playerid], pPos[0] + random(25), pPos[1] + random(25), pPos[2] - 5 + random(10));
    }
    else if(GetPVarInt(playerid, "Snow_Dav1dBlane") == 1)
    {
        GetPlayerCameraPos(playerid, pPos[0], pPos[1], pPos[2]);
        MovePlayerObject(playerid,snowobj[playerid], pPos[0], pPos[1], pPos[2] - 5.0, 9999.0);
    }
    return 1;
}
public OnPlayerCommandText(playerid, cmdtext[])
{
    new Float:pPos[3];
    if(strcmp(cmdtext, "/snow1", true) == 0)
    {
        SendClientMessage(playerid, 0xFFFF00FF, "Метод Kwarde");
        if(GetPVarInt(playerid, "Snow_Kwarde") == 0)
        {
            SetPVarInt(playerid, "Snow_Kwarde", 1);
            GetPlayerPos(playerid, pPos[0], pPos[1], pPos[2]);
            snowobj[playerid] = CreateDynamicObject(18864, pPos[0] + random(25), pPos[1] + random (25), pPos[2] - 5 + random(10), random(280), random(280), 0, -1, -1, playerid);
            return 1;
        }
        DeletePVar(playerid, "Snow_Kwarde");
        DestroyDynamicObject(snowobj[playerid]);
        return 1;
    }
    if(strcmp(cmdtext, "/snow2", true) == 0)
    {
        SendClientMessage(playerid, 0xFFFF00FF, "Метод Dav1dBlane");
        if(GetPVarInt(playerid, "Snow_Dav1dBlane") == 0)
        {
            SetPVarInt(playerid, "Snow_Dav1dBlane", 1);
            GetPlayerCameraPos(playerid, pPos[0], pPos[1], pPos[2]);
            snowobj[playerid] = CreatePlayerObject(playerid, 18864, pPos[0], pPos[1], pPos[2] - 5.0, 0.0, 0.0, 0.0, 300.0);
            return 1;
        }
        DeletePVar(playerid, "Snow_Dav1dBlane");
        DestroyPlayerObject(playerid, snowobj[playerid]);
        return 1;
    }
    if(strcmp(cmdtext, "/snow3", true) == 0)
    {
        SendClientMessage(playerid, 0xFFFF00FF, "Метод Xenus");
        if(GetPVarInt(playerid, "Snow_Xenus") == 0)
        {
            SetPVarInt(playerid, "Snow_Xenus", 1);
            SetPlayerAttachedObject(playerid, 9, 18864, 1, -9.0, 0.0, 0.0, 0.0, 90.0, 0.0);
            return 1;
        }
        DeletePVar(playerid, "Snow_Xenus");
        RemovePlayerAttachedObject(playerid, 9);
        return 1;
    }
    if(strcmp(cmdtext, "/snow4", true) == 0)
    {
        SendClientMessage(playerid, 0xFFFF00FF, "Метод AnGeL");
        if(GetPVarInt(playerid, "Snow_AnGeL") == 0)
        {
            SetPVarInt(playerid, "Snow_AnGeL", 1);
            for(new x = -3000; x < 3000; x += 100)
            {
                for(new y = -3000; y < 3000; y += 100) CreateDynamicObject(18864, x, y, 2.0, 0.0, 0.0, 1.0);
            }
            return 1;
        }
        DeletePVar(playerid, "Snow_AnGeL");
        DestroyAllDynamicObjects();
        return 1;
    }
    return 1;
}
[/spoiler]

P.S. Советую при снегопаде ставить погоду № 9.

Автор: OKStyle
Reply
#2

А почему везде используется 18864? Он на снег не похож, большие серые хлопья. Летит чересчур быстро.
18863 ещё же есть. Маленькие, аккуратненькие белые частички, медленно спускаются.
Reply
#3

Это вулканический пепел.
Reply
#4

Способ #2
GetPlayerCameraPos(playerid, pPos[0], pPos[1], pPos[2); - не хватает квадратной скобки
Reply
#5

Окс Вариант не мой....

Перепиши его на White_116

У меня с того момента уже другой вариант)))
Reply
#6

Ну показывай давай - добавим.
Reply
#7

После нового года)))
Reply
#8

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

Второй вариант самый оптимальный..
Reply
#9

Все это визуально херня, если честно. Куда логичнее сгенерить тучу объектов и разместить их через стример.
Reply
#10

Написано черт знает когда.
PHP Code:
new snow;
new 
snowobj[32000];
new 
maxsnowobj;
COMMAND:snow(playerid,params[])
{
        switch(
snow)
        {
            case 
0:
            {
                new 
i=CreateSnowMass();
                   new 
str[64];
                
format(str,sizeof(str),"Снег создан, всего %d",i);
                
SendClientMessage(playerid,0x000000FF,str);
                
snow=1;
            }
            case 
1:
            {
                for(new 
i=0i<maxsnowobji++)DestroyDynamicObject(snowobj[i]);
                
SendClientMessage(playerid,0x000000FF,"Снег удален");
                
snow=0;
            }
        }
    return 
1;
}
stock CreateSnowMass()
{
    new 
i;
    new 
x=-3000,y=-3000,z=0;
    while(
z<100)
    {
        while(
x<=3000)
        {
            while(
y<=3000)
            {
                
//18864
                
snowobj[i]=CreateDynamicObject(18864x,y,zrandom(100),random(100),random(100),-10,-1,100.0);
                
i++;
                
y+=50;
            }
            
y=-3000;
            
x+=50;
        }
        
x=-3000;
        
z+=50;
    }
    
maxsnowobj=i;
    return 
i;

Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)