XGM Forum
Сайт - Статьи - Проекты - Ресурсы - Блоги

Форуме в режиме ТОЛЬКО ЧТЕНИЕ. Вы можете задать вопросы в Q/A на сайте, либо создать свой проект или ресурс.
Вернуться   XGM Forum > Warcraft> Академия: форум для вопросов> Jass
Ник
Пароль
Войти через VK в один клик
Сайт использует только имя.

Ответ
 
ShadoW DaemoN

offline
Опыт: 37,078
Активность:
Распространенные ошибки Jass программистов (by ADOLF)
Автор: ADOLF.

Распространенные ошибки Jass программистов

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

Оформление кода.

Вот отрывок кода, его надо несколько раз перечитать, чтобы понять, к какому блоку что относиться. Мне сначала показалось, что endloop - окончание функции, далее идет объявление другой. Логику расстановки отступов понять я так и не смог.
((код jass
local real StartLife = 0.
local real EndLife = 0.
if Time < 1 and GetWidgetLife(Dummy) > 0.405 then
call GroupEnumUnitsInRange(Group,X,Y,120,null)
loop
set Picked = FirstOfGroup(Group)
exitwhen Secret_Pirouette_Filter(Caster,Picked) == true or Picked == null
call GroupRemoveUnit(Group,Picked)
endloop
if Picked != null then
if LoadBoolean(udg_Hashtable,Handle,7) == true then
set StartLife = GetUnitState(Picked,UNIT_STATE_LIFE)
endif
call UnitDamageTarget(Caster,Picked,Damage, true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_MAGIC, null)
call Secret_Pirouette_DPS(Caster,Picked,25,LoadBoolean(udg_Hashtable,Handle,7))
call DummyCastTarget(Caster,Picked,Level,'A001',"thunderbolt")//Raw-code
if LoadBoolean(udg_Hashtable,Handle,7) == true then
set EndLife = GetUnitState(Picked,UNIT_STATE_LIFE)
call TextTag(Picked,udg_PlayerColors[GetPlayerId(GetOwningPlayer(Caster))+1]+"-"+I2S(R2I(StartL​ife-EndLife))+"|r",8)
endif
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Weapons\\WingedSerpentMissile\\WingedSerpentMi​ssile.mdl",Picked,"origin"))
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.​mdl",Picked,"origin"))
call KillUnit(Dummy)
call SaveReal(udg_Hashtable,Handle,9,10)
endif
=====
call SetUnitX(Dummy,X+Speed*Cos(Angle-25))
call SetUnitY(Dummy,Y+Speed*Sin(Angle-25))
))
Добавить побольше ASCII-графики, можно написать, какое у вас настроение, или скопировать старый анекдот, что бы код было читать веселее.
((код jass
*********************\\-------------------------------------------------------\\
=====================\\ *** * ***** **** **** ***** * * \\
Timer Library \\ * * * * * * * * * * * * * \\
by \\ ***** * **** ** **** **** **** *** \\
ALEXPREY © \\ * * * * * * * * * * * * \\
=====================\\ * ***** ***** * * ***** ** \\
*********************\\-------------------------------------------------------\\
))
Даешь осмысленные комментарии! ФИЛЬТР! Я СКАЗАЛ ГОРБА ФИЛЬТР! Главное, без комментария догадаться, что эта функция что-то фильтрует, нельзя. Точно также, как и понять из комментария, что же именно фильтрует эта функция.
((код jass
ФИЛЬТР!
===============================
function Secret_Pirouette_Filter takes unit Caster,unit Picked returns boolean
return IsUnitEnemy(Picked,GetOwningPlayer(Caster)) and GetWidgetLife(Picked) > 0.405 and not IsUnitType(Picked,UNIT_TYPE_STRUCTURE) and not IsUnitType(Picked,UNIT_TYPE_MAGIC_IMMUNE) and not IsUnitType(Picked,UNIT_TYPE_MECHANICAL)
endfunction
===============================
))
На десерт.
((код jass
function Chat_Space takes nothing returns nothing
_________________________________________________
call ClearTextMessages()
_________________________________________________
endfunction
))
Хорош тот код, который не нуждается в комментариях. Назовите функцию CreateTextTag*** (OnUnit например) - и будет вам счастье.
((код jass
Проверка на неуязвимость. Автор - DioD (from XGM forum)
...
Вывод текста. Автора нет.
function TextTag takes unit u, string text, real height returns texttag
))

