Blender GameKit 2/Basic Networking with Game Blender

Материал из Blender3D.

Перейти к: навигация, поиск

Основы Использования Сети в Blender - Сделай это просто от "Old Jim" Coulter

Автор: "Old jim" Coulter

Оригинал статьи в PDF

Создание игр как и игра в них интересное и увлекающее занятие, но гораздо более увлекательным оно становится когда вы можете создавать играть в которые можно играть вместе с друзьями. Я покажу вам как "приготовить" основные вещи для работы с сетью в Blender. Так как Игровой Движек Blender не имеет встроенной поддержки сети нам нужно будет реализовывать это с помощью Pyrhon. Вам потребуется установленная версия Python, подходящая для вашей версии Blender. Обратите более пристальное внимание к информации выводящейся в терминале или в dos-box при старте Blender. Там будет указанна какая версия Python вам нужна и работает ли импорт.

Ингридиенты:

  • IP: Уникальный адрес компьютера
  • LAN IP: Доступен только внутри локальной сети
  • Internet IP: Доступен из любой точки мира (когда маршрутизаторы и FireWall-ы позволяют это)
  • Порт: Точка доступа к определенному приложению
  • Socket: Станция приема-передачи
  • Библиотеки: Подключаемые "Поваренные книги" (модули) из набора библиотек Python говорящие Blender как готовить пищу определенного вида
  • Логические Блоки: центральная станция управления в Blender
  • Объекты: Мы будем работать с двумя Кубами, которые сможем перемещать по сцене и эти перемещения будут передаваться по сети.

Если вы загрузите файл BasicNetwork.blend то сможете найти в нем 2 скрипты - Server.py и Client.py. Они демонстрируют как работает сеть, если разложить ее до самых основ. Что же они делают?


Server.py:

#------------SETUP--------------#
1.from GameLogic import *
2.from socket import *
3.from cPickle import *
4.cont = GameLogic.getCurrentController()
5.obj = cont.getOwner()
6.if obj.OneTime == 0:
7.  Host = ''
8.  ServerPort = 10000
9.  GameLogic.sServer = socket(AF_INET,SOCK_DGRAM)
10.    GameLogic.sServer.bind((Host,ServerPort))
11.    GameLogic.sServer.setblocking(0)
12.    obj.OneTime = 1
13.PosYou = obj.getPosition()
14. scene = getCurrentScene()
15.Client = scene.getObjectList()["OBClient"]
16.PosClient = [0,0,0]
#------------RECEIVE/SEND--------------#
17.try:
18.   Data, CLIP = GameLogic.sServer.recvfrom(1024)
19.   UPData = loads(Data)
20.   PosClient = [UPData[0],UPData[1],UPData[2]]
21.   Client.setPosition(PosClient)
22.   Data = dumps((PosYou))
23.   GameLogic.sServer.sendto(Data,CLIP)
24.except:
25.   pass


1. from GameLogic import *
Из библиотеки мы берем (мипортируем) книгу (модуль), называющуюся GameLogic. Импортируя эту книгу мы получаем всю информацию об Игровом Движке Blender.


2. from socket import *
Эта книга (модуль) дает нам всю информацию о создании и использовании сетевых сокетов


3. from cPickle import *
Здесь мы получаем информацию как упаковывать данные в контейнер (похоже на использование программы zip-архивации)


4. cont = getCurrentController()
Эта команда берет Controller из скрипта и сохраняет его в переменную count. Логический блок, который мы только что сделали доступным, это Controller, котрый задает правила исполнения python-скрипта.

This command gets the Controller for the script and saves it to the variable cont. The logic brick we just made accessible, is the Controller that gave the order to execute the python script.


5. Obj = Cont.getOwner()
Делает нас владельцами скрипта. Obj будет объектом, владеющим Логическими Блоками. Gets us the owner of this script. That would be the object that owns the logic brick.


6. if Obj.OneTime == 0:
12. Obj.OneTime = 1
Строка 6 вызывает свойство OneTime и если его значение равно 0 - будут выполнены строки с отступом ниже. Строка 12 изменит значение свойства OneTime на 1. Изменяя этот параметр мы можем быть уверенны что строки с отступом, ниже строки 5, будут выполнены только один раз.


