Перейти к содержанию

Terraria v1.3.5.3 Создание коллизии по координатам


Рекомендуемые сообщения

Terraria лицензия, потому смещения и адреса на репаках могут отличатся.
 

Спойлер

Здесь рассказывается как создать коллизию (просчет столкновений) между игроком и какими либо объектами в двумерном пространстве, без проверок на вталкивание в стену например. Суть заключается в том, что при создании такого скрипта персонаж не сможет пройти через существ, а они через персонажа. Скрипт в данной теме может быть сложным запутанным и скорее всего можно было сделать намного проще. Но главное, он работает.

3.png


Для начала, нам нужно найти все необходимые адреса, как это сделать думаю понятно, адрес игрока можно найти по здоровью и сделать указатель на него. У меня получился вот такой указатель:
Для вставки в скрипт: [[[Terraria.Main::DoDraw+375]]+08+[[Terraria.Main::DoDraw+37B]]*4]
Принцип такого указателя: В Terraria.Main::DoDraw+375 в коде вписан адрес структуры с игроками

Спойлер

c71bc72ff19ad65c.png

Таким образом в Terraria.Main::DoDraw+37B записан адрес хранящий номер активного игрока

Спойлер

2.png


Далее идет прибавление +08 до первого элемента, потом номер игрока умножается на 4, так как 1 адрес занимает 4 байта, вот и получается адрес игрока.

Теперь необходимо найти структуру содержащую адреса существ, думаю это тоже понятно как найти, у меня вот такой адрес:
Для вставки в скрипт: [[Terraria.Main::UpdateAudio+4F7]], по такому же принципу как и 2 адреса сверху.
Теперь мы можем начать писать скрипт коллизии, суть скрипта в организации проверок координат касания углов персонажа и координат углов существа.
Вот примерная схема этого действа:

Спойлер

285c1bd62ae00ccc.png

Желтым изображены виртуальные полигоны коллизии, то есть промежутки в которых скрипт делает проверку, попадает ли точка игрока в них.
Самый верхний желтый полигон используется для другой проверки, о которой будет сказано ниже.

Итак, у нас есть адрес игрока, и предположительно адрес существа, для проверки существ нужно сделать цикл, перебирающий их и проверяющий координаты каждого:
 

Спойлер

//Вырезка из всего скрипта:
StartCocleC: //Цикл перебора существ
cmp ebx,#99
je back //Если проверены все нипы из структуры то закончить цикл
add ebx,1
mov edx,[eax+ebx*4+08] //Адрес нпс
cmp edx,esi //Проверка на совпадение с адресом существа для которого делается коллизия
je StartCocleC
cmp [edx+18],1 //Проверка на активность, если тут 1, то обьект существует, 0 - нет.
jne StartCocleC

 

Как тут указано, тут так же проверяется совпадение адреса существа в цикле с адресом существа для которого делается коллизия, это сделано для того что бы не было самоколлизии, то есть столкновения существа с самим собой. Так же имеется проверка на активность, есть ли вообще этот объект, или он отсутствует или отключен.
Теперь, так как у нас имеется цикл перебора существ, мы можем сделать вычисление крайних точек существа.
Координаты существа в игре - это его крайняя левая нижняя точка. Так же у существа есть размер, и исходя из этих данных игра центрирует точку координат перед выводом существа на позицию в карте. Координаты в структуре существа отображают именно крайнюю левую нижнюю точку.
Делаем вычисления после цикла и записываем в метки координаты точек и расстояние:

Спойлер

