Форум программистов, компьютерный форум, киберфорум
Программирование игр
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.98/49: Рейтинг темы: голосов - 49, средняя оценка - 4.98
4176 / 2282 / 387
Регистрация: 05.10.2013
Сообщений: 6,385
Записей в блоге: 177
1

Создание игры "Battle City" (танчики) на BGE

26.02.2015, 15:44. Просмотров 9960. Ответов 56
Метки нет (Все метки)

Привет!

Хочу написать танчики на BGE с целью лучше узнать API движка. До применения API и Python пока далеко. Проблема в самом начале: не могу придумать, как сделать анимацию движения танка на спрайтах. Могу наложить текстуру и двигать площадку, а вот как менять текстуры и организовать удобно всё это - ума не приложу. Хочу делать сначала на Logic Bricks, а потом писать на Python, но только то, что действительно проще на нём (или только эта возможность и есть)

Я записал небольшое видео. Мне кажется, уже на этапе, показанном в видео, много ошибок. Посмотрите, пожалуйста: Battle City in BGE. Attempt number 1
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
26.02.2015, 15:44
Ответы с готовыми решениями:

Как написать Battle city (танчики)
Задали писать игру Battle city (танчики), сам не осиливаю помоги кто чем может.очень нужно

С помощью каких библиотек писать игру "Battle City"?
Собрался написать игру Battle City на С++. Какие библиотеки для этого лучше подойдут?

необходимо задать услоовие: если переменная $city["id"] есть, выводится $city["city"]
Здравствуйте. Внезапно залип на фигне, не могу такое сделать: нужно, чтобы если переменная...

Есть библиотеки для создания 2D игр? Таких как танчики (Battle City) или Марио?
Есть библиотеки для создания 2D игр? Таких как танчики (Battle City) или Марио?

56
58 / 57 / 15
Регистрация: 15.09.2012
Сообщений: 555
09.01.2017, 21:17 41
Fulcrum_013, это тоже по сути не решает проблемы - тут две стороны при большом пинге : или более реальное положение обьектов и хуже сглаживание или хорошее сглаживание и больший промах в реальном положении игрока. там где недопустимо переезд игрока дальше реального положение, например на сервере игрок подошел к обрыву а на клиенте он упадет, там всегда будут рывки.
0
4176 / 2282 / 387
Регистрация: 05.10.2013
Сообщений: 6,385
Записей в блоге: 177
09.01.2017, 22:04  [ТС] 42
Цитата Сообщение от ASDFD12 Посмотреть сообщение
в этой игре http://curvefever.io - черви двигаются постоянно и еще и с равномерной скоростью - это идеальный вариант для скрытия большого пинга - движение даже не нужно синхронизировать - просто передавать в какую сторону нужно повернуть персонажа.
Каково ваше мнение по поводу этой игры: http://tanx.io/

Добавлено через 8 минут
Я узнал, что она сделана на бесплатном html5 игровом движке PlayCanvas. А на сервере игра использует бесплатный игровой сервер на Node.js (с открытыми исходниками), который называется Colyseus
0
58 / 57 / 15
Регистрация: 15.09.2012
Сообщений: 555
09.01.2017, 22:20 43
8Observer8, если по самой игре - то все сделано на высоком уровне) по поводу синхронизации, иногда если присмотреться то вижу рывки даже на своем танке - это особенно если двигаться по прямой линии, то есть при команде на движение сервер вычисляет положение, присылает клиенту и только потом клиент двигается в эту точку.
1
2050 / 1525 / 167
Регистрация: 14.12.2014
Сообщений: 13,326
09.01.2017, 22:32 44
Цитата Сообщение от 8Observer8 Посмотреть сообщение
Каково ваше мнение по поводу этой игры: http://tanx.io/
Как понимаю cиcтема коллизий по массиву высот? Ну в принципе простенько. но симпатичненько. Стреляют слишком часто. было бы время перезарядки было бы повеселее

