Опрос на сайте
Что вы делаете с GTA?

Популярные новости

Magic - TXD Builder 0.9.1

Magic - TXD Builder 0.9.1
Полезная программа для сборки TXD файлов, которая важные параметры, такие как mip map, DXT сжатие... Кроме того, программа

Vertex Alpha в Vice City

Vertex Alpha в Vice City
То, что некогда было доступно лишь в GTA: San Andreas и выше: Vertex Alpha, а потенциально - и физический бленд текстур в

Компактное меню

Компактное меню
Компактное меню для глобальных модов. Исключено все лишнее.

Main Menu Scene

Main Menu Scene
"Main Menu Scene" дает вам возможность создавать собственные сцены в "Главном Меню" игры с кастомными картой и скриптом, при

Rollerskates Mod

Rollerskates Mod
Модификация позволяет кататься на роликах, прямо как пляжные девушки.

04 ноябрь 2014

Программирование спидометра для GTA на C++


Приветствую вас, дорогие модмейкеры в предыдущих уроке мы научились рисовать спидометр, но рисунки спидометра без программирования это бесполезный хлам. По этому мы вынужденны запрограммировать спидометр а именно в этом уроке мы научимся кодить свои спидометры на C++ для GTA Vice City!

Разработка спидометра начинается по шагам, сперва логически мы проектируем условия (пусть это будет как задача для нас), можно на тетрадном листке. Грубо говоря обдумать все важные детали причем на не сколько шагов вперед.


    1. Спидометр должен показываться, когда игрок сел в транспорт.
    2. Мы должны получить текущую скорость транспорта.
    3. Мы должны вывести две текстуры, одна это контур вторая это подвижная стрелочка.
    4. Относительно скорости, вращать стрелку от опорной точки (задача математическая).
    5. Важно! Мы должны сохранить пропорции размеров и положений текстур на экране при разном разрешении.


Ага и тут накипело сразу масса вопросов, таких как: каким образом мы узнаем транспорт, как же мы вычислим скорость то? О_о а как же мы сможем разворачивать текстуру да еще и от опорной точки? А что значит сохранять пропорцию для разного разрешения экрана?
Спешу вас обрадовать, все на самом деле не так уж и сложно, глаза бояться руки и ум делают. Теперь мы пошагово разберем остальные детали и приступим к разработке.

1. Шаг сбор структур из IDA pro


Именно с этого мы и начнем, вам необходимо собрать все структуры из готовой базы для gta vice city. Все структуры вы собираете в нужный вам h файл. Это нам упростит массу задача и сделает программирование более высокого уровня, чем сидеть тупо решать задачи одними адресами. Причем в дальнейшем они вам могут пригодиться для абсолютно разных задач. Здесь же нам не все подряд нужно собирать а возьмем по мере надобности. Код в статью я не буду выкладывать так как статья растянуться до огромной величины а исходниках структуры вам будут доступны под названием hGTA.h и hGTA.cpp .

2. Шаг пишем свой удобный функционал

Отлично наши структуры собраны, теперь нам пора написать свои удобные функции. Начнем пожалуй с того вопроса как узнать в машине ли игрок? Для начала нам надо узнать самого педа плеера, начнем с того, делается это просто:

auto _currentPlayer = (BYTE*)0x0A10AFB; 
auto _players = (CPlayer*)0x094AD28;

CPed * GetPlayerPed() {
return (CPed*)_players[*_currentPlayer].pPed;
};


и наконец всего лишь написать так:

bool isPlayerCar(){
return true == GetPlayerPed()->m_bInVehicle;
};



Вот и все! Теперь надеюсь становиться понятно, что структуры нам упростили массу задач!
Отлично как же теперь получить скорость авто? Тоже очень просто:

float GetCarSpeed(){
float x = GetPlayerPed()->m_pVehicle->physical.velocity.x;
float y = GetPlayerPed()->m_pVehicle->physical.velocity.y;
float z = GetPlayerPed()->m_pVehicle->physical.velocity.z;

float lenght = sqrt(x*x + y*y + z*z);
return lenght * 180;
}


Здесь мы по формуле поучаем длину вектора, в единичном представлении, благодаря этому мы спокойно узнаем текущую скорость авто и также вы можете результат перемножить на нужную вам величину скорости. Вот теперь будет самый такой муторный момент, это с текстурами мы практически полностью внедрим новую функцию, что не было у ROCKSTAR. в начале объявим глобальные переменные:


const float widthMultiplier  = 1.0f / 640.0f;
const float heightMultiplier = 1.0f / 448.0f;