//Вырезка из скрипта
//Вычисления крайних точек и сторон по Х
fild dword [edx+10] //Отношение правой нпс к левой игрока 2 (игрок справа)
fstp dword [CoordsTest+1C] //Размер нпс во флоат и временное сохранение
fld dword [edx+20] //Загрузить координаты НПС
fadd dword [CoordsTest+1C] //Получение координат правой стороны нпс
fsub dword [esi+20] //Вычитание координат игрока из координат нпс
fistp dword [CoordsTest] //Полученное число расстояния в метку
fild dword [esi+10] //Отношение левой нпс к правой игрока 1 (игрок слева)
fstp dword [CoordsTest+1C] //Размер игрока во флоат и временное сохранение
fld dword [esi+20] //Загрузить координаты игрока
fadd dword [CoordsTest+1C] //Получение координат правой стороны игрока
fsubr dword [edx+20] //Обратное вычитание координат игрока из коордиеат НПС
fistp dword [CoordsTest+4] //Полученное число расстояния в метку
//Вычисления крайних точек и сторон по Y
fild dword [edx+14] //Отношение верхней нпс к нижней игрока 2 (игрок сверху)
fstp dword [CoordsTest+1C] //Размер нпс во флоат и временное сохранение
fld dword [edx+24] //Загрузить координаты НПС
fsub dword [CoordsTest+1C] //Получение координат верхней стороны нпс
fsub dword [esi+24] //Вычитание координат игрока из координат нпс
fistp dword [CoordsTest+8] //Полученное число расстояния в метку
fild dword [esi+14] //Отношение верхней игрока к нижней нпс 1 (игрок снизу)
fstp dword [CoordsTest+1C] //Размер игрока во флоат и временное сохранение
fld dword [esi+24] //Загрузить координаты игрока
fsub dword [CoordsTest+1C] //Получение координат верхней стороны игрока
fsubr dword [edx+24] //Обратное вычитание координат игрока из коордиеат НПС
fistp dword [CoordsTest+C] //Полученное число расстояния в метку

 

 

Теперь можно написать проверки.

Данный код проверяет положение точек 1 существа, относительно другого, при этом проверяется как X так и Y, иначе коллизия будет размером во всю карту, а не только по размерам существа, из за этого в каждом блоке по 4 проверки. После проверок в метку записывается состояние персонажа, слева он, сверху, справа или снизу.

Спойлер

//Вырезка из скрипта
//Проверки на положение игрока относительно существа
TestCoordsP:
cmp [CoordsTest],0
jl noRight
cmp [CoordsTest],F //Виртуальный полигон коллизи (просто размер проверки)
jg noRight
cmp [CoordsTest+8],0
jl TestCoordsP2
jmp noRight
 TestCoordsP2:
cmp [CoordsTest+C],0
jl noRight
 TestCoordsP3:
mov byte ptr [CoordsTest+18],2 //Справа
jmp WerhTest

noRight:
cmp [CoordsTest+4],0
jg WerhTest
cmp [CoordsTest+4],#-15 //Виртуальный полигон коллизи (просто размер проверки)
jl WerhTest
cmp [CoordsTest+8],0
jl noRight2
jmp WerhTest
 noRight2:
cmp [CoordsTest+C],0
jl WerhTest
 noRight3:
mov byte ptr [CoordsTest+18],1 //Слева

WerhTest:
cmp [CoordsTest+8],0
jg SnizTest
sub [CoordsTest+8],#3
cmp [CoordsTest+8],#-18 //Виртуальный полигон коллизи (просто размер проверки)
jl SnizTest
cmp [CoordsTest],0
jg WerhTest1
jmp SnizTest
 WerhTest1:
cmp [CoordsTest+4],0
jg SnizTest
 WerhTest2:
mov byte ptr [CoordsTest+19],2 //Сверху

SnizTest:
cmp [CoordsTest+C],0
jl ParamPrim
cmp [CoordsTest+C],F //Виртуальный полигон коллизи (просто размер проверки)
jg ParamPrim
cmp [CoordsTest],0
jg SnizTest1
jmp ParamPrim
 SnizTest1:
cmp [CoordsTest+4],0
jg ParamPrim
 SnizTest2:
mov byte ptr [CoordsTest+19],1 //Снизу

 

 

Следующий код делает проверку значения записанного в метку 1/2 1/2 и относительно этого выполняет действия с персонажем, убавляет его координаты или прибавляет на еденичку, создавая таким образом координатную коллизию, не пропускающую игрока сквозь существо.

Спойлер

//Вырезка из скрипта
//Скрипт который выполняется если игрок касается какой либо стороны моба
ParamPrim:
cmp byte ptr [CoordsTest+19],2 //Сверху
jne next1
fld1 //Загрузка еденички
fsubr dword [esi+24]
fstp dword [esi+24]
//Проверка ускорения игрока
fild dword [esi+2C]
fistp dword [CoordsTest+1C]
cmp [CoordsTest+1C],0
jg setzero
jmp next1
setzero:
mov [esi+2C],0

