#2) Учимся делать урон на экране как взрослые ребята (??-HF)

итак, ещё немного мануалов как сделать что-то лучше
на этот раз будем учиться запускать летающий урон на экране

начнём сразу с констант и глобальных переменных, которые будут так или иначе встречаться в примерах
C#:
const DAMAGE_MESSAGE_OFFSET = 100;
const MAX_DAMAGE_MESSAGE = 28;
C#:
    var TextBoxHandle DamageText[MAX_DAMAGE_MESSAGE]; //именно столько нам нужно TextBox в xdat, т.е. 28
    for (i=0; i<MAX_DAMAGE_MESSAGE; i++)
    {
        DamageText[i] = GetTextBoxHandle("OnScreenMessageExWnd.DamageText-0-" $ i);
    }
1621682803959.png



думаю не стоит разводить воду и говорить, что работаем мы с EV_SystemMessage и его нужно зарегистрировать и принять в OnEvent, думаю это и так понятно

сразу к куску который всё делает:
C#:
function HandleSystemMessage (string a_Param)
{
    local int SystemMsgIndex, DamageToPlayer, i;
  
    ParseInt(a_Param,"Index",SystemMsgIndex);
    switch (SystemMsgIndex)
    {
        case 2261: //player msg
        case 2281: //summoner msg
        for(i=0; i<MAX_DAMAGE_MESSAGE; i++)
        {
            if(DamageText[i].GetText() == "") //гоняем циклом пока не упираем в свободный TextBox
            {
                DamageText[i].SetAlpha(255); //принудительно делаем непрозрачным, в теории можно покрутить плавное появление
              
                ParseInt( a_Param, "Param3", DamageToPlayer); //цифра урона
              
                DamageText[i].SetText(string(DamageToPlayer)); //установить цифру урона в свободный индекс массива текстобоксов
                DamageText[i].SetAnchor( "OnScreenMessageExWnd", "BottomCenter", "BottomCenter", -200 + Rand(150), Rand(60) ); //выбираем случайную точку 
                DamageText[i].ClearAnchor(); //убираем якорь с окна после предыдущего действия
                DamageText[i].Move(0, -1500, 8f); //начинаем движение текстбокса на -1500 (вверх) со скоростью 8            
                DamageText[i].SetAlpha( 0, 2.8f ); //плавно делаем текстбокс прозрачным
                Me.KillTimer(i + DAMAGE_MESSAGE_OFFSET + 1); //убиваем таймер (индекс + константа + 1)
                Me.SetTimer(i + DAMAGE_MESSAGE_OFFSET + 1, 2500); //заводим таймер именно для этого текстбокса исходя из того же (индекс + константа + 1)
                break;
            }
        }
        break;
    }
}
Спорить как лучше "рандомить" точку для бокса я не хочу, это не лучший пример, а дальше как хотите


Логика таймера много проще:
C#:
function OnTimer (int TimerID)
{
    Me.KillTimer(TimerID); //убиваем любой таймер в самом начале, тут ИД нам не важен
    if(TimerID >= 101 && TimerID <= 200) //Тут подключается логика завода таймер индекс + DAMAGE_MESSAGE_OFFSET
    {
        DamageText[TimerID-DAMAGE_MESSAGE_OFFSET-1].SetText(""); //удаляем текст с текстбокса, что бы он освободился
    } 
}

Итого мы имеем 28 активных текстбоксов, каждый прибит к своему таймер и независим от другого ни по времени жизни, ни по позициям на экране
почему 28? потому что выше 28 клиенту становится не очень хорошо, проблема не выяснена
damage.gif
 

Спорить как лучше "рандомить" точку для бокса я не хочу, это не лучший пример, а дальше как хотите
Для рандома в определенном диапазоне можно сделать так:
C#:
function int mRnd(int IMin, int IMax)
{
    return Rand(IMax - IMin) + IMin;
}
 
Для рандома в определенном диапазоне можно сделать так:
C#:
function int mRnd(int IMin, int IMax)
{
    return Rand(IMax - IMin) + IMin;
}
ох и любите же вы велосипеды придумывать, когда у анриала уже есть такой функционал
)
C#:
int(RandRange(-100, 100))

да собсна и я хорош, заленился (забыл) написать красиво
 
default_npc, ну в общем да, результат один и тот же) как и код практически, отличие в типе данных)
 
Уважаемый default_npc, неподскажите в каких файлах вы это крутили? interface.xdat? или ище ряд файлов?
 
Если HF можно попробовать создать динамически без .xdat, думаю пошустрей работать будет.
AddChildWnd( EXMLControlType ChildType );
 