7. host =
Сохраняет пустое текстовое значение в переменную host. Целью создания этого пустого текстового хранилища является создание места, куда в дальнейшем возможно будет поместить уникальный адрес компьютера. Вы, возможно, захотите спросить - "Почему бы просто не записать адрес компьютера прямо здесь?". Вы, конечно, можете это сделать, но в таком случае этот скрипт будет работать только на вашем компьютере. Поэтому мы оставляем эту переменную пустой и позволим сокету заполнить это значение самостоятельно. У вас так же будет возможность указать localhost в поле, между " ' ' ", что укажет скрипту использовать адрес того же компьютера, на котором он запущен. Но зачем писать сейчас больше, чем требуется?


8. ServerPort = 10000
Записывает значение 10000 в переменную ServerPort. Это значение будет являться номером порта, через который сокет производить взаимодействие и передачу данных. Вы должны убедиться что фаш FireWall или роутер не блокируют этот и другие порты, которые мы добавим позже. Информация о том, как настроить ваш FireWall и роутер на передачу нужных портов вы можете найти в документации на них. Если у вас возникают какие то вопросы по этой части, вы можете задать их на форуме gameblender.org и blender3d.org.ua.


9. GameLogic.sServer = socket(AF_INET,SOCK_DGRAM)
В этой строке создается сокет, который будет использовать протокол, указанный в скобках и этот сокет будет сохранен в глобальной переменной GameLogic.sServer.
AF_INET,SOCK_DGRAM - это определение UDP протокола. Мы будем использовать это протокол потому что он очень быстр и продолжает работать, даже если в какой то момент он не может получить или принять несколько пакетов.


10. GameLogic.sServer.bind((Host,ServerPort))
Код .bind((host,Serverport)) используется для передачи значений, которые мы сохранили в переменных host и Serverport в сокет. Теперь сокет знает через какой адрес и через какой порт он должен производить взаимодействие.


11. GameLogic.sServer.setblocking(0)
Сокет начал работать еще в предидущей строке. Но как я уже говорит в коментарии к 8 строке мы хотим быть уверенными что скрипт продолжит работать, даже если сокету не удастся получить или передать данные. А это может произойти очень просто. Например, у вас проблему с сетевым соединением, или у сервер и клиента разные скорости получения/передачи данных в сеть, или подключение используется другим приложением ... Именно по этому мы используем .setblocking(0). 0 указывает скрипту не останавливать выполнение, даже если он не может передать или получить данные. Если вы здесь укажите 1 скрипт будет пытаться передать или получить пакет, пока эти попытки не увенчаются успехом. И тогда все будет работать настолько бастро, насколько быстро может работать самый медленный клиент, подключенный к серверу.


13. PosYou = obj.getPosition()
Получение позиции серверного куба (сервер контролирует синий куб)


14. scene = getCurrentScene()
15. Client = scene.getObjectList()["OBClient"]
Команда getCurrenScene() передаст все элементы сцены в скрипт. Эти элементы будут сохранены в переменной scene. Теперь переменная scene содержит все элементы текущей сцены и мы хотим получить доступ ко всем Объектам в сцене. Это делается командой .getObjectList(). В квадратных скобках указывается имя того объекта, который вы хотим сохранить в переменной objPump1. Очень важно что бы вы поместили буквы "OB" перед именем объекта.


16. PosClient = [0,0,0]
В переменной PosClient мы сохраняем три элемента. В дальнейшем эти три элементы будут заменены координатами игрока. Эти три элемента [0,0,0] представляют собой координаты X, Y и Z объекта.


17. try:
В строке 17 производиться попытка выполнить строки с отступом идущие ниже. Если одна из этих строк выполняется неудачно то управление передается в строку 24 и 25 которые посто пропускают неудачное выполнение и дают команду выполнять программу дальше (pass). Единственная строка, которая действительно может выполниться неудачно - это строка 18. Такое может произойти при попытке скрипта получить данные когда данные никем не посылаются. Например, когда ни один клиент не передает никаких данных.


18. Data, CLIP = GameLogic.sServer.recvfrom(1024)
Переменная GameLogic.sServer содержит информацию о сокете. Код .recvfrom дает команду сокету получить данные. Параметр (1024) определяет максимальный объем, которы буфер может получить за раз. Каждый раз, когда мы получаем данные мы получаем два блока. Первый блок содержит данные и сохраняется в переменную Data. Второй блок содержит адрес отправителя и сохрпняется в переменную CLIP (= Client IP).


19. UPData = loads(Data)
Сейчас мы впервые воспользуемся методом из модуля cPickle. Полученные данные распаковываюься и сохраняются в переменную UPData. Как вы можете заметить в строке 22, данные переда отправкой в сеть упаковываются в контейнер.