auto RsGlobal = (RsGlobalType*)0x09B48D8;

float g_width = 128, g_height = 128;
float g_hotX = 64, g_hotY = 64;


Теперь пояснение, это widthMultiplier и heightMultiplier они же стандартные коэффициенты пропорций, благодаря ним, текстурные размеры и позиции в разных разрешениях экрана будут в строго в нужном положении. С помощью RsGlobal, мы узнаем текущее разрешение экрана игры и наконец наши глобальные переменные: g_width, g_height – размеры текстуры и опорная точка g_hotX, g_hotY для разворота.
И так еще один рывок и вот она наша функция которая выводить и разворачивает текстуру от опорной точки при этом сохраняя масштаб:


void SprRenderEx(CSprite2D *spr, float x, float y, float rot, float hscale, float vscale )
{
float tx1, ty1, tx2, ty2;
float sint, cost;
CQuad quad[4];

x -= g_hotX;
y += g_hotY;

x = RsGlobal->w - (x * RsGlobal->w * widthMultiplier);
y = (y * RsGlobal->h * heightMultiplier);
g_width = (RsGlobal->w * widthMultiplier * g_width);
g_height = (RsGlobal->h * heightMultiplier * g_height);
g_hotX = (RsGlobal->w * widthMultiplier * g_hotX);
g_hotY = (RsGlobal->h * heightMultiplier * g_hotY);

if(vscale == 0)
vscale = hscale;

tx1 = -g_hotX*hscale;
ty1 = -g_hotY*vscale;
tx2 = (g_width-g_hotX)*hscale;
ty2 = (g_height-g_hotY)*vscale;

if (rot != 0.0f){
cost = cosf(rot);
sint = sinf(rot);

quad[0].x = tx1*cost - ty1 * sint + x;
quad[0].y = tx1*sint + ty1 * cost + y;
quad[1].x = tx2*cost - ty1 * sint + x;
quad[1].y = tx2*sint + ty1 * cost + y;
quad[2].x = tx2*cost - ty2 * sint + x;
quad[2].y = tx2*sint + ty2 * cost + y;
quad[3].x = tx1*cost - ty2 * sint + x;
quad[3].y = tx1*sint + ty2 * cost + y;
}
else {
quad[0].x = tx1 + x; quad[0].y = ty1 + y;
quad[1].x = tx2 + x; quad[1].y = ty1 + y;
quad[2].x = tx2 + x; quad[2].y = ty2 + y;
quad[3].x = tx1 + x; quad[3].y = ty2 + y;
}

RwRGBA rgba;
rgba.alpha = 255;
rgba.blue = 255;
rgba.green = 255;
rgba.red = 255;

auto CSprite2d_Draw = (void (__thiscall*)(CSprite2D*, float, float, float, float, float, float, float, float, RwRGBA*))0x05785D0;
CSprite2d_Draw(spr, quad[1].x, quad[1].y, quad[0].x,quad[0].y, quad[2].x, quad[2].y, quad[3].x, quad[3].y, &rgba);
}


Параметры:
CSprite2D *spr – указатель на TXD спрайт
float x – положение по X
float y – положение по Y
float rot – Угол в радианах
float hscale – коэффициент трансформирования по высоте
float vscale – коэффициент трансформирования по ширине
Тут ведется работа с разворотом вертекса и затем же вызов стандартного рендера текстуры вайса. Подробно мы эту функцию рассматривать не будем, так как это уже отдельный материал, но по коду вы можете дальше разобраться что к чему. А также пара удобных и нужных функций:

void SetSpiteSize(float width, float height) {
g_width = width;
g_height = height;
};

void SetHotSpotSpite(float x, float y) {
g_hotX = x;
g_hotY = y;
};


Эти функции надо вызывать перед рендерем текстуры, они позволяют установить опорную точку и размеры. Вот и все наш удобный модуль закончен, теперь осталось сделать основу и воспользоваться нашими функциями и спидометр готов. Вот как нужно все сделать:



#include "stdafx.h"
#include "hGTA.h"

// Также другие функции

auto _txdAdd = (int (__cdecl*)(char *name) )0x0580F00;
auto _txdLoad = (int (__cdecl*)(int a, char *Pathname) )0x0580CD0;
auto _txdAddRef = (int (__cdecl*)(int a) )0x0580A60;
auto txdIndexByName = (int (__cdecl*)(char *name) )0x0580D70;
auto _txdSetCurrent = (int (__cdecl*)(int index) )0x0580AD0;
auto RwReadTexture = ( CSprite2D * (__cdecl*)(char *name, int a2) )0x064E110;