Перебор юитов в группах.

"Милый, заберешь сегодня нашего малого из детского садика."
Милый идет в садик, забирает оттуда домой всех детей, приводит их домой и начинает по одному проверять, не его ли это сын, если нет - отправляет ребенка назад в садик.
Также обратите внимание на b == true. Это неправильно. Для надежности надо писать (b == true and b != false), этому нас еще в свое время MPI3 учил. На самом деле надо писать просто b, например if b then...
((код jass
local group Group = CreateGroup()
...
call GroupEnumUnitsInRange(Group,X,Y,120,null)
loop
set Picked = FirstOfGroup(Group)
exitwhen Secret_Pirouette_Filter(Caster,Picked) == true or Picked == null
call GroupRemoveUnit(Group,Picked)
endloop
...
call DestroyGroup(Group)
set Group = null
))
Правильно:
((код jass
c_temp и t_temp - глобальные переменные
gr_temp - Глобальная, всегда пустая группа, создання для переборов юнитов
JASS
function foo takes nothing returns boolean
if t_temp == null and SecretPirouetteFilter (c_temp, GetFilterUnit()) then
set t_temp = GetFilterUnit()
endif
return false
endfunction
...
set c_temp = Caster
set t_temp = null
call GroupEnumUnitsInRange (gr_temp, x, y, 120., Condition(function Foo))
cJass
c_temp = Caster
t_temp = null
GroupEnumUnitsInRange (gr_temp, x, y, 120., Condition(lambda boolean () {
if (t_temp == null && SecretPirouetteFilter (c_temp, GetFilterUnit()) {
t_temp = GetFilterUnit()
}
return false
}))
))
При работе с глобальными переменными, используемыми многими функциями, важно учитывать возможность остановки потока и запуска другого, в котором она может быть перезаписана.

Запись в хеш

Что это за ключ 1? Юнит-пустышка? Юнит, применивший способность? Цель? А вы наверное и переменные называете u1, u2 и т.д.?
((код jass
call SaveUnitHandle(udg_Hash,GetHandleId(t),1,u)
))
Неправильно решение проблемы - высока возможность опечатки, да и вообще, криво это все.
((код jass
call RemoveSavedHandle(udg_Hashtable,GetHandleId(Caster),StringHash("Omnislash Caster Trigger"))
))
Внимание, правильный ответ:
((код jass
JASS
globals
constant integer HASHKEY_OMNISLASH_CASTER = 1
constant integer HASHKEY_OMNISLASH_TARGET = 2
endglobals
...
call RemoveSavedHandle (udg_Hashtable, GetHandleId(Caster), HASHKEY_OMNISLASH_CASTER)
cJass
enum (HASHTABLENAME_KEYS) {
HASHKEY_OMNISLASH_CASTER
HASHKEY_OMNISLASH_TARGET
}
...
RemoveSavedHandle (udg_Hashtable, GetHandleId(Caster), HASHKEY_OMNISLASH_CASTER)
))

Обнулить всё!

Чем больше всего обнулить, тем быстрее будет работать.
((код jass
local real StartLife = 0.
local real EndLife = 0.
...
set StartLife = 0.
set EndLife = 0.
))
Самые продвинутые обнуляют даже boolean.
((код jass
local boolean TextMessages = true
...
set TextMessages = false
endfunction
))
Скалярные локальные переменные обнулять не нужно. Не нужно! Ещё раз - не нужно! integer, boolean, real не нужно обнулять. Вообще, сам термин обнуления некорректен.
Утечки могут быть вызваны удаленными объектами, на которые остались ссылки. Читайте мое добавление к статье Сергея "Осваиваем jass", там об этом подробно.

Отредактировано ShadoW DaemoN, 28.04.2011 в 17:07.
Старый 27.04.2011, 21:23
Doc

offline
Опыт: 63,163
Активность:
Даеш еще!
Алсо не очень понял что там про комментарии к функции TextTag.
Установил статус важной :3
Старый 27.04.2011, 21:47
Nekit1234007

offline
Опыт: 11,916
Активность:
Шик. Неужели кто-то подумал, что перебор группы лупом хорошо оценят?
Старый 27.04.2011, 21:55
iZucken
ШТО
offline
Опыт: 17,960
Активность:
Вкусно :3
какое счастье, за мной ничего этого не водится
Старый 27.04.2011, 22:07
Hanabishi
COOL STATUS
offline
Опыт: отключен
круто, адик умеет "ненавязчиво ткнуть рожей" в ошибки=)
Старый 27.04.2011, 22:41
Rampage
Бицепс
offline
Опыт: 9,722
Активность:
Да, я краб. Ну что ж.
Rampage добавил:
Я ни одной статьи не прочитал про Jass, и обнулял реальные. Кстати, это спелл я из-за крабовства и отменил. В Omnislash'e максимально аккуратно делал.
call RemoveSavedHandle(udg_Hashtable,GetHandleId(Caster),StringHash("Omnislash Caster Trigger"))
Чем плохо? Нормально.
Старый 28.04.2011, 13:04
DotaMaster666
Silenced by GadenbIsh
offline
Опыт: 1,259
Активность:
Чем плохо? Нормально.
call SaveUnitHandle(udg_Hashtable,GetHandleId(Caster),StringHash("Omnislash Caster Trigger"), u)
call Foo(13, 42, 53)
if Bar() or FooBar!=0 then
    call SaveUnitHandle(udg_Hashtable,GetHandleId(Caster),StringHash("Onmislash Caster Trigger"), u)