Добавлено через 7 минут
Цитата Сообщение от ASDFD12 Посмотреть сообщение
то есть при команде на движение сервер вычисляет положение, присылает клиенту и только потом клиент двигается в эту точку.
Кстати танчики от варгаминга делают точно так же. Но они точно снапшоты по UDP сокету шлют и в бинарном виде. А WebSoсket как понимаю по TCP и в XML. Размер пакета в результате в десятки раз больше. Плюс ожидание подтверждения доставки плюс если не влез в один TCP пакет ожидание доставки всех и сборка по порядку. Если какой то не дошел перепосылка хотя он уже не актуален по большому счету. Отсюда и рывки по всей видимости при потерянном или задержавшемся пакете. Бинаркой по UDP за это время успевается несколько тиков передать посему если один выпал не страшно.
0
4176 / 2282 / 387
Регистрация: 05.10.2013
Сообщений: 6,385
Записей в блоге: 177
09.01.2017, 22:45  [ТС] 45
Цитата Сообщение от ASDFD12 Посмотреть сообщение
по поводу синхронизации, иногда если присмотреться то вижу рывки даже на своем танке
Я думаю, что это не из-за node.js, а из-за не слишком хорошей реализации. Реально сейчас скорость работы node.js настолько высокая, что всё упирается в сетевые задержки и логику реализации сбособов их компенсации, чтобы сделать их наименее заметными для игроков. По логике так получается и в книге так написано: Многопользовательские игры. Разработка сетевых приложений - Джошуа Глейзер, Санджай Мадхав Там про node.js тоже в конце написано. Мне ещё он нравится тем, что можно на heroku.com создать 5 приложений бесплатно. На клиенте и на сервере пишу на одном языке на TypeScript. По методам компенсации задержек если что найдёте, то дайте знать.

Добавлено через 3 минуты
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Как понимаю cиcтема коллизий по массиву высот?
Как я понимаю, там свой физический движок вшитый в игровой движок PlayCanvas. Программисту игры, я думаю, недоступно, как реализована система коллизий. По-мойму, движок PlayCanvas без отрытых исходников. Могу ошибаться. Это только моё предположение.

Добавлено через 2 минуты
А нет, вот исходники движка: https://github.com/playcanvas/engine

Но всё равно, в таких движках физический движок описан только на уровне документации и обычно мало кто лезет. Вот тут в документации описано, что представляет физический движок: http://developer.playcanvas.co... l/physics/
0
2050 / 1525 / 167
Регистрация: 14.12.2014
Сообщений: 13,326
09.01.2017, 23:39 46
Цитата Сообщение от 8Observer8 Посмотреть сообщение
что всё упирается в сетевые задержки и логику реализации сбособов их компенсации,
Вот об этом и речь. Вернее о том что websocket по определению сильно проигрывает бинарной передаче через UDP. При этом выпавший пакет у UDP вызывает гораздо меньшую задержку чем пересылка выпавшего пакета по TCP. Т.е. сами говорили - есть предел задержки при которых произойдет рассогласование состояний на сервере и в клиенте и по большому счету оно никак кроме как скоростью связи не решается.

Добавлено через 12 минут
Цитата Сообщение от 8Observer8 Посмотреть сообщение
Вот тут в документации описано, что представляет физический движок:
коллизии там похоже на AABB. Хотя в принципе карта проходимости/высот там просто напрашивается, а тем боле что карта тайлов там есть по любому. Да и AABB коллизии можно при помощи карты очень ускорить, отсеяв те объекты которые заведомо не могут столкнуться (находятся в абсолютно разных тайлах).
1
4176 / 2282 / 387
Регистрация: 05.10.2013
Сообщений: 6,385
Записей в блоге: 177
17.01.2017, 00:37  [ТС] 47
ASDFD12, я воспроизвёл дизайн вашей карты. Пока без мультиплеера, танк едет поверх блоков, можно только осмотреть карту: https://tanks2d.herokuapp.com/

Правда, там нескольких блоков не хватает, потому что пока я делал скриншоты кто-то заходил, портил, и мой танк пытался взорвать

Заодно познакомился, как использовать совместно Tiled Map Editor, Phaser+TypeScript, Texture Packer. Для Unity пришлось активировать триал версию на 7 дней для Texture Packer Pro. Из Tiled экспортировал в csv формат, а по нему уже раставляю префабы в Unity. А так очень удобные инструменты. Позволяют быстро создавать карты и отделить работу Левел Дизайнера и программиста. Хочу купить Texture Packer Pro + есть бесплатный экспортёр в Unity на Asset Store. Texture Packer Pro стоит в районе 2000 рублей. Очень удобный и эффективный инструмент для Unity.