// Здесь объявим строки
char ring_name[] = "ring";
char arrow_name[] = "arrow";

char txd_name[] = "speedometer";
char path_txd[] = "MODELS/speedometer.txd";


void injectFunction (DWORD address, DWORD function) {
DWORD _old;
VirtualProtect((LPVOID)address,4, PAGE_READWRITE, &_old);
BYTE * patch = (BYTE *)address;
*patch = 0xE9; // JMP
*(DWORD *)(patch+1) = (function-(address+5));
VirtualProtect((LPVOID)address,4, _old, &_old);
}


// Для инициализации
void LoadTextures() {

// Имя самого файла txd
int ref = _txdAdd(txd_name);

// Путь по которому будем загружать txd
_txdLoad(ref, path_txd);
_txdAddRef(ref);
};


void VC_DrawFuncHUD() {

// Если игрок в машине...
if ( isPlayerCar() ) {

_txdSetCurrent(txdIndexByName(txd_name));
CSprite2D * spr_ring = RwReadTexture(ring_name, 0);
CSprite2D * spr_arrow = RwReadTexture(arrow_name, 0);

SetSpiteSize(128, 128);
SetHotSpotSpite(64, 64);
SprRenderEx(spr_ring, 160, 300, 180 * PI_Math/180, 1.0f, 1.0f);

SetSpiteSize(32, 64);
SetHotSpotSpite(15.75, 16.77);
SprRenderEx(spr_arrow, 110, 350, (GetCarSpeed() + 45) * PI_Math/180, 1.0f, 1.0f);
}


};

BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
injectFunction(0x043E490, (DWORD)VC_DrawFuncHUD);
injectFunction(0x057FAC0, (DWORD)LoadTextures);
break;

case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}


Как видно все очень просто и легко, плагин ориентирован на FAST Loader обычным способом ASI работать не будет! Однако вы можете написать код для обычной asi, для этого вам надо вызвать LoadTextures() в case DLL_PROCESS_ATTACH: и отказаться от подмены injectFunction(0x057FAC0, (DWORD)LoadTextures).

Теперь не много пояснений к коду:
Пути текстур а также сами текстуры:

char ring_name[]         = "ring";
char arrow_name[] = "arrow";
char txd_name[] = "speedometer";
char path_txd[] = "MODELS/speedometer.txd";


Так что не забывайте свой TXD спидометра положить в папку Models.

Инициализация
Инициализация находиться тут void LoadTextures(), тут же лучше и делать загрузки нужных нам ресурсов.
Отрисовка/процесс спидометра
Все это находиться в этой функции VC_DrawFuncHUD() процесс простой, если игрок в машине начинаем переключаться на текстуру считывать и затем выводить. Имейте введу:

(GetCarSpeed() + 45) * PI_Math/180 – Это все выражение у нас в итоге выглядит как градус, благодаря чему стрелочка и движется. Изначальное положение 45 градусов, а используя формулу PI_Math/180, мы градусы переводим в радианы.

Скачать исходник ASI спидометра [119,74 Kb] (cкачиваний: 235)

Если у вас все получилось в игре все будет выглядеть тогда так:

Программирование спидометра для GTA на C++


Приятного вам моддинга в GTA Vice City!

Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.

Добавить свой комментарий

Полужирный Наклонный текст Подчёркнутый текст Зачёркнутый текст | Выравнивание по левому краю По центру Выравнивание по правому краю | Вставка смайликов Выбор цвета | Скрытый текст Вставка цитаты Преобразовать выбранный текст из транслитерации в кириллицу Вставка спойлера
Вопрос: Введите первые 3 (Русские) буквы сайта (заглавные).
Ответ:*
Другие материалы

Вывод на экран GXT текста в GTA VC

Вывод на экран GXT текста в GTA VC
Настала пора поработать не много с текстами в GTA Vice City, а это значит что в этом уроке мы научимся выводить текст GXT,

Вывод на экран TXD GTA

Вывод на экран TXD GTA
После того как мы научились в предыдущих статьях по программированию хорошо работать с памятью игры, то можно уже приступить

Замена функций GTA Vice City на свою

Замена функций GTA Vice City на свою
После того как мы в предыдущих статьях, научились уже более менее хоть к чему-то. Теперь же мы перейдем к тому вопросу как

Подхват переменных в GTA Vice City

Подхват переменных в GTA Vice City
Сейчас в начале разберем вкратце, что же за такой подхват переменных в GTA Vice City. Например мы просто объявляем некую
Ads

Группа GTA Builder