Если HF можно попробовать создать динамически без .xdat, думаю пошустрей работать будет.
AddChildWnd( EXMLControlType ChildType );
Разницы не будет, окно из хдата создается лишь один раз на этапе инициализации, больше хдат не дергается вообще (кроме вызова reloadui)
 
В хдат вы создаёте окошко и элементы в нём, в коде окна описывается логика работы элементов
то есть кроме interface.xdat больше никакой файл менять не придется? я правильно понимаю?
или все таки interface.u нужно будет ковырять?
 
примерно так должен выглядеть конечный класс
писал от руки
C#:
class OnScreenMessageExWnd extends UICommonAPI;

const DAMAGE_MESSAGE_OFFSET = 100;
const MAX_DAMAGE_MESSAGE = 28;

var TextBoxHandle DamageText[MAX_DAMAGE_MESSAGE]; //именно столько нам нужно TextBox в xdat, т.е. 28


function OnLoad()
{
    local int i;
    for (i=0; i<MAX_DAMAGE_MESSAGE; i++)
    {
        DamageText[i] = GetTextBoxHandle("OnScreenMessageExWnd.DamageText-0-" $ i);
    }
}

function OnRegisterEvent()
{
    RegisterEvent(EV_SystemMessage);   
}

function OnEvent(int Event_ID, string a_param)
{
    if(Event_ID == EV_SystemMessage)
        HandleSystemMessage(a_param);
}

function HandleSystemMessage (string a_Param)
{
    local int SystemMsgIndex, DamageToPlayer, i;
 
    ParseInt(a_Param,"Index",SystemMsgIndex);
    switch (SystemMsgIndex)
    {
        case 2261: //player msg
        case 2281: //summoner msg
        for(i=0; i<MAX_DAMAGE_MESSAGE; i++)
        {
            if(DamageText[i].GetText() == "") //гоняем циклом пока не упираем в свободный TextBox
            {
                DamageText[i].SetAlpha(255); //принудительно делаем непрозрачным, в теории можно покрутить плавное появление
              
                ParseInt( a_Param, "Param3", DamageToPlayer); //цифра урона
              
                DamageText[i].SetText(string(DamageToPlayer)); //установить цифру урона в свободный индекс массива текстобоксов
                DamageText[i].SetAnchor( "OnScreenMessageExWnd", "BottomCenter", "BottomCenter", -200 + Rand(150), Rand(60) ); //выбираем случайную точку
                DamageText[i].ClearAnchor(); //убираем якорь с окна после предыдущего действия
                DamageText[i].Move(0, -1500, 8f); //начинаем движение текстбокса на -1500 (вверх) со скоростью 8           
                DamageText[i].SetAlpha( 0, 2.8f ); //плавно делаем текстбокс прозрачным
                Me.KillTimer(i + DAMAGE_MESSAGE_OFFSET + 1); //убиваем таймер (индекс + константа + 1)
                Me.SetTimer(i + DAMAGE_MESSAGE_OFFSET + 1, 2500); //заводим таймер именно для этого текстбокса исходя из того же (индекс + константа + 1)
                break;
            }
        }
        break;
    }
}


function OnTimer (int TimerID)
{
    Me.KillTimer(TimerID); //убиваем любой таймер в самом начале, тут ИД нам не важен
    if(TimerID >= 101 && TimerID <= 200) //Тут подключается логика завода таймер индекс + DAMAGE_MESSAGE_OFFSET
    {
        DamageText[TimerID-DAMAGE_MESSAGE_OFFSET-1].SetText(""); //удаляем текст с текстбокса, что бы он освободился
    }
}
 
Ребят кто может кинуть готовый класс прикомпиляции много ошибок

Ребят кто поможет реализовать такое не много с компилом проблемы
 
init "me"? Thread error?


Код:
var WindowHandle Me;
function OnLoad()

{

    local int i;

    for (i=0; i<MAX_DAMAGE_MESSAGE; i++)

    {

        DamageText = GetTextBoxHandle("OnScreenMessageExWnd.DamageText-0-" $ i);

    }



    if(CREATE_ON_DEMAND==0)

    {

        Me = GetHandle( "OnScreenMessageExWnd" );

    }

    else

    {

        Me = GetWindowHandle( "OnScreenMessageExWnd" );

    }

}


Me.KillTimer(i + DAMAGE_MESSAGE_OFFSET + 1);
Me.SetTimer(i + DAMAGE_MESSAGE_OFFSET + 1, 2500);
 