Я больше сосредоточусь на Unity + UNet, так как в Phaser уйдёт больше времени и UNet мне понравился. Он больше подходит для такого типа игр и в нём как раз можно делать комнаты на небольшое кол-во человек, не больше 20.
0
58 / 57 / 15
Регистрация: 15.09.2012
Сообщений: 555
17.01.2017, 10:35 48
8Observer8, жду тогда мультиплееп) неплохой подход для редизайна. Texture Packer Pro можно спокойно заменить стандартным юнитивским sprite editor, он также прекрасно делает атласы. А UNet фри лицензия только 20 коннектов.
0
4176 / 2282 / 387
Регистрация: 05.10.2013
Сообщений: 6,385
Записей в блоге: 177
17.01.2017, 12:25  [ТС] 49
Цитата Сообщение от ASDFD12 Посмотреть сообщение
А UNet фри лицензия только 20 коннектов.
Может быть на одну комнату 20? Даже если для всей игры, то на UNet можно создать Headless сервер, написать свой Match Macker и использовать Low Level API, тогда можно делать сколько угодно коннектов (я находил такую инфу на форуме forum.unity3d) Я пробовал собирать Headless сервер для Linux (Mint, Ubuntu), запускал на Virtual Box и соединялся с ним из клиентов. Я могу сделать две комнаты по 10 человек. Вряд ли они в ближайшее время заполнятся, а я пока освою UNet, а потом и народу будет всё больше и уже всё чаще больше 20, то я к тому времени должен буду реализовать свой Headless сервер и арендовать VPS с Ubuntu.

Цитата Сообщение от ASDFD12 Посмотреть сообщение
Texture Packer Pro можно спокойно заменить стандартным юнитивским sprite editor, он также прекрасно делает атласы.
Никак не могу заменить, потому что он универсальный и я его использую как для Unity, так и для Phaser (и ещё для PixiJS). Texture Packer Pro мне здорово экономит время. Он очень компактно упаковывает тайлы и в один клик я получаю нарезку и названия тайлов и спрайтов для Unity, Phaser и PixiJS

Цитата Сообщение от ASDFD12 Посмотреть сообщение
жду тогда мультиплееп
Я буду делать две версии мультипреера: одну версию в виде клиентов на UNet для настольных ПК, а другую версию - универсальную на Phaser + игровой сервер Colyseus. Она будет запускаться, там где есть браузер ПК, Android и iOS. Я думаю, это будет отличный вариант, так как игровой фреймворк Phaser использует супер быстрый графический движок PixiJS, который оптимизирован для мобильных платформ.

Я пробовал тестить UNet. Меня удивило, что даже с моим пингом в 150 мс движения довольно плавные. Причём, я пробовал ставить в настройках отправку синхронизирующих сообщений с частотой 9 и 16 пакетов в секунду, всё равно работает одинаково замечательно.
0
58 / 57 / 15
Регистрация: 15.09.2012
Сообщений: 555
17.01.2017, 12:36 50
Цитата Сообщение от 8Observer8 Посмотреть сообщение
Я пробовал тестить UNet. Меня удивило, что даже с моим пингом в 150 мс движения довольно плавные
тогда надо б их исходники посмотреть по сглаживанию

