Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > разработка игр, графический дизайн и моделирование > Gamedev - cоздание игр: Unity, OpenGL, DirectX
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 23.12.2007, 04:04   #321
Tenray
 
Регистрация: 20.12.2007
Сообщений: 3
По умолчанию

to Beermonza:

А можно ли примерчик? (код на Delphi или на С/C++)

У меня возникла сложность как раз в определении тайла, на который я "кликаю". До этого я разрабатывал игры с ограниченым числом тайлов. Т.е. с размером, например, 20x20... (Настольные игры) Где вычисление тайла происходит следующим образом:
1. Определяю координаты курсора.
2. Определяю к какому тайлу (ромбу) принадлежит точка курсора..
(В отдельном массиве хранится координаты верхней точки тайла.)

Попробывал созадь карту по технологии выше описаной... И при создании карты, например, 100x100 определение тайла теряется...

Последний раз редактировалось Tenray; 23.12.2007 в 04:13.
Tenray вне форума Ответить с цитированием
Старый 23.12.2007, 14:31   #322
mutabor
Телепат с дипломом
Старожил
 
Аватар для mutabor
 
Регистрация: 10.06.2007
Сообщений: 4,929
По умолчанию

Цитата:
при создании карты, например, 100x100 определение тайла теряется...
С чего бы ему теряться, нет принципиальной разницы карта у тебя 20х20, 100х100, или 1000х1000. Ты просто где-то ошибку допустил при переделывании кода под большую карту, скорее всего в определении принадлежности точки к тайлу.
The future is not a tablet with a 9" screen no more than the future was a 9" black & white screen in a box. It’s the paradigm that survives. (Kroc Camen)
Проверь себя! Онлайн тестирование | Мой блог
mutabor вне форума Ответить с цитированием
Старый 23.12.2007, 20:43   #323
Beermonza
Инженер ИС
Старожил
 
Аватар для Beermonza
 
Регистрация: 13.12.2006
Сообщений: 2,671
Счастье Делимся опытом.

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

Код:
procedure ............MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
Х := dispX + Trunc((Mouse.CursorPos.X - Form1.Left – {поправка} ) / {ширина тайла});
Y := dispY + Trunc((Mouse.CursorPos.Y - Form1.Top – {поправка} ) / {высота тайла});

LabelX.Caption:='X: '+IntToStr(X);
LabelY.Caption:='Y: '+IntToStr(Y);
end;
… где, dispX, dispY – переменные типа Word.

Допустим, мы сдвинули карту на 5 клеток влево (карта уходит за левый конец игровой зоны), тогда область видимого уже начинается с 5-й клетки карты, расчет координат ведется от нее, т.к. ОНА у нас теперь базовая, а не 0-я.
Очень удобно использовать клавиатурный сдвиг карты. В этом случае в процедуре OnKeyDown задаются условия на границы видимого и выполняются простые прибавления к текущей "базовой" координате единицы, или вычитание. Вот пример:

Код:
procedure ………..KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin

  If key=VK_LEFT then
    Begin
      If dispX>0 then dispX:=dispX-1;
    end;

  If key=VK_RIGHT then
    Begin
      If (dispX+{число тайлов по-горизонтали}*2)-1<({размер карты по-горизонтали}*2) then dispX:=dispX+1;
    end;

  If key=VK_UP then
    Begin
      If dispY>0 then dispY:=dispY-1;
    end;

  If key=VK_DOWN then
    Begin
      If (dispY+{число тайлов по-вертикали}*2)<({размер карты по-вертикали}*2) then dispY:=dispY+1;
    end;

end;
Умножение на 2 нужно для правильного позиционирования, ведь в полоске соседние тайлы расположены через ячейку массива, значит, массив 100х100 имеет вместимость 50х50 клеток карты.
Теперь координаты будут всегда правильно определены с движением мыши, дальше действия OnClick или тот же KeyDown.