next1:
cmp byte ptr [CoordsTest+18],2 //Справа
jne next2
fld1 //Загрузка еденички
fadd dword [esi+20]
fstp dword [esi+20]
fld1 //Загрузка еденички
fsubr dword [edx+20]
fstp dword [edx+20]

next2:
cmp byte ptr [CoordsTest+18],1 //Слева
jne next3
fld1 //Загрузка еденички
fsubr dword [esi+20]
fstp dword [esi+20]
fld1 //Загрузка еденички
fadd dword [edx+20]
fstp dword [edx+20]

next3:
cmp byte ptr [CoordsTest+19],1 //Снизу
jne writeToV
fld1 //Загрузка еденички
fsubr dword [edx+24]
fstp dword [edx+24]

 

 

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

Спойлер

writeToV:
cmp [CoordsTest+8],0
jl nosetThis
add [CoordsTest+8],D
cmp [CoordsTest+8],#18 //Виртуальный полигон коллизи
jg nosetThis
cmp [CoordsTest],0
jg writeToV1
jmp nosetThis
 writeToV1:
cmp [CoordsTest+4],0
jg nosetThis
 writeToV2:
 mov byte ptr [CoordsTest+1A],1
 mov dword [CoordsTest+24],edx
jmp NasledVeloctory

nosetThis:
cmp [CoordsTest+24],edx //Проверка касается игрок верхнего полигона того же существа или уже другого
jne NasledVeloctory
mov byte ptr [CoordsTest+1A],0

 

 

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

Спойлер

//Внедренные коды
SetUscorInCode:
cmp byte ptr [CoordsTest+1A],1 //Если игрок стоит на существе то не записывать увеличивать ускорение падения (стоит на земле)
jne ispcode
fstp dword [CoordsTest+20]
jmp exitret
ispcode:
mov eax,[ebp-000005EC]
fadd dword ptr [eax]
fstp dword ptr [eax]
exitret:
ret

Terraria.Player::Update+10C8F: //Иньекция
call SetUscorInCode
nop
nop
nop
nop
nop

 

 

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

Спойлер

//Весь мой скрипт включая недоработки и убранные функции

[ENABLE]
alloc(CollisionCreator,1300)
registersymbol(CollisionCreator)
label(adresStrs)
label(CoordsTest)
label(NpsPr)
registersymbol(CoordsTest)

CollisionCreator:
mov esi,[[[Terraria.Main::DoDraw+375]]+08+[[Terraria.Main::DoDraw+37B]]*4] //Адрес игрока
call CollisionCreateFunction

mov eax,[[Terraria.Main::UpdateAudio+4F7]]
mov byte ptr [NpsPr],1
//Начало проверки координат при совпадении
mov ebx,0 //Обнуление счетчика
sub ebx,1
StartCocleN:
cmp ebx,#99
je backpotok //Если проверены все нипы из структуры то закончить цикл
add ebx,1
mov edx,[eax+ebx*4+08] //Адрес нпс
cmp [edx+18],1
jne StartCocleN
mov esi,edx
call CollisionCreateFunction
jmp StartCocleN
backpotok:
mov byte ptr [NpsPr],0

{mov eax,[[Terraria.Main::CacheProjDraws+41]]
mov byte ptr [NpsPr],1
//Начало проверки координат при совпадении
mov ebx,0 //Обнуление счетчика
sub ebx,1
StartCocleP:
cmp ebx,#99
je backpotok1 //Если проверены все снаряды из структуры то закончить цикл
add ebx,1
mov edx,[eax+ebx*4+08] //Адрес нпс
cmp [edx+18],1
jne StartCocleP
mov esi,edx
call CollisionCreateFunction
jmp StartCocleP
backpotok1:
mov byte ptr [NpsPr],0}
ret