Добавлено через 4 минуты
Цитата Сообщение от 8Observer8 Посмотреть сообщение
Даже если для всей игры, то на UNet можно создать Headless сервер, написать свой Match Macker и использовать Low Level API, тогда можно делать сколько угодно коннектов (я находил такую инфу на форуме forum.unity3d)
можно ссылку, если найдете.
0
4176 / 2282 / 387
Регистрация: 05.10.2013
Сообщений: 6,385
Записей в блоге: 177
18.01.2017, 14:35  [ТС] 51
Цитата Сообщение от ASDFD12 Посмотреть сообщение
Texture Packer Pro можно спокойно заменить стандартным юнитивским sprite editor, он также прекрасно делает атласы.
В Texture Packer Pro есть большая куча настроек и ещё он добавляет настройки в стандартный Sprite Editor. Я, правда, пока в них ничего не понимаю Да, в Unity ещё есть свой встроенный упаковщик (Window->Sprite Packer). Но есть проблема блидинга (просвет и засветка между тайлами), её можно решить только если добавить обводку в хотя бы один пиксель вокруг каждого тайла. Раньше я это делал с помощью плагина GIMP (перед тем как нашёл этот плагин - написал свой на Python), а Texture Packer Pro добавляет их сам:
0
Миниатюры
Создание игры "Battle City" (танчики) на BGE  
4176 / 2282 / 387
Регистрация: 05.10.2013
Сообщений: 6,385
Записей в блоге: 177
17.12.2020, 12:20  [ТС] 52
После большого перерыва возвращаюсь к написанию клона Battle City по сети. Многие вещи глобально переосмыслил. Одно время была мысль, что выгодно взять Unity и C#, а ещё также реализовать версию на C# и OpenGL, чтобы за одно тренироваться с C# и практиковаться с шейдерами на чистом OpenGL. Но всегда зудела мысль, что C++ быстрее. Чистый C++ не так удобен, как C#, но зато есть такой же удобный Qt C++. Qt C++ гораздо более удобный для OpenGL, чем C#, потому что на C# нужно использовать отдельную библиотеку OpenTK от группы энтузиастов, а Qt включает в себя поддержку OpenGL на официальном уровне. Qt включает в себя: парсеры Json/Xml, загрузку текстур, матрицы, сеть, базы данных и многое другое. По Qt много вакансий и поэтому на него выгодно тратить время в отличие от других библиотек для окон: GLFW, SDL2 и т.д. Это сугубо моя точка зрения. На Qt можно легко собирать в APK и под Android и iOS. Второй важный момент - это версии игр для веб на WebGL, чтобы была возможность запустить игру в один клик прямов в браузере, без скачиваний, проверок на вирус, распаковок и т.д. Если кто-то захочет начать изучать шейдерный OpenGL и WebGL, то советую начать с этой книги: WebGL. Программирование трехмерной графики | Мацуда Коичи, Ли Роджер. Здесь примеры: Небольшие примеры на WebGL Игра должна быть в трёх версиях: Desktop, Mobile и Web.

В Qt встроена поддержка вебсокетов. Сервер я буду писать на Node.js с хостингом на бесплатном Heroku. Для сервера я использую пакет для вебсокетов: https://www.npmjs.com/package/ws Этот пакет очень популярен - за неделю более 35 млн. установок. Для упаковки спрайтов в текстурный атлас я использую Texture Packer Pro. Я купил эту программу несколько лет назад. Это программа упаковывает спрайты на атлас и генерирует два файла: атлас (png) и данные о спрайтах (.json). В JSON хранятся характеристики спрайтов: координаты на атласе, ширина, высота и т.д. Парсер JSON встроен в Qt и в JavaScript.

Оставлю здесь полезный пример парсинга JSON на Qt из консольного приложения:

Входной файл: Person.js

JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
  "firstName": "John",
  "lastName": "Smith",
  "isAlive": true,
  "age": 27,
  "address": {
    "streetAddress": "21 2nd Street",
    "city": "New York",
    "state": "NY",
    "postalCode": "10021-3100"
  },
  "phoneNumbers": [
    {
      "type": "home",
      "number": "212 555-1234"
    },
    {
      "type": "office",
      "number": "646 555-4567"
    }
  ],
  "children": [],
  "spouse": null
}


main.cpp

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <QtCore/QCoreApplication>
#include <QtCore/QFile>
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject>
#include <QtCore/QJsonArray>
#include <QtCore/QDebug>
 
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
 
    QFile jsonFile(":/JsonFiles/Person.json");
    jsonFile.open(QIODevice::ReadOnly);
 
    // Get a first name and a last name
    QByteArray data = jsonFile.readAll();
    QJsonDocument jsonDoc(QJsonDocument::fromJson(data));
    QJsonObject jsonObj = jsonDoc.object();
    qDebug() << jsonObj["firstName"].toString();
    qDebug() << jsonObj["lastName"].toString();
 
    // Get a phone number
    QJsonArray jsonArray = jsonObj["phoneNumbers"].toArray();
    qDebug() << jsonArray[0].toObject()["number"].toString();
 
    jsonFile.close();
    return a.exec();
}
Вывод программы в консоль:

"John"
"Smith"
"212 555-1234"
0
4176 / 2282 / 387
Регистрация: 05.10.2013
Сообщений: 6,385
Записей в блоге: 177
17.12.2020, 15:41  [ТС] 53
TexturePacker оказывается написан на Qt:

Создание игры "Battle City" (танчики) на BGE


