1. Создания строкового типа данных
Представьте что вам нужно создать карту 10x10 причем каждая клетка будет содержать несколько параметров. Вот тут то и помогут вам типы. Вы создаете тип с именем TMap в котором будут парматры X, Y, Name$. Теперь объявляете переменную newmap(9,9) типом TMap и чтобы получить доступ к любому из парметров клетки нужно всего лишь использовать newmap(0,0)\X = значение. В blitz типы немного расширены...
Допутим вам нужно создать противника типичного которых по игре будет сотни но сколько точно вы не знаете. Вы создаете тип TPlayer с параетрами ... среди них должно быть обязательно Name$. При создании нового противника newplayer обязательно задайте Name... теперь игрок есть даже если вы удалите newplayer он содержится в TPlayer где то среди неограниченных его копий. и чтобы получить доступ к его параметрам нужно вызвать newplayer и найти нужного по Name$.
Пример объявления:
Type MyType
Field x,y
End Type
Создает тип 'MyType' с 2 парметрами - x и y.
Еще один пример:
Type MyType
Field x,y
Field description$
Field delta_x#,delta_y#
End Type
Теперь чтобы создать переменную или массив вашего типа нужно использовать символ '.' . Пример:
Global mine.MyType Dim all_mine.MyType( 100 )
До того как вы сможете использовать вашу переменную вам необходимо использовать опертор 'New'. Пример:
mine.MyType=New MyType
Оператор 'New' создает 'object' типа 'MyType', и возвращает 'pointer' новому объекту.
Для того чтобы вызвать параметры типа нужно использовать символ '\'. Пример:
mine\x=100 Print mine\x
Уничтожение переменной типа:
Когда вы закончили работу с типом через переменную используйте комманду 'Delete'. Небойтесь вся информация записана в типе а не в переменной через которую осуществляется доступ. При следеющем вызове типа через какую нибудь переменную у вас о5 появится доступ к ранее записанным данным. Пример:
Delete mine
Специальное слово 'Null' используется для проверки существования объекта. Объект несуществует если ранее не был вызван опертором 'New', или уже был стерт опертором 'Delete'. Пример:
mine.MyType=New MyType
If mine<>Null
Print "exists!"
Else
Print "doesn't exist!"
EndIf
Delete mine
If mine<>Null
Print "exists!"
Else
Print "doesn't exist!"
EndIf
...на экране появится:
exists!
doesn't exist!
Список типов динамичен и может быть просканирова при помощи множества комманд таких как Each....
Слова 'First', 'Last', 'After' и 'Before' позволяют вам работать с листом типа. Опертор 'First' позволяет осуществлять доступ к первому эллементу типа. Пример:
mine.MyType=First MyType
Тоже и с остальными оперторами.
Если тип пуст то выводится 'Null'.
Еще два опертора 'After' перебирает объекты, и 'Before' перебирает объекты в обратном порядке.
Пример:
mine.MyType=First MyType ;mine=first object in the type list
mine=After( mine ) ;mine=second object
mine=After( mine ) ;mine=third object
mine=Before( mine ) ;mine=second object
mine=Before( mine ) ;mine=first again!
'After' и 'Before' возвращают 'Null' если тип пуст или объектов дальше нет. Пример:
mine.MyType=Last MyType ;mine=last object
mine=After( mine ) ;object after last does not exist!
Так же можно вставлять опретором Insert в любое место списка. Пример:
mine1.MyType=New MyType
mine2.MyType=New MyType
Insert mine2 Before mine1
Прмер как вставить новый эллемент в начало списка:
Insert mine Before First MyType
Специальная форма For...Next позволяет вам легко проверить каждый эллемент типа в листе. Пример:
For mine.MyType=Each MyType
Next
Наконец, опертор 'Delete Each' Позволит вам удалить все эеллементы из листа типа. Пример:
Delete Each MyType
2. Анимация объектов
Почти в любой игре вы встречали анимацию, например, бег героев, врагов, вращение винта вертолёта и др. И в Blitz3D существуют специальные команды, которые позволяют воспроизводить анимацию 3D объектов. Анимационные объекты имеют "кадры" или определённые фиксированные координаты отдельных частей объекта в разные моменты времени.
Теперь поговорим об анимации объектов различных форматов. У объектов форматов 3DS и X анимируют компоненты, состоящие из примитивов, но не анимируют по вершинам и треугольникам. Но формат MD2 позволяет анимировать по отдельным вершинам и треугольникам, поэтому его используют для анимации персонажей и животных. Загрузка анимационного объекта в формате 3DS и X (при успешной загрузке, переменной возвращается адрес на объект):
перем=LoadAnimMesh("файл",[родитель] )
Воспроизвести анимацию для форматов 3DS и X. Допустимые значения для параметра режим:
1 - однократная анимация, 2 - зацикленная анимация, 3 - воспроизведение вперёд-назад, 0 - анимации нет. Скорость - параметр скорости анимации. Кадр - значение начального кадра. Задержка - пауза перед анимацией:
Animate перем,[режим],[скорость#],[кадр],[задержка#]
Функция, возвращающая время анимации объекта:
AnimTime#(перем)
Проверка на воспроизведение анимации. Функция возвращает 1, если объект анимирует и 0, если нет:
Animating(перем)
Загрузка анимационного объекта в формате MD2. Загружается такой же командой, как и неанимационный объект:
перем=LoadMD2("файл",[родитель] )
Воспроизвести анимацию MD2. Допустимые значения для параметра режим: 1 - однократная анимация, 2 - зацикленная анимация, 3 - воспроизведение впрёд-назад, 0 - анимации нет. Скорость - параметр скорости анимации. Начанльный кадр - значение начального кадра. Конечный кадр - значение конечного кадра. Задержка - пауза перед анимацией:
Animate перем,[режим],[скорость#],[начальный_кадр],[конечный_кадр],[задержка#]
Функция, возвращающая время анимации MD2 объекта:
MD2AnimTime#(перем)
Проверка на воспроизведение анимации MD2 объекта. Функция возвращает 1, если объект анимирует и 0, если нет:
MD2Animating(перем)
Чтобы воспроизводилась анимация объектов, должна присутствовать в цикле команда UpdateWorld (значение параметра скорость по-умолчанию равно 1):
UpdateWorld [скорость#]
3. Столкновение объектов
Созданные объекты при движении не будут взаимодействовать друг с другом, так как не установлены для них столкновения. Объекты будут проходить насквозь друг друга, поэтому чтобы избежать таких ситуаций, используют столкновения.
Установка режима столкновений. Используется команда Collisions, которая имеет множество параметров. Первый параметр - тип объекта (целое значение от 1 до 999), который будет сталкиваться. Второй параметр - тип объектов (целое значение от 1 до 999), об которые будут сталкиваться. Третий параметр - метод столкновения: 1 - сфера к сфере, 2 - сфера к многограннику, 3 - сфера к кубу. Четвёртый параметр - реакция сталкиваемого объекта: 1 - объект останавливается при столкновении, 2 - объект скользит при столкновении, 3 - объект скользит с трением. Общий вид команды:
Collisions тип1,тип2,метод,реакция
Чтобы объекты могли сталкиваться, нужно им применить тип (значение от 1 до 999):
EntityType перем,значение
Чтобы работала анимация, в цикле используют (та же команда для анимации объектов):
UpdateWorld
Примеры.
1 метод: метод с остановкой. Создаётся шар и конус. Тип шара - 1, а конуса - 2. В команде Collisions устанавливается первый параметр равен1, т.е. сталкивается объект с типом 1 - это шар. Второй параметр равен 2 - тип конуса, об который будет сталкиваться шар. Третий параемтр равен 2 (сфера об многогранник), лучше использовать такой метод, потому что конус - это многогранник. Последний параметр равен 1, значит, шар при столкновении остановится.
Graphics3D 640,480 ;3D графический режим
cam=CreateCamera() ;создаёт камеру
sphe=CreateSphere() ;создаёт шарик
PositionEntity sphe,4,0,8 ;позиция шарика
EntityType sphe,1 ;тип шарика
cone=CreateCone() ;создаёт конус
PositionEntity cone,-3,0,8 ;позиция конуса
EntityType cone,2 ;тип конуса
Collisions 1,2,2,1 ;устанавливает столкновения
While Not KeyHit(1)
MoveEntity sphe,-0.05,0,0
UpdateWorld ;обновляет анимацию и столкновения объектов
RenderWorld ;прорисовывает мир
Flip ;отбражает графический буфер
Wend ;конец цикла
End ;выход
2 метод: метод со скольжением. Пример ничем не отличается от первого, только последний параметр команды Collisions равен 2.
Graphics3D 640,480 ;3D графический режим
cam=CreateCamera() ;создаёт камеру
sphe=CreateSphere() ;создаёт шарик
PositionEntity sphe,4,0,8 ;позиция шарика
EntityType sphe,1 ;тип шарика
cone=CreateCone() ;создаёт конус
PositionEntity cone,-3,0,8 ;позиция конуса
EntityType cone,2 ;тип конуса
Collisions 1,2,2,2 ;устанавливает столкновения
While Not KeyHit(1)
MoveEntity sphe,-0.05,0,0
UpdateWorld ;обновляет анимацию и столкновения объектов
RenderWorld ;прорисовывает мир
Flip ;отбражает графический буфер
Wend ;конец цикла
End ;выход
3 метод: метод со скольжением и трением. Последний параметр команды Collisions равен 3.
Graphics3D 640,480 ;3D графический режим
cam=CreateCamera() ;создаёт камеру
sphe=CreateSphere() ;создаёт шарик
PositionEntity sphe,4,0,8 ;позиция шарика
EntityType sphe,1 ;тип шарика
cone=CreateCone() ;создаёт конус
PositionEntity cone,-3,0,8 ;позиция конуса
EntityType cone,2 ;тип конуса
Collisions 1,2,2,3 ;устанавливает столкновения
While Not KeyHit(1)
MoveEntity sphe,-0.05,0,0
UpdateWorld ;обновляет анимацию и столкновения объектов
RenderWorld ;прорисовывает мир
Flip ;отбражает графический буфер
Wend ;конец цикла
End ;выход
Дополнительные команды:
Отменить все столкновения:
ClearCollisions
Сбросить столкновение для определённого объекта:
ResetEntity(перем)
Установить радиус столкновения для объекта (вещественное значение) с методом столкновения сфера к сфере. Если значение меньше 1, то объект будет частично проходить другой, больше - не доходить до его поверхности.:
EntityRadius перем,знач#
Установить границу столкновения для объекта с методом столкновения сфера к кубу: x,y,z - координаты относительно объекта, а ширина, длина, высота - размер границы:
EntityBox перем,x#,y#,z#,ширина#,высота#,длина#
Функция, проверяющая произошло ли столкновение. Возвращает 1, если объекты столкнулись и 0, если нет. переменная - сталкиваемый объект, а тип - тип всех объектов, с которыми сталкивается объект:
EntityCollided(перем,тип)
Функция, возваращающая тип объекта:
GetEntityType(перем)
Функция, возваращающая количество произошедших столкновений в мире:
CountCollisions(перем)
Пример на проверку столкновений. Если первый куб столкнулся со вторым, то выходит сообщение:
Graphics3D 800,600
SetBuffer BackBuffer()
cam=CreateCamera()
cub1=CreateCube()
PositionEntity cub1,-4,0,8
EntityType cub1,125
cub2=CreateCube()
PositionEntity cub2,4,0,8
EntityType cub2,347
Collisions 347,125,1,1
Repeat
MoveEntity cub2,-0.1,0,0
UpdateWorld
RenderWorld
Flip
Until EntityCollided(cub2,125)
RuntimeError "Кубики столкнулись"
End
источник главы:blitz3d.hutz2.ru
4. Работа с файлами
В этой главе вы узнаете, как записывать и считывать данные из файлов. В Blitz3D существует три режима работы с файлами: режим записи, режим чтения и режим записи-чтения. Режим записи позволять открыть и занести значения в файл, а режим чтения считать значения из файла.
При работе с файлом присваивается переменная-идентификатор, которая характеризует его. Чтение и запись происходит последовательно, путём перемещения указателя(аналогично в банках). В режиме записи файл создаётся автоматически, если он не существует на диске. Если перед записью в файле присутствовали значения, то они перезаписываются на новые.
Внимание! Если прекращается работа с файлом в одном из режимов, то надо его закрыть, а затем можно его открыть в новом режиме.
Файл для записи открывают с помощью команды WriteFile и в скобках указывают путь в кавычках:
идентификатор_файла=WriteFile("путь")
Файл для чтения открывают с помощью команды ReadFile:
идентификатор_файла=ReadFile("путь")
Файл для записи/чтения открывают с помощью команды OpenFile:
идентификатор_файла=OpenFile("путь")
Закрыть файл:
CloseFile идентификатор_файла
Запись значений разных типов в файл (только в режиме для записи и записи/чтения).
Занести значение типа Byte:
WriteByte(идентификатор_файла,значение)
Занести значение типа Short:
WriteShort(идентификатор_файла,значение)
Занести значение типа Integer:
WriteInt(идентификатор_файла,значение)
Занести значение типа Float:
WriteFloat(идентификатор_файла,значение)
Занести значение типа String:
WriteString(идентификатор_файла,"значение")
Занести строку текста (запись текста строками, т.е. после каждой записи переход вниз) :
WriteLine(идентификатор_файла, "строка")
Занести некоторое число байт из банка в файл с некоторой позиции:
WriteBytes имя_банка,идентификатор_файла,позиция,число_байт
Чтение из файла значений разных типов (только в режиме для записи и записи/чтения).
Считать значение типа Byte:
имя_перем=ReadByte(идентификатор_файла)
Считать значение типа Short:
имя_перем=ReadShort(идентификатор_файла)
Считать значение типа Integer:
имя_перем=ReadInt(идентификатор_файла)
Считать значение типа Float:
имя_перем=ReadFloat(идентификатор_файла)
Считать значение типа String:
имя_перем=ReadString(идентификатор_файла)
Считать строку текста из файла:
имя_перем=ReadLine(идентификатор_файла)
Считать некоторое число байт из файла в банк с некоторой позицией начального байта:
ReadBytes имя_банка,имя_файла,позиция,число_байт
Работа с указателем файла. Значение начальной позиции указателя файла равно 0.
Проверка конца файла (функция возвращает 1, если конец файла и 0, если не конец файла):
Eof(идентификатор_файла)
Текущая позиция указателя файла (функция возвращает значение номера байта в данной позиции):
FilePos(идентификатор_файла)
Перенос указателя файла в нужную позицию:
SeekFile(идентификатор_файла,значение)
Пример программы на запись/чтение данных:
f=WriteFile("1.txt") ;открытие файла для записи
WriteByte(f,255) ;запись байтового значения
WriteInt(f,6500) ;запись целого значения
WriteFloat(f,0.1) ;запись вещественного значения
WriteString(f,"file") ;запись строкового значения
CloseFile(f) ;закрытие файла
f=OpenFile("1.txt") ;открытие файла для чтения
Print ReadByte( f ) ;печать байтового значения
Print ReadInt( f ) ;печать целого значения
Print ReadFloat( f ) ;печать вещественного значения
Print ReadString( f ) ;печать строкового значения
CloseFile(f) ;закрытие файла
Работа с файлами и папками.
Размер файла (функция возвращает размер файла в байтах):
FileSize(идентификатор_файла)
Проверка на существование файла (функция возвращает 0, если файл не существует; 1, если он существует и 2, если это папка):
FileType(идентификатор_файла)
Копирование файла:
CopyFile "путь1","путь2"
Удаление файла:
DeleteFile("путь")
Открытие папки для чтения:
идентификатор_папки=ReadDir("путь")
Закрытие папки для чтения:
CloseDir(идентификатор_папки)
Считать имя файла из текущей открытой папки (считывание имен файлов идет по алфавиту):
NextFile$(идентификатор_папки)
Текущий рабочий путь папки по умолчанию:
CurrentDir$()
Изменить рабочий путь папки по умолчанию:
ChangeDir$()
Удаление папки:
DeleteDir("путь")
5. Физика в игре
Большинство уважаемых читателей играло в такие шедевры игровой индустрии как DOOM, Half-Life и др.?
Наверняка вы наслаждались физикой в этих играх: реалистичным поведением и взаимодействием предметов. Тем, как катится бочка или кантуется ящик. Оказывается, такую физику можно сделать даже на Blitz. Об этом и пойдет речь в предлагаемом цикле статей.
В начале будет немного теории. Я знаю, теория не настолько интересна, как программирование. Но без нее дальше будет много непонятного. Потом коротко рассмотрим существующие физические движки. В конце приведу пример создания физического мира. Материал совсем новый, постараюсь изложить ясно и остановится на нужных моментах более подробно.
Мы не будим писать физику предметов с нуля. Это очень трудоемкий и очень долгий процесс.
Для этого существуют так называемые физические движки. Физический движок — это программа, которая рассчитывает физику предметов, сделанная для применения в играх и в других приложениях. Используется в играх как отдельный модуль для создания физического мира.
На данный момент наиболее популярны: ODE, Newton, Takomak, Havok и PhysX. ODE — бесплатный и распространяется с исходным кодом. Newton тоже бесплатный, обладает высокой стабильностью, но по этой причине, увы, проигрывает в скорости. Havok и PhysX — самые быстрые, обладают очень большим спектром возможностей. Havok знаком по игре Half–Life 2, для нее он и был разработан. К сожалению, по причине его дороговизны я не смог его оценить. На PhysX игры только начали появляться. Вот игры, которые используют этот движок:
• Tom Clancy's Ghost Recon Advanced Warfighter;
• Rise of Nations: Rise of Legends (патч);
• Bet on Soldier: Blood Sport (патч);
• Bet on Soldier: Blood Of Sahara Expansion Pack;
• CellFactor: Combat Training;
• City of Villains (патч);
• Gunship Apocalypse;
• Stoked Rider: Big Mountain Snowboarding;
• Switchball.
Остановимся на PhysX и в дальнейшем будем делать все только на нем. Почему именно он? PhysX намного быстрее других движков, очень гибок в настройках, имеет богатый спектр возможностей (их мы оценим по ходу изучения), а главное — его можно использовать бесплатно на условиях рекламы (иначе говоря, в вашей игре вы должны всеми возможными способами расхваливать PhysX, но можно поступить и иначе — просто заплатить кругленькую сумму долларов).
Если кто-то еще не знает, то PhysX был разработан компанией AGEIA для плат PhysX. Плата предназначена для ускорения просчета физики. Вот что нам обещает производитель чипа:
• динамика твердого тела;
• универсальный детектор столкновений;
• анализ конечных элементов;
• динамика мягких тел;
• движение жидкостей;
• симулятор волос и одежды;
• позволяет рассчитывать физику нескольких сотен предметов одновременно ( рис. 1).
К сожалению, в бесплатной версии половиной возможностей невозможно воспользоваться. Недоступны будут, например, движение жидкостей, симулятор волос и одежды.
Но то, что нам нужно, будет прекрасно работать и без денег. Конечно, есть недостатки: придется качать пятимегабайтный драйвер. Без него никак . PhysX не работает под «реликтовой» Windows 98 и ей подобными.
Теперь вы знаете, что такое физический движок и знаете где он применяется.
Приступим к делу. Качаем драйвера: itmbin.nm.ru/physx/physx.zip — 5 метров (самые последние дрова можно закачать на сайте support.ageia.com, там же можно узнать подробную информацию), инсталлируем. Качаем PhysX — ddownloadd.nm.ru/Blitzpx.rar (либо смотрите на сайте dev.swargo.com в файлах, там буду выкладывать уроки и последние обновления — следите за новостями). Теперь ВНИМАТЕЛЬНО: в архиве два файла — Blitzpx.dll и Blitzpx.decls. Копируем их в папку X:\Blitz3d\userlibs. Все, движок готов к использованию. Создаем в блитце новый проект.
Graphics3D 640,480
SetBuffer BackBuffer() ;создаем камеру
cam=CreateCamera()
PositionEntity cam,0,3,-10 ;создаем свет
light=CreateLight()
PositionEntity light,15,66,15 ;создаем плоскость
plane=CreatePlane()
EntityColor plane,0,200,100 ;Инициализация физики
PxCreateWorld(1) pxSetGravity(0,-10,0) ;физика кубика
cube_body = PxCreateCube(1,1,1,3,2)
pxSetPosition cube_body,0,7,0
pxSetRotation cube_body,30,0,40
cube_mesh=CreateCube()
Repeat ;расчет физики
RenderPhysic(30, 0)
pxSetEntity(cube_mesh, cube_body)
UpdateWorld()
RenderWorld()
Flip
Until KeyHit(1)
End
Теперь разберем каждую команду и все параметры функций по отдельности.
PxCreateWorld(1) — эта функция создает мир. Параметр 1 включает плоскость, с которой взаимодействуют предметы, 0 — отключает. Это самая первая команда в физике. Все остальные пишутся после.
pxSetGravity(0,-10,0) — устанавливает вектор гравитации. В нашем случае ускорение свободного падения равно 10 м/с*с и направлено к земле. По умолчанию — 9.8.
PxCreateCube(x, y, z, mass, dens) — эта функция создает параллелепипед с размерами по осям x, y, z и массой mass. Dens — плотность, пока об этом знать не обязательно, просто ставьте 1. В нашем случае мы создаем кубик с ребрами длиной 1 и массой 3.
Функции pxSetPosition body, x, y, z и pxSetRotation body, pitch, yaw, roll устанавливают кубик в точке x, y, z и разворачивают под углами pitch, yaw, roll. То есть кубик будет создан в точке 0,7,0 и развернут под углами 30,0,40.
RenderPhysic(30,0) — рассчитывает физику всех предметов в сцене. 30 — время просчета физики: чем больше время просчета, тем меньше требуется ресурсов от компьютера. 0 — синхронизация отключена, 1 — включена. Синхронизацию следует использовать, если у вас в сцене число тел не превышает 400.
pxSetEntity(cube_mesh, cube_body) — определяет каркас (меш) кубика для созданного нами физического тела. Можно обойтись без этой команды. Альтернативный способ рассмотрим потом.
В сцене можно наложить текстуры на кубик и плоскость. Это придаст реалистичный вид нашему творению. Из кубика можно сделать деревянный ящик, картонную коробку или кирпич :-). Вот что получилось у меня ( рис. 2).
Как видите, всего несколькими строчками можно описать полную физику кубика. Можете попробовать сами создать несколько кубиков. Только учтите, что кубики не должны лепиться друг на друга. Просто меняйте позицию каждого следующего тела. Вроде бы ничего сложного нет. Если возникнут вопросы — пишите. В следующий раз рассмотрим физику сферы, капсулы и некоторые настройки тел.
6. Сеть
Итак, вы решили изучить основу многих протоколов высшего уровня, то бишь ТСР? Хорошо! Чем он хорош? Гарантией того, что сообщение придет в целости и сохранности. Однако, в результате этого мы теряем скорость. Целеобразно использовать ТСР там, где надежность важнее скорости. В ином случае - используйте UDP(я уже написал туториал по нему - почитайте).
Начнем, пожалуй, с пары нюансов. Во-первых, ТСР использует архитектуру "клиент-сервер", что облегчает нам жизнь, и на нужно знать IP-адресс только сервера. Всмысле, сначала. Во-вторых, тут насчет портов такой же принцип как и в UDP. Порты до 1024 являются системными и использовать их в сетевых играх не стоит. Также следует поберечься от портов с номерами от 1024 до 49151 - они зарезервированны. Рекомендуется использовать порты с номерами от 49152 до 65535 - они динамические. В отличие от UDP, в ТСР вам надо сразу определится с портом, ибо тут нет таких вольностей, как "обнаружение свободных портов".
Рассмотрев моменты, приступим к рассмотру команд. Итак, так как в ТСР архитектура "клиент-сервер", значит у нас имеется две команды инициализации сеанса: для сервера и для клиента. Для начала давайте разберемся с сервером.
поток_сервера=CreateTCPServer(порт)
Создает сервер потока ТСР на указанный порт и возвращает хэндл потока сервера. Возвращает 0, если неудачно, поток - если удачно. Про порты уже говорилось выше. Далее, для сервера, чтобы получать и писать сообщение, надо принимать входящий поток. Делается это коммандой AcceptTCPStream вот так: поток=AcceptTCPStream(поток_сервера)
Думаю, в примере это будет смотрется понятнее:
svr=CreateTCPServer(80)
While Not KeyHit(1)
pot=AcceptTCPStream(svr)
Wend
Таким образом, мы создали сервер на порте 80. К слову, если вы на блице пишете программу для работы с сетью (броузер, почтовый клиент и т.д.), то вы конечно же можете использовать системные порты - они для того и предназначены. Однако, если вы создаете игру - берите динамический и только. Вернемся к коду. Мы каждый цикл пытаемся принять входящий поток, чтобы в цикле можно было соответственно читать и посылать информацию. Чтобы получить IP-адресс пославшего, используем функцию TCPStreamIP. Синтаксис:
переменная=TCPStreamIP(поток)
Возвращает целочисленный IP в переменную. Если вам надо получить точечный IP - смотрите в справке DottedIP$()
Также можно получить порт машины клиента функцией TCPStreamPort:
переменная=TCPStreamPort(поток)
Обьяснять, думаю не надо?
Теперь о передаче информации. А как же эта информация собственно посылается и получается? Очень просто! Вы, я думаю, уже работали с файлами, не так ли? Так вот, представьте, что ТСР-поток - это ваш файл и просто используйте команды для чтения в или из потока. Правда, с чтением есть еще один нюанс - надо проверять, пришла ли какая-то информация. Это очень просто! AcceptTCPStream возвращает 0, если ничего не пришло и поток для того, кто послал сообщение, если оно, собсно, было посланно. И нужно учесть еще вот что - человек мог сделать запрос вот таким:
WriteLine pot,"1"
WriteLine pot,"2"
WriteLine pot,"3"
Как его считать? Опять таки, очень просто! С помощью, думаю, знакомой вам функции Eof:
Eof(поток)
Возвращает False если информация в потоке еще не закончилась и True, если вся уже пришла и считана. Вот как это:
svr=CreateTCPServer(50000)
While Not KeyHit(1)
pot=AcceptTCPStream(svr)
If pot Then
While Not Eof(pot)
Print Readline$(pot)
Wend
Endif
Wend
Чтобы написать игроку, нужно писать именно на уникальный поток. Сейчас я вам покажу, как собсно получить этот поток:
Type Player
Field stream
End Type
svr=CreateTCPServer(50000)
While Not Keyhit(1)
pot=AcceptTCPStream(svr)
If pot Then
p.Player=New Player
p\stream=pot
Endif
Wend
Далее, чтобы получать сообщения не от новых игроков, а от тех, что уже записаны, используем следующую схему:
For p.Player=Each Player
If ReadAvail(p\stream) Then
...
Endif
Next
Думаю, все ясно как пень. Самая сложная часть позади. Теперь давайте о клиенте.
Подключается он командой OpenTCPStream. Синтаксис:
поток=OpenTCPStream(IP_сервера,порт)
Возвращает 0 если неуспешно, и поток - если успешно. Тут все проще, нежели у сервера. Просто посылаем информацию на этот же поток и все! Для наглядности пример:
pot=OpenTCPStream("prevedmedved.ru",80)
WriteLine pot,"PREVED!"
Вот и все! Что еще хотелось бы сказать, так это насчет посылания сообщения другим клиентам. Так вот. ВСЕ передается через сервер. Вот так вот. Если надо послать мэссагу кому-то одному - шлем запрос серверу. Хотим всем - шлем запрос к серверу. И сервер должен все эти запросы отрабатывать.
Вот и закончили мы долбить второй основной протокол, поддерживаемый блицем. А что это нам дает? Очень многое. Ведь нам открывается дорога к протоколам более высокого уровня. Но об этом в следующих статьях.