Ребят кто поможет реализовать такое не много с компилом проблемы
Все работает я просто скопировал и вставил и сразу заработало + (В xdat добавил окно с текстовыми полями.)
 
Вот может кому пригодится, урон наносимый и наносимый вам.

1.jpg


Код автора темы я только добавил вывод урона по вам)
C++:
/******************************************

    Разработчик: BITHACK

    Copyright (c) 1995,2022 Ваша компания

    Описание скрипта:....

 *******************************************/
class BIT_DemageHUD extends UICommonAPI;

  var WindowHandle Me;

  const DAMAGE_MESSAGE_OFFSET = 100;
  const MAX_DAMAGE_MESSAGE = 28;
  var TextBoxHandle DamageText[MAX_DAMAGE_MESSAGE]; //именно столько нам нужно TextBox в xdat, т.е. 28

function OnRegisterEvent(){ /* Регистрация игровых событий */

    RegisterEvent(EV_SystemMessage);

  }

function OnLoad() {

     local int i;

    Me = GetWindowHandle("BIT_DemageHUD");

 for (i=0; i<=MAX_DAMAGE_MESSAGE; i++){
    DamageText[i] = GetTextBoxHandle("BIT_DemageHUD.D-" $ i);
    DamageText[i].SetText("");
  }

  }

function OnEvent(int Event_ID, string a_param){

  if(Event_ID == EV_SystemMessage) {
    HandleSystemMessage(a_param);
  }

  }

function HandleSystemMessage (string a_Param){

     local Color RedColor, WhiteColor;
     local int SystemMsgIndex;

    ParseInt(a_Param,"Index",SystemMsgIndex);

    RedColor.R =  205;  RedColor.G = 0;  RedColor.B = 0;

    WhiteColor.R = 255;  WhiteColor.G = 255;  WhiteColor.B = 255;

  switch (SystemMsgIndex)
{
    case 2261: //player msg
    case 2281: //summoner msg
    DemageHud(WhiteColor, a_param); //Наш урон, цвет белый
      break;
    case 2262: //player msg
    case 2263: //player msg
    DemageHud(RedColor, a_param); //Урон от противника, цвет красный
      break;
  }

  }


function  DemageHud(Color DColor, string a_param){

     local int DamageToPlayer, i;

 for(i=0; i <= MAX_DAMAGE_MESSAGE; i++)
{
  if(DamageText[i].GetText() == "") //гоняем циклом пока не упираем в свободный TextBox
{
    DamageText[i].SetAlpha(255); //принудительно делаем непрозрачным, в теории можно покрутить плавное появление

    ParseInt( a_Param, "Param3", DamageToPlayer); //цифра урона
    DamageText[i].SetText(string(DamageToPlayer)); //установить цифру урона в свободный индекс массива текстобоксов
    DamageText[i].SetAnchor( "BIT_DemageHUD", "BottomCenter", "BottomCenter", -120 + Rand(150), Rand(100) ); //выбираем случайную точку
    DamageText[i].ClearAnchor(); //убираем якорь с окна после предыдущего действия
    DamageText[i].Move(0, -1500, 8f); //начинаем движение текстбокса на -1500 (вверх) со скоростью 8
    DamageText[i].SetTextColor(DColor);
    DamageText[i].SetAlpha( 0, 2.8f ); //плавно делаем текстбокс прозрачным
    Me.KillTimer(i + DAMAGE_MESSAGE_OFFSET + 1); //убиваем таймер (индекс + константа + 1)
    Me.SetTimer(i + DAMAGE_MESSAGE_OFFSET + 1, 2500); //заводим таймер именно для этого текстбокса исходя из того же (индекс + константа + 1)
      break;
  }
  }

  }

function OnTimer (int TimerID){

    Me.KillTimer(TimerID); //убиваем любой таймер в самом начале, тут ИД нам не важен

  if(TimerID >= 101 && TimerID <= 200) //Тут подключается логика завода таймер индекс + DAMAGE_MESSAGE_OFFSET
{
    DamageText[TimerID-DAMAGE_MESSAGE_OFFSET-1].SetText(""); //удаляем текст с текстбокса, что бы он освободился
  }

  }

    defaultproperties{}

1667113792557.png
 
Все тот же код только без таймера, надеюсь автор будет не против)
C++:
/******************************************

    Разработчик: BITHACK

    Copyright (c) 1995,2022 Ваша компания

    Описание скрипта: Вывод урона на экран

 *******************************************/