Я создал Sprite Sheet следующим образом. Нашёл в интернете набор тайлов игры (Tile Set). Нарезал в GIMP спрайты:

Создание игры "Battle City" (танчики) на BGE


Эти спрайты перенёс мышкой в TexturePacker:

Название: 664dbe24-c244-45c3-b24a-f022f2a602c1.png
Просмотров: 71

Размер: 9.1 Кб

TexturePacker упаковал спрайты в один Sprite Sheet. Я нажал кнопку "Publish sprite sheet" и было сгенерировано два файла: сам Sprite Sheet, в виде png-файла, и файл json, по которому можно узнать текстурные координаты и размеры спрайтов:

Название: 66982037-e624-4118-ade9-2865d2739742.png
Просмотров: 69

Размер: 673 байт

JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
{"frames": {
 
"tank_yellow_small_down_01.png":
{
    "frame": {"x":0,"y":0,"w":32,"h":32},
    "rotated": false,
    "trimmed": false,
    "spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
    "sourceSize": {"w":32,"h":32},
    "pivot": {"x":0.5,"y":0.5}
},
"tank_yellow_small_down_02.png":
{
    "frame": {"x":32,"y":0,"w":32,"h":32},
    "rotated": false,
    "trimmed": false,
    "spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
    "sourceSize": {"w":32,"h":32},
    "pivot": {"x":0.5,"y":0.5}
},
"tank_yellow_small_left_01.png":
{
    "frame": {"x":64,"y":0,"w":32,"h":32},
    "rotated": false,
    "trimmed": false,
    "spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
    "sourceSize": {"w":32,"h":32},
    "pivot": {"x":0.5,"y":0.5}
},
"tank_yellow_small_left_02.png":
{
    "frame": {"x":96,"y":0,"w":32,"h":32},
    "rotated": false,
    "trimmed": false,
    "spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
    "sourceSize": {"w":32,"h":32},
    "pivot": {"x":0.5,"y":0.5}
},
"tank_yellow_small_right_01.png":
{
    "frame": {"x":128,"y":0,"w":32,"h":32},
    "rotated": false,
    "trimmed": false,
    "spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
    "sourceSize": {"w":32,"h":32},
    "pivot": {"x":0.5,"y":0.5}
},
"tank_yellow_small_right_02.png":
{
    "frame": {"x":160,"y":0,"w":32,"h":32},
    "rotated": false,
    "trimmed": false,
    "spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
    "sourceSize": {"w":32,"h":32},
    "pivot": {"x":0.5,"y":0.5}
},
"tank_yellow_small_up_01.png":
{
    "frame": {"x":192,"y":0,"w":32,"h":32},
    "rotated": false,
    "trimmed": false,
    "spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
    "sourceSize": {"w":32,"h":32},
    "pivot": {"x":0.5,"y":0.5}
},
"tank_yellow_small_up_02.png":
{
    "frame": {"x":224,"y":0,"w":32,"h":32},
    "rotated": false,
    "trimmed": false,
    "spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
    "sourceSize": {"w":32,"h":32},
    "pivot": {"x":0.5,"y":0.5}
}},
"meta": {
    "app": "http://www.codeandweb.com/texturepacker",
    "version": "1.0",
    "image": "battle_city_tiles.png",
    "format": "RGBA8888",
    "size": {"w":256,"h":32},
    "scale": "1",
    "smartupdate": "$TexturePacker:SmartUpdate:ae1aaf8438413a614c6bc943a72c42c1:dde6a5be5dfe368d565574779e47cbd7:e2a7b58ac8aa2d4914a37feebbfe8a71$"
}
}
0
4176 / 2282 / 387
Регистрация: 05.10.2013
Сообщений: 6,385
Записей в блоге: 177
17.12.2020, 16:05  [ТС] 54
Пример кода, как из JSON-файла выше (то есть из файла описания Sprite Sheet, который хранит описания фреймов и другую информацию) извлечь размеры Sprite Sheet. Эти размеры нужны, чтобы пересчитать текстурные координаты. OpenGL будет воспринимать текстуру, как квадрат 1x1 юнитов.

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void Widget::initVertexBuffers()
{
    QFile jsonFile(":/Sprites/battle_city_spritesheet.json");
    jsonFile.open(QIODevice::ReadOnly);
 
    QByteArray data = jsonFile.readAll();
    QJsonDocument jsonDoc(QJsonDocument::fromJson(data));
    QJsonObject jsonObj = jsonDoc.object();
 
    int w = jsonObj["meta"]
            .toObject()["size"]
            .toObject()["w"].toInt();
 
    int h = jsonObj["meta"]
            .toObject()["size"]
            .toObject()["h"].toInt();
 
    qDebug() << "w = " << w << ", h = " << h;
}
Вывод программы в терминал:

w = 256 , h = 32
0
4176 / 2282 / 387
Регистрация: 05.10.2013
Сообщений: 6,385
Записей в блоге: 177
19.12.2020, 00:54  [ТС] 55
Когда из JSON загружаются танчик игрока, как в примере выше, то нужно подключить библиотеки:

C++ (Qt)
1
2
3
#include <QtCore/QFile>
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject>
Кроме сохранения в JSON, TexturePacker умеет сохранять Sprite Sheet в XML. В Qt из коробки есть модуль для работы с XML, как и с JSON. Модуль подключается в файле pro: QT += xml

Тоже самое, что и сообщением выше, но загрузка Sprite Sheet из XML. Комментарии в XML не я писал, они сами генерируются в TexturePacker. За одно у меня в коде происходит перевод пиксельных координат спрайта в текстурные координаты:

Название: 9d6b85c1-152c-4214-84a1-293e86fa9a49.png
Просмотров: 60

Размер: 816 байт

XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with TexturePacker http://www.codeandweb.com/texturepacker-->
<!-- $TexturePacker:SmartUpdate:110c02a4b5ffaedca0fdfd7882cd424f:dde6a5be5dfe368d565574779e47cbd7:84e2e08cbb080f94c14db0f9b9c220e8$ -->
<!--Format:
n  => name of the sprite
x  => sprite x pos in texture
y  => sprite y pos in texture
w  => sprite width (may be trimmed)
h  => sprite height (may be trimmed)
pX => x pos of the pivot point (relative to sprite width)
pY => y pos of the pivot point (relative to sprite height)
oX => sprite's x-corner offset (only available if trimmed)
oY => sprite's y-corner offset (only available if trimmed)
oW => sprite's original width (only available if trimmed)
oH => sprite's original height (only available if trimmed)
r => 'y' only set if sprite is rotated
with polygon mode enabled:
vertices   => points in sprite coordinate system (x0,y0,x1,y1,x2,y2, ...)
verticesUV => points in sheet coordinate system (x0,y0,x1,y1,x2,y2, ...)
triangles  => sprite triangulation, 3 vertex indices per triangle
-->
<TextureAtlas imagePath="battle_city_spritesheet.png" width="102" height="102">
    <sprite n="tank_yellow_small_down_01.png" x="1" y="1" w="32" h="32" pX="0.5" pY="0.5"/>
    <sprite n="tank_yellow_small_down_02.png" x="1" y="35" w="32" h="32" pX="0.5" pY="0.5"/>
    <sprite n="tank_yellow_small_left_01.png" x="1" y="69" w="32" h="32" pX="0.5" pY="0.5"/>
    <sprite n="tank_yellow_small_left_02.png" x="35" y="1" w="32" h="32" pX="0.5" pY="0.5"/>
    <sprite n="tank_yellow_small_right_01.png" x="69" y="1" w="32" h="32" pX="0.5" pY="0.5"/>
    <sprite n="tank_yellow_small_right_02.png" x="35" y="35" w="32" h="32" pX="0.5" pY="0.5"/>
    <sprite n="tank_yellow_small_up_01.png" x="35" y="69" w="32" h="32" pX="0.5" pY="0.5"/>
    <sprite n="tank_yellow_small_up_02.png" x="69" y="35" w="32" h="32" pX="0.5" pY="0.5"/>
</TextureAtlas>
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <QtXml/QDomDocument>
#include <QtCore/QFile>
 
/* ... */
 