К сожалению, простого примера нет, а сложный требует множества ресурсов (по количеству конечно) и вырезать интересующие моменты не представляется возможным (очень легко запутать).
Руководитель проекта MMO 2D RPG: Настоящее имя Денис Стрижак (10.05.1981-6.02.2019) Мир духу его

Последний раз редактировалось Beermonza; 28.03.2010 в 19:26.
Beermonza вне форума Ответить с цитированием
Старый 23.12.2007, 23:59   #324
Tenray
 
Регистрация: 20.12.2007
Сообщений: 3
По умолчанию

Спасибо за подсказки, ребята.. Попробую немного переделать...
Tenray вне форума Ответить с цитированием
Старый 04.01.2008, 18:07   #325
kuzjma
Пользователь Подтвердите свой е-майл
 
Аватар для kuzjma
 
Регистрация: 02.01.2007
Сообщений: 62
По умолчанию

Привет всем, я недавно начал учить C++Builder и писать простенькую 2D игру. И мне интересно как вы будете всё это превращать в online (скажем чтоб каждый мог видеть передвижение другого игрока). Я сделал так:
1) Игрок жмёт w
2) через clientsocket/sendtext на сервер отправляется "#sendpl#(nick)#(куда, если w то - up)
3) Сервер пережевывает и кидает всем клиентам что делать (подвинуть картинку image1 на 5 вверх)
-) Всё работает, но вот пока ходит один игрок, второй не может. Если уже придумали и не жалко поделиться скажите пожалуйста.
kuzjma вне форума Ответить с цитированием
Старый 04.01.2008, 19:02   #326
Beermonza
Инженер ИС
Старожил
 
Аватар для Beermonza
 
Регистрация: 13.12.2006
Сообщений: 2,671
Счастье Делимся опытом.

Вообще, все банально просто. По стандартной схеме клиент-сервер-клиенты. Нюансы в алгоритмах приема и отправки данных.

Клиент.
Система клиента строится на дискретных пакетах. Нажав некоторую клавишу, мы создаем команду, в которой зашифрованы основные параметры:

координаты места положения,
координаты точки назначения,
сопутствующие характеристики объекта.


Команды идут не текстовые, а наборами байт (буферы). Идентификация происходит по их длине и содержимому, так же узнаются источники команд.
Проверка отправляемых команд исключает их идентичность, т.е. если много раз тыкать одну кнопку, указывая в одно и то же место, или выполняя атаку, больше раз в интервал времени чем положено, то ничего отправляться на сервер не должно. Промежуточные команды стробирования отправляются на сервер, чтобы избежать разсинхронизации.

Сервер.
Масса условий на прием и отправку должна устранять все лишнее и не нужное, снижая трафик. Например, если поступила команда от некоторого клиента, то сервер автоматически должен рассчитать область карты, в которой его можно видеть другим клиентам, и отправлять измененные координаты только клиентам, находящимся в этой области карты.
На сервере должна быть организована очередь выполнения команд, так называемая "доска объявлений". Просматривая ее, сервер сам решает что выполнять, а что можно "отсеять". Алгоритм достаточно сложный, один из вариантов строения из теории Экспертных систем.

Цитата:
Сообщение от kuzjma Посмотреть сообщение
... -) Всё работает, но вот пока ходит один игрок, второй не может. Если уже придумали и не жалко поделиться скажите пожалуйста.
По подробнее об отправке команд (у нас Delphi, но и С++ тоже можно, все понятно будет). Возможно, у Вас алгоритм построен так, что канал занимается одним клиентом, и сервер не может принимать команды других клиентов, поскольку "слушает" постоянно одного. Такого быть не должно.
Руководитель проекта MMO 2D RPG: Настоящее имя Денис Стрижак (10.05.1981-6.02.2019) Мир духу его
Beermonza вне форума Ответить с цитированием
Старый 04.01.2008, 19:29   #327
kuzjma
Пользователь Подтвердите свой е-майл
 
Аватар для kuzjma
 