endif
Старый 28.04.2011, 13:15
spellwerk

offline
Опыт: 4,869
Активность:
call SaveUnitHandle(udg_Hash,GetHandleId(t),1,u)
действительно ужасно =(
Spy_ добавил:
и, кстати, может я чего то не понимаю:
        if lvl == 1 then
            return 15.00
        elseif lvl == 2 then
            return 30.00
        elseif lvl == 3 then
            return 45.00
        endif
не проще ли
return 15.*lvl
?
Старый 28.04.2011, 14:03
Hanabishi
COOL STATUS
offline
Опыт: отключен
Spy_, ну там могут быть кастом цифры, не связанные напрямую с уровнем
Старый 28.04.2011, 14:25
SRes
1110101000
offline
Опыт: 9,997
Активность:
"некоректен"
Некорректен.
После безграмотных дотеров большую часть ошибок не заметил, каюсь.

Дополнил:
"например: if b then..."

Как-то по китайски написан первый абзац.
Так мастер Йода писал бы, уверен я.

Отредактировано SRes, 28.04.2011 в 16:23.
Старый 28.04.2011, 15:51
Rewenger
The culprit will not die
offline
Опыт: 35,273
Активность:
поддержим грамматического нациста выше
незнание, казалось бы, банальных
чтобы понять, к какому блоку
ASCII-графики
догадаться, что эта функция что-то фильтрует, нельзя
приводит их домой и начинает (надо без запятой)
Это неправильно.
вот уж действительно
переменными, используемыми многими функциями, важно
Что это за ключ 1? Юнит-пустышка?
да и вообще, криво это все
Внимание, правильный ответ
Старый 28.04.2011, 16:06
Clamp
Lost in space
offline
Опыт: 71,258
Активность:
ShadoW_DaemoN:
обратите внимание на b == true. Это не правильно. Для надежности надо писать (b == true and b != false)
плакал =)
ShadoW_DaemoN:
Самые продвинутые обнуляют даже boolean.
уже даже не плакал - рыдал! =DDDD
Старый 28.04.2011, 16:20
Master_chan
Полуночный командир
offline
Опыт: 15,660
Активность:
Написано под впечатлением от проверки Spell Contest. пораньше бы Т_Т
Старый 28.04.2011, 16:56
ARHUI