void Widget::initVertexBuffers()
{
    QFile xmlFile(":/Sprites/battle_city_spritesheet.xml");
    xmlFile.open(QIODevice::ReadOnly);
 
    QDomDocument xmlDoc;
    xmlDoc.setContent(&xmlFile);
    xmlFile.close();
 
    QDomElement root = xmlDoc.documentElement();
    float spriteSheetWidth = root.attribute("width").toFloat();
    float spriteSheetHeight = root.attribute("height").toFloat();
 
    QDomElement sprite = root.firstChildElement();
    while(!sprite.isNull())
    {
        float x = 1.f / (spriteSheetWidth / sprite.attribute("x").toFloat());
        float y = 1.f / (spriteSheetHeight / sprite.attribute("y").toFloat());
        float w = 1.f / (spriteSheetWidth / sprite.attribute("w").toFloat());
        float h = 1.f / (spriteSheetHeight / sprite.attribute("h").toFloat());
 
        qDebug() << QString("x = %1, y = %2, w = %3, h = %4")
                    .arg(x).arg(y).arg(w).arg(h);
 
        sprite = sprite.nextSiblingElement();
    }
}
Вывод программы:

"x = 0.00980392, y = 0.00980392, w = 0.313726, h = 0.313726"
"x = 0.00980392, y = 0.343137, w = 0.313726, h = 0.313726"
"x = 0.00980392, y = 0.676471, w = 0.313726, h = 0.313726"
"x = 0.343137, y = 0.00980392, w = 0.313726, h = 0.313726"
"x = 0.676471, y = 0.00980392, w = 0.313726, h = 0.313726"
"x = 0.343137, y = 0.343137, w = 0.313726, h = 0.313726"
"x = 0.343137, y = 0.676471, w = 0.313726, h = 0.313726"
"x = 0.676471, y = 0.343137, w = 0.313726, h = 0.313726"
0
4176 / 2282 / 387
Регистрация: 05.10.2013
Сообщений: 6,385
Записей в блоге: 177
19.12.2020, 01:10  [ТС] 56
Перед тем, как я забросил эту игру, в мае 2017, у меня были наброски на WebGL-движке Phaser, где я реализовал механику движения танчика. Демку можно запустить в браузере по ссылке: https://8observer8.bitbucket.i... City/dist/

Создание игры "Battle City" (танчики) на BGE
0
4176 / 2282 / 387
Регистрация: 05.10.2013
Сообщений: 6,385
Записей в блоге: 177
28.12.2020, 02:31  [ТС] 57
Самый простой (из известных мне) и бесплатный способ соединиться с удалённым сервером - это писать сервер с использованием Node.js/Express/WebSocket и использовать хостинг на Heroku или OpenShift. Официальная пошаговая инструкция для развёртывания на Heroku: Getting Started on Heroku with Node.js

Пример, в котором после соединения клиента с сервером - клиент и сервер выводят сообщения о соединении на экран. Используется бесплатный тариф, поэтому сервер засыпает если им не пользуются 30 минут, а чтобы разбудить, нужно подождать 10-15 секунд.

Содержимое архива desktop-клиента, собранного в релиз для Windows на Qt C++:

Название: c9e9a689-7818-48c4-bfe6-85ed1276609b.png
Просмотров: 32

Размер: 5.7 Кб

Результат работы desktop-клиента на Qt C++:

Создание игры "Battle City" (танчики) на BGE


Для отладки и релиз нужно на web-клиенте и на desktop-клиенте раскомментировать и закомментировать соответствующие строки:

На веб-клиенте:

Javascript
1
2
    // const socket = new WebSocket("ws://localhost:3000");
    const socket = new WebSocket("wss://connection-websocket-js.herokuapp.com");
На на desktop-клиенте:

C++ (Qt)
1
2
//    m_socket.open(QUrl("ws://localhost:3000"));
     m_socket.open(QUrl("wss://connection-websocket-js.herokuapp.com"));

Исходники web-клиента и сервера

src/client/main.js
Javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function main()
{
    const socket = new WebSocket("ws://localhost:3000");
    // const socket = new WebSocket("wss://connection-websocket-js.herokuapp.com");
 
    const output = document.getElementById("output");
    output.innerHTML = "Please, wait for connection..."
 
    socket.onopen = () =>
    {
        const message = "Client was connected to server";
        console.log(message);
        output.innerHTML = message;
    };
}
 
window.onload = main();
src/server/controllers/homeController.js

Javascript
1
2
3
4
exports.index = (request, response) =>
{
    response.render("home.hbs");
};
src/server/routers/homeRouter.js

Javascript
1
2
3
4
5
6
const express = require("express");
const homeController = require("../controllers/homeController");
 