class BIT_DemageHUD extends UICommonAPI;

  const MAX_DAMAGE_MESSAGE = 28;

  var TextBoxHandle DamageText[MAX_DAMAGE_MESSAGE]; //именно столько нам нужно TextBox в xdat, т.е. 28
  var int i;
  var Color RedColor, WhiteColor;

function OnRegisterEvent(){ /* Регистрация игровых событий */

    RegisterEvent(EV_SystemMessage);
  }

function OnLoad() {

 for ( i=0; i <= MAX_DAMAGE_MESSAGE; i++){
    DamageText[i] = GetTextBoxHandle("BIT_DemageHUD.D-" $ i);
    DamageText[i].SetText("");
  }
  }

function OnEvent(int Event_ID, string a_param){

   if(Event_ID == EV_SystemMessage) {
    HandleSystemMessage(a_param);
  }
  }

function HandleSystemMessage (string a_Param){

     local int SystemMsgIndex;

    ParseInt(a_Param,"Index",SystemMsgIndex);

  switch (SystemMsgIndex)
{
    case 2261: //player msg
    case 2281: //summoner msg
    DemageHud(WhiteColor, a_param);
      break;
    case 2262: //Enemy msg
    case 2263: //Enemy msg
    DemageHud(RedColor, a_param);
      break;
  }
  }

function DemageHud(Color DColor, string a_param){

     local String DamageToPlayer;

 for(i=0; i <= MAX_DAMAGE_MESSAGE; i++){
   if(DamageText[i].GetText() == "" || DamageText[i].GetAlpha() <= 0){ //гоняем циклом пока не упираем в Alpha = 0 или пустой TextBox
    DamageText[i].SetText("");
    DamageText[i].SetAlpha(255); //принудительно делаем непрозрачным, в теории можно покрутить плавное появление
    ParseString(a_Param, "Param3", DamageToPlayer); //цифра урона
    DamageText[i].SetText(DamageToPlayer); //установить цифру урона в свободный индекс массива текстобоксов
    DamageText[i].SetAnchor( "BIT_DemageHUD", "BottomCenter", "BottomCenter", -120 + Rand(150), Rand(100) ); //выбираем случайную точку
    DamageText[i].ClearAnchor(); //убираем якорь с окна после предыдущего действия
    DamageText[i].Move(-100, -1500, 8f); //начинаем движение текстбокса на -1500 (вверх) со скоростью 8
    DamageText[i].SetTextColor(DColor); //Меняем цвет урона
    DamageText[i].SetAlpha( 0, 4f ); //плавно делаем текстбокс прозрачным
      break;
  }
  }
  }
    defaultproperties{
    RedColor=(R=255,A=255)
    WhiteColor=(B=255,G=255,R=255,A=255)
  }
 
Все тот же код только без таймера, надеюсь автор будет не против)
C++:
/******************************************

    Разработчик: BITHACK

    Copyright (c) 1995,2022 Ваша компания

    Описание скрипта: Вывод урона на экран

 *******************************************/
class BIT_DemageHUD extends UICommonAPI;

  const MAX_DAMAGE_MESSAGE = 28;

  var TextBoxHandle DamageText[MAX_DAMAGE_MESSAGE]; //именно столько нам нужно TextBox в xdat, т.е. 28
  var int i;
  var Color RedColor, WhiteColor;

function OnRegisterEvent(){ /* Регистрация игровых событий */

    RegisterEvent(EV_SystemMessage);
  }

function OnLoad() {

 for ( i=0; i <= MAX_DAMAGE_MESSAGE; i++){
    DamageText[i] = GetTextBoxHandle("BIT_DemageHUD.D-" $ i);
    DamageText[i].SetText("");
  }
  }

function OnEvent(int Event_ID, string a_param){

   if(Event_ID == EV_SystemMessage) {
    HandleSystemMessage(a_param);
  }
  }

function HandleSystemMessage (string a_Param){

     local int SystemMsgIndex;

    ParseInt(a_Param,"Index",SystemMsgIndex);

  switch (SystemMsgIndex)
{
    case 2261: //player msg
    case 2281: //summoner msg
    DemageHud(WhiteColor, a_param);
      break;
    case 2262: //Enemy msg
    case 2263: //Enemy msg
    DemageHud(RedColor, a_param);
      break;
  }
  }