CollisionCreateFunction: //Начало функции коллизии в esi адрес того для чего коллизия
push eax
push ebx
push edx
mov eax,[[Terraria.Main::UpdateAudio+4F7]] //Запись адреса с нпс
//mov eax,[[Terraria.Main::CacheProjDraws+41]]//Запись адреса со снарядами
//Начало проверки координат при совпадении
mov ebx,0 //Обнуление счетчика
sub ebx,1
mov [CoordsTest+14],BDCCCCCD //1 float
StartCocleC:
mov word ptr [CoordsTest+18],0
cmp ebx,#99
je back //Если проверены все нипы из структуры то закончить цикл
add ebx,1
mov edx,[eax+ebx*4+08] //Адрес нпс
cmp edx,esi //Проверка на совпадение с адресом существа для которого делается коллизия
je StartCocleC
cmp [edx+18],1 //Проверка на активность, если тут 1, то обьект существует, 0 - нет.
jne StartCocleC
//Вычисления крайних точек и сторон по Х
fild dword [edx+10] //Отношение правой нпс к левой игрока 2 (игрок справа)
fstp dword [CoordsTest+1C] //Размер нпс во флоат и временное сохранение
fld dword [edx+20] //Загрузить координаты НПС
fadd dword [CoordsTest+1C] //Получение координат правой стороны нпс
fsub dword [esi+20] //Вычитание координат игрока из координат нпс
fistp dword [CoordsTest] //Полученное число расстояния в метку
fild dword [esi+10] //Отношение левой нпс к правой игрока 1 (игрок слева)
fstp dword [CoordsTest+1C] //Размер игрока во флоат и временное сохранение
fld dword [esi+20] //Загрузить координаты игрока
fadd dword [CoordsTest+1C] //Получение координат правой стороны игрока
fsubr dword [edx+20] //Обратное вычитание координат игрока из коордиеат НПС
fistp dword [CoordsTest+4] //Полученное число расстояния в метку
//Вычисления крайних точек и сторон по Y
fild dword [edx+14] //Отношение верхней нпс к нижней игрока 2 (игрок сверху)
fstp dword [CoordsTest+1C] //Размер нпс во флоат и временное сохранение
fld dword [edx+24] //Загрузить координаты НПС
fsub dword [CoordsTest+1C] //Получение координат верхней стороны нпс
fsub dword [esi+24] //Вычитание координат игрока из координат нпс
fistp dword [CoordsTest+8] //Полученное число расстояния в метку
fild dword [esi+14] //Отношение верхней игрока к нижней нпс 1 (игрок снизу)
fstp dword [CoordsTest+1C] //Размер игрока во флоат и временное сохранение
fld dword [esi+24] //Загрузить координаты игрока
fsub dword [CoordsTest+1C] //Получение координат верхней стороны игрока
fsubr dword [edx+24] //Обратное вычитание координат игрока из коордиеат НПС
fistp dword [CoordsTest+C] //Полученное число расстояния в метку
//Если айди прыгательное или летательное добавить
cmp byte ptr [NpsPr],1
je noadd
cmp [edx+D8],1
jne noadd
sub [CoordsTest+8],#25
noadd:
sub [CoordsTest+8],#5
//Проверки на положение игрока относительно существа
TestCoordsP:
cmp [CoordsTest],0
jl noRight
cmp [CoordsTest],F //Виртуальный полигон коллизи размером в 2
jg noRight
cmp [CoordsTest+8],0
jl TestCoordsP2
jmp noRight
 TestCoordsP2:
cmp [CoordsTest+C],0
jl noRight
 TestCoordsP3:
mov byte ptr [CoordsTest+18],2 //Справа
jmp WerhTest

noRight:
cmp [CoordsTest+4],0
jg WerhTest
cmp [CoordsTest+4],#-15 //Виртуальный полигон коллизи размером в 2
jl WerhTest
cmp [CoordsTest+8],0
jl noRight2
jmp WerhTest
 noRight2:
cmp [CoordsTest+C],0
jl WerhTest
 noRight3:
mov byte ptr [CoordsTest+18],1 //Слева

WerhTest:
cmp [CoordsTest+8],0
jg SnizTest
sub [CoordsTest+8],#3
cmp [CoordsTest+8],#-18 //Виртуальный полигон коллизи размером в 2
jl SnizTest
cmp [CoordsTest],0
jg WerhTest1
jmp SnizTest
 WerhTest1:
cmp [CoordsTest+4],0
jg SnizTest
 WerhTest2:
mov byte ptr [CoordsTest+19],2 //Сверху

SnizTest:
cmp [CoordsTest+C],0
jl ParamPrim
cmp [CoordsTest+C],F //Виртуальный полигон коллизи размером в 2
jg ParamPrim
cmp [CoordsTest],0
jg SnizTest1
jmp ParamPrim
 SnizTest1:
cmp [CoordsTest+4],0
jg ParamPrim
 SnizTest2:
mov byte ptr [CoordsTest+19],1 //Снизу

//Скрипт который выполняется если игрок касается какой либо стороны моба
ParamPrim:
cmp byte ptr [CoordsTest+19],2 //Сверху
jne next1
fld1 //Загрузка еденички
fsubr dword [esi+24]
fstp dword [esi+24]
//Проверка ускорения игрока
fild dword [esi+2C]
fistp dword [CoordsTest+1C]
cmp [CoordsTest+1C],0
jg setzero
jmp next1
setzero:
mov [esi+2C],0

next1:
cmp byte ptr [CoordsTest+18],2 //Справа
jne next2
fld1 //Загрузка еденички
fadd dword [esi+20]
fstp dword [esi+20]
fld1 //Загрузка еденички
fsubr dword [edx+20]
fstp dword [edx+20]

next2:
cmp byte ptr [CoordsTest+18],1 //Слева
jne next3
fld1 //Загрузка еденички
fsubr dword [esi+20]
fstp dword [esi+20]
fld1 //Загрузка еденички
fadd dword [edx+20]
fstp dword [edx+20]

next3:
cmp byte ptr [CoordsTest+19],1 //Снизу
jne writeToV
fld1 //Загрузка еденички
fsubr dword [edx+24]
fstp dword [edx+24]

writeToV:
cmp [CoordsTest+8],0
jl nosetThis
add [CoordsTest+8],D
cmp [CoordsTest+8],#18 //Виртуальный полигон коллизи
jg nosetThis
cmp [CoordsTest],0
jg writeToV1
jmp nosetThis
 writeToV1:
cmp [CoordsTest+4],0
jg nosetThis
 writeToV2:
 mov byte ptr [CoordsTest+1A],1
 mov dword [CoordsTest+24],edx
jmp NasledVeloctory

nosetThis:
cmp [CoordsTest+24],edx
jne NasledVeloctory
mov byte ptr [CoordsTest+1A],0

NasledVeloctory:
jmp StartCocleC
back:
pop edx
pop ebx
pop eax
ret //Конец функции коллизии



//Внедренные коды
SetUscorInCode:
cmp byte ptr [CoordsTest+1A],1
jne ispcode
fstp dword [CoordsTest+20]
jmp exitret
ispcode:
mov eax,[ebp-000005EC]
fadd dword ptr [eax]
fstp dword ptr [eax]
exitret:
ret

adresStrs:
dd 0 0
CoordsTest:
dd 0 0 0 0 0 0 0 0 0 0 0
NpsPr:
db 00

Terraria.Player::Update+10C8F:
call SetUscorInCode
nop
nop
nop
nop
nop


[DISABLE]
Terraria.Player::Update+10C8F:
mov eax,[ebp-000005EC]
fadd dword ptr [eax]
fstp dword ptr [eax]

unregistersymbol(CollisionCreator)
unregistersymbol(CoordsTest)
dealloc(CollisionCreator)

 


Этот скрипт должен на входе получить адрес структуры для проверки. Он выполняется 2 раза, 1 раз делает коллизию игроку, а 2 раз делает коллизию тому адрес чего получен дальше. В моём случае этот адрес - адрес существа.  Этот скрипт вызывается другим скриптом с потоком:

Спойлер

[ENABLE]
alloc(potoc,64)
label(byteupr)
registersymbol(byteupr)
createthread(potoc)

potoc:
cmp byte ptr [byteupr],1 
jne potoc
cmp ecx,#20000
add ecx,1
jl potoc
mov ecx,0
push ecx
call CollisionCreator
pop ecx
cmp byte ptr [byteupr],2
jne potoc
ret

byteupr:
db 00
[DISABLE]
dealloc(potoc)
unregistersymbol(byteupr)

 


Вот эти сложные махинации создают коллизию между игроком и существами, и между самими существами.
Картинки работы:
Скрипт работает - существа не могут пройти сквозь друг друга и игрока:

Спойлер

4.png5.png6.png?width=888&height=4587.png

 

Скрипт отключён:

Спойлер

8.png

 

Изменено пользователем inaginary
  • Понравилось 2
  • Плюс 2
Ссылка на комментарий
Поделиться на другие сайты

×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.