const homeRouter = express.Router();
homeRouter.get("/", homeController.index);
module.exports = homeRouter;
src/server/views/layouts/layout.hbs

HTML5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Rectangle Coordinates. WebSockets, JavaScript</title>
</head>
 
<body>
    {{{body}}}
    <script src="js/bundle.js"></script>
    {{!-- <script src="js/bundle.min.js"></script> --}}
</body>
 
</html>
src/server/views/home.hbs

HTML5
1
<div id="output"></div>
src/server/app.js

Javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const express = require("express");
const http = require("http");
const path = require("path");
const ws = require("ws");
const homeRouter = require("./routers/homeRouter");
 
const app = express();
app.set("view engine", "hbs");
app.set("view options", { layout: "layouts/layout" });
app.set("views", path.join(__dirname, "/views"));
app.use(express.static(path.join(__dirname, "../../public")));
app.use("/", homeRouter);
 
const httpServer = http.createServer(app);
const wss = new ws.Server({ server: httpServer });
 
wss.on("connection", (socket) =>
{
    console.log("Client was coonected");
});
 
const port = process.env.PORT || 3000;
httpServer.listen(port, () => { console.log("Server started at port: " + port) });
package.json

JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
  "name": "connection-websocket-js",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node src/server/app.js",
    "clear": "del /f /q /s .\\public\\js\\*.*",
    "del-bundle": "del /f /q /s .\\src\\bundle.js",
    "bundle-debug": "browserify --debug src/client/main.js -o public/js/bundle.js",
    "bundle-release": "browserify src/client/main.js -o src/client/bundle.js",
    "uglify": "uglifyjs src/client/bundle.js -o public/js/bundle.min.js",
    "debug": "npm run bundle-debug",
    "release": "npm run clear && npm run bundle-release && npm run uglify && npm run del-bundle"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.1",
    "hbs": "^4.1.1",
    "ws": "^7.3.1"
  }
}


Исходники desktop-клиента на Qt C++

main.cpp

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Add this line to .pro
// QT += websockets
 
#include "Widget.h"
 
#include <QApplication>
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}
Widget.h

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef WIDGET_H
#define WIDGET_H
 
#include <QtWidgets/QWidget>
#include <QtWidgets/QLabel>
#include <QtWebSockets/QWebSocket>
 
class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget();
private slots:
    void onConnection();
private:
    QWebSocket m_socket;
    QLabel *m_pLabel;
};
#endif // WIDGET_H
Widget.cpp

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <QtWidgets/QVBoxLayout>
#include <QtCore/QDebug>
#include "Widget.h"
 
Widget::Widget()
{
    setWindowTitle("Qt C++ Client");
    resize(300, 300);
    QFont font("Arial", 14);
    QVBoxLayout *vbox = new QVBoxLayout(this);
    m_pLabel = new QLabel("Please, wait for connection...", this);
    m_pLabel->setFont(font);
    vbox->addWidget(m_pLabel);
    vbox->addStretch(1);
    connect(&m_socket, &QWebSocket::connected, this, &Widget::onConnection);
//    m_socket.open(QUrl("ws://localhost:3000"));
    m_socket.open(QUrl("wss://connection-websocket-js.herokuapp.com"));
}
 
void Widget::onConnection()
{
    QString message = "Client was connected to server";
    qDebug() << message;
    m_pLabel->setText(message);
}
0
Вложения
Тип файла: zip ConnectionWebSocket_ExeWindows.zip (11.99 Мб, 0 просмотров)
Тип файла: zip connection-websocket-js-master.zip (5.5 Кб, 0 просмотров)
Тип файла: zip ConnectionWebSocket_Qt5Cpp-master.zip (2.2 Кб, 0 просмотров)
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
28.12.2020, 02:31

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

Готовая реализация игры "Танчики"
Помогите ребята!!! У кого нибудь есть программа моделирующая игру танчики. На C#

Создание игры "монополия" или по-другому "менеджер"
Доброго всем дня, задача ставится, написать игру с возможностями OpenGL, дабы создать красочное...

Игра Battle City
Ребята помогите мне для кyрсовой надо написать Battle City (танчики) на C#. Меня интересyeт где...

Для каждой проведенной игры напечатать словесный результат: "выигрыш", "проигрыш" или "ничья"
Даны два массива из n, однозначных чисел. В первом из них записано кол-во мячей, забитых...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
57
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.