function DemageHud(Color DColor, string a_param){

     local String DamageToPlayer;

 for(i=0; i <= MAX_DAMAGE_MESSAGE; i++){
   if(DamageText[i].GetText() == "" || DamageText[i].GetAlpha() <= 0){ //гоняем циклом пока не упираем в Alpha = 0 или пустой TextBox
    DamageText[i].SetText("");
    DamageText[i].SetAlpha(255); //принудительно делаем непрозрачным, в теории можно покрутить плавное появление
    ParseString(a_Param, "Param3", DamageToPlayer); //цифра урона
    DamageText[i].SetText(DamageToPlayer); //установить цифру урона в свободный индекс массива текстобоксов
    DamageText[i].SetAnchor( "BIT_DemageHUD", "BottomCenter", "BottomCenter", -120 + Rand(150), Rand(100) ); //выбираем случайную точку
    DamageText[i].ClearAnchor(); //убираем якорь с окна после предыдущего действия
    DamageText[i].Move(-100, -1500, 8f); //начинаем движение текстбокса на -1500 (вверх) со скоростью 8
    DamageText[i].SetTextColor(DColor); //Меняем цвет урона
    DamageText[i].SetAlpha( 0, 4f ); //плавно делаем текстбокс прозрачным
      break;
  }
  }
  }
    defaultproperties{
    RedColor=(R=255,A=255)
    WhiteColor=(B=255,G=255,R=255,A=255)
  }
На самом деле я действительно не знаю, что мной двигало, когда я крутил всё через таймер, хотя сам же запускаю элемент с плавной альфой до нуля, что по сути и есть проверка на условный null.

Но зато какой полёт для рефакторинга.
1668767903383.png
 
Все тот же код только без таймера, надеюсь автор будет не против)
C++:
/******************************************

    Разработчик: BITHACK

    Copyright (c) 1995,2022 Ваша компания

    Описание скрипта: Вывод урона на экран

 *******************************************/
class BIT_DemageHUD extends UICommonAPI;

  const MAX_DAMAGE_MESSAGE = 28;

  var TextBoxHandle DamageText[MAX_DAMAGE_MESSAGE]; //именно столько нам нужно TextBox в xdat, т.е. 28
  var int i;
  var Color RedColor, WhiteColor;

function OnRegisterEvent(){ /* Регистрация игровых событий */

    RegisterEvent(EV_SystemMessage);
  }

function OnLoad() {

 for ( i=0; i <= MAX_DAMAGE_MESSAGE; i++){
    DamageText[i] = GetTextBoxHandle("BIT_DemageHUD.D-" $ i);
    DamageText[i].SetText("");
  }
  }

function OnEvent(int Event_ID, string a_param){

   if(Event_ID == EV_SystemMessage) {
    HandleSystemMessage(a_param);
  }
  }

function HandleSystemMessage (string a_Param){

     local int SystemMsgIndex;

    ParseInt(a_Param,"Index",SystemMsgIndex);

  switch (SystemMsgIndex)
{
    case 2261: //player msg
    case 2281: //summoner msg
    DemageHud(WhiteColor, a_param);
      break;
    case 2262: //Enemy msg
    case 2263: //Enemy msg
    DemageHud(RedColor, a_param);
      break;
  }
  }

function DemageHud(Color DColor, string a_param){

     local String DamageToPlayer;

 for(i=0; i <= MAX_DAMAGE_MESSAGE; i++){
   if(DamageText[i].GetText() == "" || DamageText[i].GetAlpha() <= 0){ //гоняем циклом пока не упираем в Alpha = 0 или пустой TextBox
    DamageText[i].SetText("");
    DamageText[i].SetAlpha(255); //принудительно делаем непрозрачным, в теории можно покрутить плавное появление
    ParseString(a_Param, "Param3", DamageToPlayer); //цифра урона
    DamageText[i].SetText(DamageToPlayer); //установить цифру урона в свободный индекс массива текстобоксов
    DamageText[i].SetAnchor( "BIT_DemageHUD", "BottomCenter", "BottomCenter", -120 + Rand(150), Rand(100) ); //выбираем случайную точку
    DamageText[i].ClearAnchor(); //убираем якорь с окна после предыдущего действия
    DamageText[i].Move(-100, -1500, 8f); //начинаем движение текстбокса на -1500 (вверх) со скоростью 8
    DamageText[i].SetTextColor(DColor); //Меняем цвет урона
    DamageText[i].SetAlpha( 0, 4f ); //плавно делаем текстбокс прозрачным
      break;
  }
  }
  }
    defaultproperties{
    RedColor=(R=255,A=255)
    WhiteColor=(B=255,G=255,R=255,A=255)
  }
В какой файл в Interface.u нужно вставить данный скрипт ?) Извините за нубство)
 
А подскажите где менять размер самих цифр урона
 
Назад
Сверху Снизу