Регистрация: 02.01.2007
Сообщений: 62
По умолчанию

Цитата:
Сообщение от Beermonza Посмотреть сообщение
По подробнее об отправке команд
Клиент
Код:
if (Key =='A')
{
  ClientSocket1->Socket->SendText("#sendpl#"+Edit1->Text+"#left");
}
Сервер
Код:
AnsiString msg = Socket->ReceiveText();
int p1;
p1=msg.Pos("sendpl#");

 if(p1 != 0)
 {
   ... //разбиваю msg (z = nick, z2 = действие)

    //ищу в таблице пользователя
   for(int i = 0;i <= jn_n;i++)
   {
     if(FormLog->PlOnSrv->Cells[1][i] == z)
     {
       p = i;
     }
   }

    //кординаты
   if(z2 == "left")
   {
     FormLog->PlOnSrv->Cells[3][p] = FormLog->PlOnSrv->Cells[3][p] - 5;
   }
   else if(z2 == "right")
   {
     gt = FormLog->PlOnSrv->Cells[3][p].ToInt();
     FormLog->PlOnSrv->Cells[3][p] = gt + 5;
   }
   else if(z2 == "down")
   {
     gt = FormLog->PlOnSrv->Cells[2][p].ToInt();
     FormLog->PlOnSrv->Cells[2][p] = gt + 5;
   }
   else if(z2 == "up")
   {
     FormLog->PlOnSrv->Cells[2][p] = FormLog->PlOnSrv->Cells[2][p] - 5;
   }

   //переводим из int в AnsiString и разсылаем
   pt = FormLog->PlOnSrv->Cells[2][p];
   pl = FormLog->PlOnSrv->Cells[3][p];
   p2 = p;

   for(int i=0;i<ServerSocket1->Socket->ActiveConnections;i++)
   {
 ServerSocket1->Socket->Connections[i]->SendText("#setpl#"+p2+"#"+pt+"#"+pl);
   }
 }
Клиент
Код:
...//разбиваем msg

   int zz2 = z2.ToInt();
   int zz3 = z3.ToInt();

   Image->Top = zz2;
   Image->Left = zz3;

P.S. Пожалуйста не пугайтесь моего кода, я недавно начал учить C++builder и эт единственный способ который я увидел.
kuzjma вне форума Ответить с цитированием
Старый 04.01.2008, 21:37   #328
Beermonza
Инженер ИС
Старожил
 
Аватар для Beermonza
 
Регистрация: 13.12.2006
Сообщений: 2,671
Счастье Рассуждения

Цитата:
Сообщение от kuzjma Посмотреть сообщение
Клиент
Код:
if (Key =='A')
{
  ClientSocket1->Socket->SendText("#sendpl#"+Edit1->Text+"#left");
}
Все ясно. Условие "if (Key =='A')" означает, что пока нажата клавиша "A" нужно выполнять действие – слать текстовый пакет. Ваш сервер не может принять команду от другого клиента, поскольку просто "захлебывается" командной очередью одного, ...сервер глух к другим, пока постоянно обрабатывает пакеты. Как только клавиша "А" отпущена, серверу нечего принимать и он может "услышать" того, кто в очередной раз нажмет "A", и будет выполнять только его команды.

Выход.
Использование Socket -> ReceiveText(); в Вашей процедуре сервера является ошибочным. Эта команда принимает пакет от любого из клиентов, и не дает возможности серверу "прослушать" всех клиентов, поскольку она выполняется постоянно. Следует ввести стробирование, ...создать общий цикл на число пользователей, в нем применить команду ServerSocket1-> Socket -> Connections[i] -> ReceiveText(); , т.е. слушать конкретного клиента и выполнять действия, что у Вас прописаны. Таким образом, сервер по порядку "прослушает" всех до ServerSocket1-> Socket -> ActiveConnections и перейдет опять к первому и так команды всех клиентов будут выполняться.