20. PosClient = [UPData[0],UPData[1],UPData[2]]
Полученные и распакованные данные сохраняются в список, соданные в строке 16.
UPData[0] = Позиция по глобальной оси X
UPData[1] = Позиция по глобальной оси Y
UPData[2] = Позиция по глобальной оси Z


21. Client.setPosition(PosClient)
Список координат, который мы только что заполнили, используется для установки координат объекта клиента.


22. Data = dumps((PosYou))
Команда dumps упакует любые данные, находящиеся в двойных круглых скобках в контейнер и сохранит его в переменну Data. Важно: здесь вы должны использовать именно двойные круглые скобки "((PosYou))"! Переменная PosYou, которую мы здесь упаковывает, содержит координаты Серверного куба (голубого) которые мы получили в строке 13.


23. GameLogic.sServer.sendto(Data,CLIP)
Для отправки данных из переменной Data командой GamLogic.sServver мы вызываем Сокет и даем ему команду .sendto. Для отправки данных, как и в строке 18, нам понадобится 2 вещи: сами данные и адрес, куда эти данные должны придти. This information you put inside the brackets.


24.except:
25. pass

These lines work together with line 17 and already where explained. The client script.py is very similar to the server.py script, the only real difference is that it sends data to the server first, so it dose not have an already received package that contains the servers address; so this will have to be entered manually. We do this in the script setup.py line 10. By entering the servers IP address there behind the global variable GameLogic.IP. If you now study the script below you may say he way not just write it in to line 7 instead of putting the global variable GameLogic.IP there. You are right, you can do so but by having the IP entering in the setup.py script it makes it easier to find it. Also the setup.py script contains other informations that help a user to start this program in any network. See lines that are behind a comment mark тАЬ#тАЭ. They are not part of the script, but give you information on how to use this script. So thatтАЩs why we will have the 3D window on the left side and the setup.py script on the right side when we open the BasicNetwork.blend file.


Client.py:
#------------SETUP--------------#
1.from GameLogic import *
2.from socket import *
3.from cPickle import *
4.cont = GameLogic.getCurrentController()
5.obj = cont.getOwner()
6.if obj.OneTime == 0:
7.  ServerIP = GameLogic.IP
8.  Serverport = 10000
9.  Clientname = ''
10. 
ClientPort = 10001
11. 
GameLogic.sClient = socket(AF_INET,SOCK_DGRAM)
12. 
GameLogic.sClient.bind((Clientname,ClientPort))
13. 
GameLogic.host = (ServerIP,Serverport)
14. 
GameLogic.sClient.setblocking(0)
15. 
obj.OneTime = 1
16.PosYou = obj.getPosition()
17.scene = getCurrentScene()
18.Server = scene.getObjectList()["OBServer"]
19.PosServer = [0,0,0]
#------------RECEIVE/SEND--------------#
20.Data = dumps((PosYou))
21.GameLogic.sClient.sendto(Data,GameLogic.host)
22.try:
23. 
Data, SRIP = GameLogic.sClient.recvfrom(1024)
24. 
UPData = loads(Data)
25. 
PosServer = [UPData[0],UPData[1],UPData[2]]
26. 
Server.setPosition(PosServer)
27. 
Server.setOrientation(OriServer)
28. except:
29. 
pass
Since all the commands in this script where explained in the server.py script I will only give a short 
summary on these lines of code:
Lines 1 тАУ 5: Basic setup to access the Object, its properties and logic bricks
Lines 6 + 15: Make sure that the intended lines below Line 6 only run once.
Line 7: Saves the global Variable that contains the IP to a local Variable.
Lines 8 тАУ 12: Setup the Socket
Line 13: Saves the complete Server address to a variable.
Line 14: Tells the script to just keep running even if no data was send/received.
Line 16: Gets the position of the red cube.
Line 17 + 18: Make the blue cube accessible by this script.
Line 19: Makes a empty list, that will be uses to set the servers cube (blue cube)
Line 20 + 21: Packs your position in a container and sends it to the server.
Line 22, 28,29: Will try to run the intended lines below line 22, if they fail the script will just pass on.
Appetite for more
I hope this little starter whetted your appetite for more. There is a more complete tutorial on the DVD 
(Blends/WSAGNetwork/PumpkinRun_MP.blend) and a lot of information about more 
complex network тАЮmealsтАЬ can be found at www.wsag.ch.vu. If any questions come up you can ask 
them at the gameblender.org forum.

</pre>

Личные инструменты