offline
Опыт: 3,341
Активность:
Код:
function foo takes nothing returns boolean
 if t_temp == null and SecretPirouetteFilter (c_temp, GetFilterUnit()) then
     set t_temp = GetFilterUnit()
 endif
 return false
endfunction
...
set c_temp = Caster
set t_temp = null
call GroupEnumUnitsInRange (gr_temp, x, y, 120., Condition(function Foo))


Я конечно понимаю, что это не весь код, но разве такая реализация применима к случаю запуска кода несколько раз подряд, переменные не успеют перезаписаться?

Я ни в коем случае не критикую, сам ещё разбираюсь...
Старый 29.04.2011, 21:24
agentex

offline
Опыт: 34,534
Активность:
не успеют
Старый 29.04.2011, 21:29
DioD

offline
Опыт: 45,184
Активность:
Распространенные ошибки Jass программистов (by ADOLF)
ошибка номер 0 - Они считают себя программистами.
Старый 30.04.2011, 15:17
Hanabishi
COOL STATUS
offline
Опыт: отключен
Они считают себя программистами.
кстати да, это всё равно что web-дизайнеры себя программистами посчитают, т.к. по факту jass - это скрипт
Старый 30.04.2011, 18:00
Faion
Noblesse Oblige
offline
Опыт: 30,395
Активность:
Ну раз заговорили о читабельности...

Обратил внимание что все юзеры cjass оформляют код вот так:

Код:
enum (HASHTABLENAME_KEYS) {
    HASHKEY_OMNISLASH_CASTER
    HASHKEY_OMNISLASH_TARGET
}


Рекомендую для большей читабельности оформлять вот так:

Код:
enum (HASHTABLENAME_KEYS) 
{
    HASHKEY_OMNISLASH_CASTER
    HASHKEY_OMNISLASH_TARGET
}


В сложных конструкциях подобное оформление существенно облегчает работу с различными конструкциями.

или

Код:
enum (HASHTABLENAME_KEYS) {HASHKEY_OMNISLASH_CASTER;HASHKEY_OMNISLASH_TARGET}


Просто пример компактного оформления=)

Так же отмечу что такое оформление удобно тем, что при сворачивании кода(я о +\- слева конструкций) оставляет "верхушку", так становится понятнее что свернули.

Думаю те кто юзают C# меня поддержут=)

Так же рекомендую всем создавать под себя как можно больше функций даже под простые вещи, такие как:
Код:
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.​mdl",Picked,"origin"))


К примеру:

Код:
function CreateSFX takes string e, real x, real y returns nothing
    DestroyEffect(AddSpecialEffect(e,x,y))
endfunction


или

Код:
function CreateOnCaster takes string e returns nothing
    DestroyEffect(AddSpecialEffect(e,GetUnitX(GetTriggerUnit()),GetUnitY(GetTriggerU  nit())))
endfunction
Старый 30.04.2011, 23:09
Doc

offline
Опыт: 63,163
Активность:
Faion, зачем функции лол? дефайны на что?
алсо, насчет скобочек, я везде так пишу, screenshot.su/show.php?img=939863ae17352e866cf356cdef844637.jpg , т.к. имхо это правильнее, хотя это личное дело каждого.
Старый 30.04.2011, 23:17
Faion
Noblesse Oblige
offline
Опыт: 30,395
Активность:
Цитата:
Сообщение от Doc
Faion, зачем функции лол? дефаны на что?


Рандомный пример для тех то були обнуляет, очевидно же.

Цитата:
Сообщение от Doc
алсо, насчет скобочек, я везде так пишу, screenshot.su/show.php?img=939863ae17352e866cf356cdef844637.jpg , т.к. имхо это правильнее, хотя это личное дело каждого.


ну вс автоматом подобным образом проставляет блоки и хочу отметить что значительно делает код читабельнее.
Старый 30.04.2011, 23:20
Ответ

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы можете скачивать файлы

BB-коды Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход



Часовой пояс GMT +3, время: 12:45.