Но, не исключено, когда пользователей станет побольше, чем 100 понадобится синхронизация, да и не только из-за числа клиентов, сколько из-за проблем в каналах (провайдерские глюки), ...ведь от выполнения первой команды первого клиента до его второй команды (по циклу сервера) пройдет достаточно времени, чтобы на ПК клиента персонаж ушел дальше, чем его успел "передвинуть" сервер и отослать остальным.
Значительно эффективнее передавать не команду движения, а вообще, какие либо изменения в нем: движется ли еще в том же направлении или уже сменил его. Сервер при этом должен отсчитывать такт изменеий, и останавливать все действия, если при очередном "прослушивании" клиента ничего не "услышит". Кроме того, полезно ввести таймаут на выполнения "цикла прослушивания", лишние команды не нужны, если они пытаются двигать объекты быстрее, чем это заложено в анимации и физике движений.
Руководитель проекта MMO 2D RPG: Настоящее имя Денис Стрижак (10.05.1981-6.02.2019) Мир духу его
Beermonza вне форума Ответить с цитированием
Старый 04.01.2008, 22:53   #329
kuzjma
Пользователь Подтвердите свой е-майл
 
Аватар для kuzjma
 
Регистрация: 02.01.2007
Сообщений: 62
По умолчанию

Спасибо большое!
Но если вам не трудно, я вас ещё немного помучаю глупыми вопросами. Я так понял сервер должен делать примерно это?!
Код:
//event onclientread
for(int i = 0;i < ServerSocket1-> Socket -> ActiveConnections;i++)
{
  if(ServerSocket1-> Socket -> Connections[i] -> ReceiveText())
  {
     //заношу в таблицу на сервере
  }
}

...//рассылаю клиентам
*) Наверно совсем тупой вопрос, но... вы не подскажите какой командой можно создать/добавить картинку на форму?
kuzjma вне форума Ответить с цитированием
Старый 05.01.2008, 19:04   #330
Beermonza
Инженер ИС
Старожил
 
Аватар для Beermonza
 
Регистрация: 13.12.2006
Сообщений: 2,671
Счастье Код мультикомандного сервера

На Delphi процедура "прослушивания" всех клиентов выглядела бы так:

Код:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if ServerSocket1.Socket.ActiveConnections<>0 then
    begin
      for i:=0 to ServerSocket1.Socket.ActiveConnections-1 do
        begin
          text:=ServerSocket1.Socket.Connections[i].ReceiveText();
          if text<>'' then
            begin
              // тут обработка команд
            end;
        end;
    end;
end;
... мы запихиваем код в таймер, с интервалом 32 мс (если есть анимация) или 100-500 мс (если схематика, все по усмотрению). Действие кода такое: "пробегаем" по открытым каналам, если считанный пакет не пустой, то производим обработку команд. Переменная text нужна для хранения пришедшего пакета, т.к. ServerSocket1.Socket.Connections[i].ReceiveText() можно выполнить только один раз.
Думаю, на C++ переложить не трудно, как точно синтаксис я не в курсе.

Цитата:
Сообщение от kuzjma Посмотреть сообщение
*) Наверно совсем тупой вопрос, но... вы не подскажите какой командой можно создать/добавить картинку на форму?
Ну, тут нужна конкретика, ...в какую форму? ...в какой объект? ...для чего? ...какие требования?
Руководитель проекта MMO 2D RPG: Настоящее имя Денис Стрижак (10.05.1981-6.02.2019) Мир духу его

Последний раз редактировалось Beermonza; 05.01.2008 в 21:07.
Beermonza вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Уроки по созданию игр для новичков... -=DeS=- Gamedev - cоздание игр: Unity, OpenGL, DirectX 750 14.11.2017 20:26
Музыка программистов - как вы относитесь к АРИИ? Весёлый Жека Свободное общение 46 10.10.2008 22:32
Конкурсы по созданию игр на Delphi mutabor Свободное общение 0 15.06.2007 12:40
Работа по созданию ПО remix Фриланс 3 22.04.2007 11:00