Полезные скрипты для GMS

Мелкие скрипты, написанные для себя и используемые в проектах.

 

Заполнение разрядов перед числом нулями

Пример:
zero(123, 5) -> 00123

/// zero(value, bits)

var t = string(floor(argument0)); // убрать округление, если необходимы дроби
repeat (argument1 - string_length(t))
{
    t = "0" + t;
}

return t

 

Вывод числа с интерактивным отображением дробной части

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

5.73 -> “5.7”
5.76 -> “5.8”
10.73 -> “10”

/// rounding_string(val)

if argument0<10
{
    if frac(argument0) == 0
    {
        return string_format(argument0, 1, 0);
    }
    else
    {
        return string_format(argument0, 1, 1);
    }
}
else
{
    return string(floor(argument0));
}

 

Перевод строки в массив.

Тут всё очень просто.
a = string_to_array(“12,10,15,18,19,20,50,51,40,38,32,16,19,3,17,0,11,1,6,31,2”) // и так далее
a[0] -> 12
a[1] -> 10
и так далее…

/// string_to_array(string)

var i, val;

var len = string_length(argument0);
var data = argument0;
var result = 0;

for (i=1; i<100; i++)
{
    val = get_part(data, i, ",");
    if val="" break;
    result[i-1] = real(val);
}

return result;

 

Получение элемента строки.

В предыдущем скрипте используется скрипт get_part, который позволяет взять определённый элемент из строки.
Задаётся строка, номер элемента и разделитель.
Например:
get_part(“Новичок|Бывалый|Мастер|Гуру”, 2, “|”) -> “Бывалый”
При ошибке возвращает пустую строку.

/// get_part(string, section, separator)

var s1, s2, res, _string, _section, _separator;
_string = argument0
_section = max(argument1, 1)
_separator = argument2

_string = _separator+_string+_separator

s1 = find_char(_string, _section, _separator)
s2 = find_char(_string, _section+1, _separator)

if s1<0 or s2<0
{
    return ""
}

res = string_copy(_string, s1+1, s2-s1-1)
return res

 

Поиск символа в строке

Используется предыдущим скриптом.
Задаём строку, номер символа, и сам символ.

Например, в строке нужно найти положение второго символа “a”:
find_char(“abcabcabc”, 2, “a”) -> 4
Возвращает -1 при отсутствии символа.

/// find_char(string,no,symbol)

var sz, n, i;

sz = string_length(argument0) + 1

n=0
for(i=1; i<sz; i++)
{
    if string_char_at(argument0, i)=argument2
    {
        n++
        if n=argument1 return i
    }
}
return -1

 

Сортировка массива

Передаём в скрипт одномерный массив, на выходе получаем его же, но в сортированном виде.

/// array_sort(array)

var lst = ds_list_create()

for (i=0; i<array_length_1d(argument0); i++)
{
    ds_list_add(lst, argument0[i])
}

ds_list_sort(lst, true)

var res;

for (i=0; i<ds_list_size(lst); i++)
{
    res[i] = ds_list_find_value(lst, i)
}

ds_list_destroy(lst)

return res

GameMaker: Studio Early Acces 1.99.55

Список изменений:

Изменения по сурфейсу приложения

  • КРИТИЧЕСКОЕ ИЗМЕНЕНИЕ: Сурфейсы теперь наращиваемые (stackable, работают как стек). Это означает, что каждое surface_set_target() ОБЯЗАНО иметь закрывающий вызов surface_reset_target(). Игнорирование этого требования приведет к ошибке во время выполнения.
  • Новая встроенная переменная application_surface, содержащая указатель на сурфейс приложения.
  • Позволяет делать корректировку соотношения сторон на всех платформах.
  • window_set_size() больше не влияет на разрешение/масштабирование игры. Теперь эти свойства контролируются через application_surface и surface_resize().
  • Добавлено новое демо, которое показывает переход между сценами, демонстрируя преимущества нового application_surface.
  • ПРИМЕЧАНИЕ 1: всё перечисленное выше пока что не доступно на HTML5! (Будет реализовано в следующей версии EA)
  • ПРИМЕЧАНИЕ 2а: с этой системой, захват области экрана в данный момент не работает на мобильных платформах, поэтому вы не можете воспользоваться get screen_save() или draw_getpixel() в этой версии.
  • ПРИМЕЧАНИЕ 2б: также знайте, что, поскольку теперь есть разделение размеров GUI и application_surface, то, если они не 1:1, вы не сможете захватывать данные через draw_getpixel(), как делали в предыдущих версиях, особенно, если есть корректировка соотношения сторон. Возможно, что вам придётся скорректировать свои значения.



Новые функции

  • timeline_clear() – полная очистка таймлайна
  • timeline_moment_add_script() – добавить вызов скрипта в нужный момент таймлайна
  • timeline_size() – возвращает размер таймлайна, число моментов
  • timeline_max_moment() – возвращает максимальный момент в таймлайне
  • buffer_get_address() – получить адрес основной памяти в буфере
  • gml_release_mode() – переключение режима публикации (релиза) (в этом режиме делается меньше проверок на ошибки)
  • tile_get_count() – получить количество тайлов
  • tile_get_id() – получить id нужного тайла
  • tile_get_ids() – получить id всех тайлов
  • tile_get_ids_at_depth() – получить id всех тайлов с заданной глубиной
  • angle_difference() – получить разницу между двумя углами
  • draw_roundrect_ext() – рисование прямоугольника со скруглениями
  • draw_roundrect_color_ext() – рисование прямоугольника со скруглениями
  • window_device() – возвращает указатель на окно устройства (D3D Handle в Windows)
  • dsin(x),dcos(x),dtan(x),darcsin(x),darccos(x),darctan(x),darctan2(x) – тригонометрические функции, работающие с градусами
  • mp_grid_get_cell() – получение состояния клетки из mp_grid
  • is_ptr – возвращает true, если переменная является указателем (ПРИМЕЧАНИЕ : функции window_device()window_handle() и get_texture теперь возвращают указатель, а не число)
  • device_mouse_x_to_gui(), device_mouse_y_to_gui() – получение координат мыши в пространстве GUI
  • surface_resize() – позволяет изменять размер сурфейса (без сохранения содержимого)
  • application_get_position() – получение позиции скорректированной с учётом соотношения сторон области внутри текущего окна
  • ds_list_add(), ds_queue_enqueue(), ds_stack_push() – изменения, позволяющие задавать множество значений
  • point_in_rectangle(), point_in_triangle(), point_in_circle() – функции проверки вхождения точки в заданный графический примитив
  • rectangle_in_rectangle(), rectangle_in_triangle(), rectangle_in_circle() – функции проверки вхождения прямоугольника в заданный графический примитив



Изменения в отладчике

  • Расширен тайм-аут связи для более надёжного соединения
  • Новая иконка
  • Добавлено отображение стека вызовов
  • Добавлено отображение списка всех экземпляров
  • Добавлено отображение выбранного экземпляра (только для Windows desktop платформы)
  • Диалоги на целевой платформе больше не прерывают отладчик, поэтому связь не теряется
  • Теперь происходит остановка при обнаружении ошибки на целевой платформе
  • Организация дерева ресурсов, каталоги и т.п. теперь отражается в отладчике
  • Добавленная частичная выборка для больших структур/массивов. ПРИМЕЧАНИЕ: в данный момент не доступно на HTML5!



Изменения в Студии

  • Объем потребляемой памяти был существенно уменьшен (приблизительно на 50%) – графика загружена не все время, а только при обращении к ней (сообщите нам о любых проблемах, которые заметите)
  • Добавлены настройки соотношения сторон в платформы, где их не было



Изменения в компиляторе

  • Добавлены новые способы доступа (аксессоры) к картам, сеткам и спискам, а также доступ к массивам по ссылке (не создаётся копия массива при записи)
  • Все функции, содержащие слово “color”, теперь имеют синоним с написанием “colour” (идентичная функция, но с корректным написанием). Вся документация и система завершения строки исправлены на “colour”



Изменения в раннере

  • http_request() теперь понимает бинарные буферы
  • На iOS функция show_message() не ждала реакции пользователя, если запуск был произведён из Студии. Исправлено.
  • Networking async event теперь передаёт номер порта в карту с ключом “port”
  • Steam Workshop uploads из Early Access 1.99.44 необходимо загрузить повторно в связи с изменениями формата файла



И, конечно же, исправления множества ошибок.

Аксессоры к структурам данных и массивам в GameMaker: Studio

Перевод: Dmi7ry
Оригинал: James Foreman

Последнее обновление (начиная с версии 1.2.1261]) GameMaker: Studio добавляет интересный дополнительный функционал для некоторых структур данных и обычным массивам, называемый “аксессоры” (Accessors, методы доступа). Эти аксессоры являются простыми логическими выражениями, которые позволяют вам добавлять или изменять значения в этих структурах и записываются таким образом, будто вы работаете с массивами, с тем отличием, что используется специальный идентификационный символ перед первым аргументом, который говорит GameMaker: Studio, что вы работаете со структурой данных (заранее созданной), либо напрямую с исходным массивом.

Вы можете добавлять, заменять и получать значения и ключи для следующих типов структур данных: ds_maps, ds_lists и ds_grids, каждый из которых имеет свой собственный символ для доступа, изменения или установки значения, как показано ниже. Для массивов этот функционал даёт вам прямой доступ к исходному массиву, передаваемому в скрипт, взамен стандартного поведения, когда передаётся копия массива, которое обычно и ожидается (это объясняется в конце статьи).

Также обратите внимание, что символы, выбранные для обозначения метода доступа, были выбраны в соответствии с их мнемонической природой (например, # – это идентификатор для ds_grid), что делает их более лёгкими для опознавания и запоминания.

ds_list [| ]

Синтаксис для списков следующий:

list_index[| index]

После создания списка с помощью ds_list_create(), вы можете использовать индекс списка, который у вас сохранён в переменной, для обращения к нему. Значение index здесь указывает на позицию элемента в списке, который вы хотите добавить или установить. Например, следующий код создаёт список и добавляет 10 записей, каждая из которых будет содержать случайное число от 0 до 9:

ds = ds_list_create();

var index = 0;

repeat(10)
{
    ds[| index++] = irandom(9);
}

После создания вашего списка и заполнения его данными, чтобы получить значение из списка, нужно сделать что-нибудь типа этого:

value = ds[| 5];

Этот код получает значение из элемента 5 (но это шестая позиция в списке, так как нумерация начинается с нуля) и сохраняет его в переменную. Обратите внимание, что если вы используете выражение для добавления ссылки на элемент, который уже имеет значение, то предыдущее значение будет заменено новым, а не просто добавится в список. Чтобы добавить дополнительные элементы, нужно узнать размер структуры данных (ds_list_size) и добавить их в её конец. Ещё нужно отметить, что вы также можете задать индекс элемента больше, чем их количество в списке – в этом случае установится заданный элемент, одновременно увеличивая список и заполняя все предыдущие элементы нулём.

ds​_map [? ]

Синтаксис для карт следующий:

map_index[? key]

После создания вашей карты с помощью ds_map_create(), вы должны использовать индекс карты, сохранённый в переменной, чтобы обращаться к ней. Значение “key” указывает на ключ карты, который необходимо записать или прочитать. Например, следующий код создаёт карту и после добавляет несколько записей, используя этот синтаксис:

ds = ds_map_create();

ds[? "Name"] = "Hamish";

ds[? "Company"] = "MacSeweeny Games";

ds[? "Game"] = "Catch The Haggis";

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

value = ds[? "Name"];

Этот код получает значение из ключа “Name” и сохраняет его в переменную. Обратите внимание, что если при записи значения, в карте уже содержится запись с таким ключом, то предыдущее значение будет заменено новым.

ds_grid [# ]

Синтаксис для сеток следующий:

grid_index[# xpos, ypos]

После создания вашей сетки с помощью ds_grid_create(), вы должны использовать индекс сетки, сохранённый в переменной, чтобы обращаться к ней. Значения “xpos” и “ypos” указывают на элемент сетки, который необходимо записать или прочитать. Например, следующий код создаёт сетку, очищает её нулём и после добавляет несколько записей в неё:

ds = ds_grid_create();

ds_grid_clear(ds, 0);

var gw = ds_grid_width(ds) - 1;

var gh = ds_grid_height(ds) - 1;

repeat(10)

{
    var xx = irandom(gw);

    var yy = irandom(gh);

    if ds[# xx, yy] == 0 ds[# xx, yy] = 1;
}

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

value = ds[# mouse_x div 16, mouse_y div 16];

Этот код получает значение из сетки, основываясь на координатах мыши (поделенных на размер “клетки” в комнате, чтобы получить корректную позицию).

Массивы.

Обычный метод работы GameMaker: Studio с массивами – “копирование при записи”, означающий, что при передаче массива (как пример) в скрипт, передаётся ссылка на оригинальный массив, но при изменении любого значения массива, будет создана копия массива. Это означает, что для того, чтобы получить новые значения, которые вы установили, вы должны вернуть массив из скрипта и переназначить его исходной переменной массива. Например:

//CREATE EVENT
a[9] = 0; //initialise a 10 value array

​
//CALL A SCRIPT WITH THE ARRAY
a = scr_Set_Array(a);

 
//SCRIPT
var temp_a = argument0;

temp_a[3] = 10;

return temp_a;

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

array[@ val]; //1D array

array[@ val, val]; //2D array

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

//CREATE EVENT
a[9] = 0; //initialise a 10 value array


//CALL A SCRIPT WITH THE ARRAY
a = scr_Set_Array(a);


//SCRIPT
var temp_a = argument0;

temp_a[@ 3] = 10;

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

Расширения для iOS и Android в GameMaker: Studio

Перевод статьи iOS & Android Extensions
Автор: James Foreman
Перевод: Dmi7ry

Буду благодарен сообщениям об опечатках и улучшениях перевода.

 

Обновление версии 1.3 вносит в GameMaker: Studio много новых и интересных функций: SWF-импорт, Push-уведомления, переработанную систему внутриигровых покупок. Тем не менее, возможно, что самой важной частью этого обновления является открытие системы расширений, что позволит использовать сторонние SDK и нативный код в Ваших играх.

Для начала, нативные расширения будут доступны только для платформ iOS и Android (постепенно будут добавлены и другие целевые платформы), поэтому в данной статье будут изложены общие принципы добавления расширений в свои игры именно для этих платформ. Впрочем, для будущих добавленных платформ не должно быть каких-либо существенных отличий.

Стоит отметить, что расширения для платформы iOS должны быть написаны с использованием Objective C++, в то время как расширения для Android должны писаться на Java. В данной статье предполагается, что если Вы пишете, либо используете нативные расширения, то у вас уже есть практические знания нативного языка для выбранной платформы.

 

Приступаем

Создание расширений в GameMaker: Studio просто и требует от вас клика правой кнопкой мыши на папке Extensions в дереве ресурсов и последующего клика на “Create Extension”.

После этого появится окно Extension Package Properties (свойства пакета расширений), в котором, во вкладке General, Вам нужно заполнить поля “name” (имя), “author” (автор) и другие, для расширения, которое Вы создаёте. Сделав это, Вам нужно заполнить детали формы для выбранной платформы в соответствующей вкладке. Обратите внимание, что пакет расширений может содержать расширения для нескольких платформ. Поэтому, если у вас есть стороннее SDK с файлами для Android и iOS, Вы можете создать один пакет, который будет содержать и то и другое. Затем в своей конфигурации нужно установить, чтобы экспортировалось только то, что Вам нужно (подробнее об этом позже).

Каждый тип расширений требует, чтобы Вы указали ClassName (имя класса), идентифицирующий его, и Source Directory (исходная папка). Это исходная папка, так как расширения для платформ iOS и Android не требуют, чтобы Вы добавляли файлы непосредственно в GameMaker: Studio, как расширения JS или DLL (хотя для корректной работы они, в настоящее время, требуют файл-болванку, как описано далее в этой статье). Вместо этого, во вкладке Вы должны указать на Ваши папки со сторонними расширениями или пользовательскими файлами – тогда GameMaker: Studio скомпилирует требуемые файлы из них в Вашу игру.

Если Вы создаёте расширение iOS, есть некоторые дополнительные поля, которые, возможно, Вам потребуется заполнить: Mac Source Directory, необходимый для любых SDK, требующих symlinks, Linker Flags, так как некоторые фреймворки и сторонние SDK требуют добавление дополнительных флагов в компоновщик и, наконец, любые системные и сторонние фреймворки, которые Вам необходимы.

Если Вы работаете с Android, то есть только два поля, которые может понадобиться заполнить: разрешения, требуемые Вашему расширению (Permissions) и любые дополнительные записи для манифеста (Android Manifest XML). Необходимые Вам разрешения будут полностью зависеть от того, что использует расширение и Вам нужно смотреть документацию Google, либо документацию, поставляемую с выбранным SDK, чтобы найти те, которые Вам нужны. Что касается Android Manifest, здесь Вы добавляете любую дополнительную информацию к манифесту, которая может требоваться для Вашего расширения, которое будет внедрено (добавлено), когда Ваша игра будет собираться для тестирования или финального релиза.

 

Создание нативного расширения – Общие

Ниже приведены основные шаги создания iOS или Android расширения и вызов функции, использующей нативный код. В данном случае мы добавим в GameMaker: Studio одну новую функцию, которая будет использовать Objective C++ на iOS для вывода информации в консоль iPhone Configuration Utility на Вашем рабочем Mac, а на Android отправляет ту же самую информацию в ADB-консоль.

Основы

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

Создание расширения

Теперь нужно создать наше расширение. Для этого нужно кликнуть правой кнопкой мыши на папке Extensions в дереве ресурсов и выбрать “Create Extension”, после чего откроется окно Extension Package Properties и здесь (для нашего простого примера) Вам нужно заполнить только общую информацию (General information), затем нажать “Okay” для продолжения.

Добавление файла-болванки.

Для JS, GML и DLL расширений, Вам требуется файл, содержащий необходимый код. Однако для iOS и Android этот файл не используется, но GameMaker: Studio по-прежнему требуется файл для “группировки” Ваших функций расширения и констант (это может измениться в будущих обновлениях). Поэтому Вам необходимо создать файл-болванку, который может иметь любой формат, кроме .js, .gex или .dll и добавить его (для нашего примера назовём его как-нибудь типа “extension.ext”).

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

 

Создание нативного расширения – iOS

Теперь, когда Вы подготовили свой файл для группировки функций и констант, которые Вы собираетесь использовать в Вашей тестовой игре, мы должны добавить файлы с исходным Objective C++ кодом, которые собирается использовать расширение. Для этого сделайте двойной щелчок по папке Extension Package и кликните по вкладке iOS, чтобы открыть свойства для этой платформы.

Для такого простого примера, Вам нет необходимости волноваться ни о каких других деталях, кроме исходного каталога (Source Directory) и имени класса (Class Name), поэтому просто установим их сейчас. Папка – место, куда мы собираемся сохранить необходимые исходные файлы, а имя класса может быть чем-нибудь простым, вроде “GenericExtension”.

Теперь, в проводнике Windows, перейдите в каталог, который Вы выбрали для исходного кода Вашего расширения и создайте папку с именем “Source” (если назвать любым другим именем, кроме “Source“, то GameMaker: Studio просто не найдёт его). В этой новой папке Вы должны создать два файла для своего кода – .mm и .h файлы. Для этого примера мы назовем их GenericExt.mm и GenericExt.h. В файл GenericExt.h добавьте строку

@interface YourClassName :NSObject

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

-(void) genexttestdummy_Function1:(char *)arg1 Arg2:(double)arg2 Arg3:(char *)arg3;

Обратите внимание, что первый параметр следует непосредственно после двоеточия и ему не требуется имя, но последующие параметры должны быть с именем “ArgN“, за которым следует двоеточие, затем тип (либо double, либо char *) в скобках и, наконец, имя, которое будет использоваться в определении функции – arg2, arg3 и т.д.

После объявления членов своих функций, добавьте “@end”, чтобы закрыть объявление интерфейса.

В .mm файле мы сначала подключим .h:

#import “GenericExt.h”

затем напишем реализацию функции, которую мы хотим добавить, начав с этого:

@implementation GenericExtClass

Добавьте свои функции как в заголовочном файле, но, вместо того, чтобы закончить строку точкой с запятой, добавьте изогнутые фигурные скобки, содержащие код, который Вы хотите вызвать. Для нашего примера, мы вызываем NSLog, чтобы вывести на экран вызов функции и параметры на консоль, которую мы будем в состоянии просмотреть из iPhone Configuration Utility на Mac, с которым соединено наше устройство на iOS.

 

Создание нативного расширения – Android

С расширениями для Android все несколько проще… Мы действительно должны создать только исходный файл Java, который собирается использовать расширение и “указать” GameMaker: Studio на него. Для нашего простого примера, Вы не должны волноваться о деталях манифеста и разрешениях. Таким образом, в окне свойств Extension Package, на вкладке Android, просто задайте имя класса (типа “GenericExtension“) и укажите папку, в которой Вы собираетесь хранить свой Java файл для использования.

Теперь, в проводнике Windows перейдите в каталог, который Вы выбрали, чтобы найти исходные файлы Вашего расширения и создайте папку “Java” (и опять, если назвать любым другим именем, кроме “Java“, то GameMaker: Studio не сможет найти его).

В этой новой папке необходимо создать файл с Java-кодом. Для нашего примера просто создайте файл с именем “GenericExtension.java”, не забывая включить следующую строку в верхней части Вашего кода Java:

package ${YYAndroidPackageName};

Теперь Вы можете создать свое определение класса, которое включает функцию, которую Вы хотите вызвать. В нашем примере Вы должны будете создать класс “GenericExtension” с функцией, названной genextestdummy_Function1, принимающей три параметра – String, double, string. Для простоты, в этом примере просто сделайте вывод параметров в ADB-консоль, чтобы проверить, что функция была вызвана правильно.

Создание GML-функции

Затем Вы должны добавить объявление функции к нашему расширению в GameMaker: Studio так, чтобы Ваш код мог вызвать Вашу новую Java-функцию. Чтобы сделать это, нажмите правой кнопкой мыши по файлу группы, который Вы добавили (файл-болванку), и выберите “Add Function”. Откроется новое окно, где Вы можете добавить свою функцию и присвоить ей параметры и свойства.

В соответствии с код, созданным ранее, Вы должны указать имя функции (Function Name) как “genextestdummy_Function1“, и Вы должны также определить внешнее имя, которое будет тем же самым. Теперь установите три параметра, которые принимает функция (string, double, string), и нажмите кнопку “Okay“, чтобы сохранить изменения.

Вызов функции нового расширения

Всё, что осталось сделать – добавить код в наш объект-кнопку, вызывающий новую функцию. В нашем примере есть только объект object0, в событии отпускания левой кнопки мыши которого мы будем делать вызов:

genexttestdummy_Function1("Hello", 100, "World");

При тестировании игры на выбранном устройстве, нажатие и отпускание этой кнопки должно приводить к отображению переданных параметров в консоли Configuration Utility iPhone на Mac или в консоли ADB на Вашем PC.

Принадлежность точки многоугольнику

Скрипт проверки вхождения точки в многоугольник (то есть проверяем, внутри многоугольника точка, или снаружи), с учётом попадания на грани и вершины многоугольника. Здесь реализован метод трассировки луча (учёт числа пересечений) Сама проверка состоит из последовательного вызова скрипта для каждой пары вершин многоугольника. Скрипт проверяет, пересекает ли луч, направленный вправо, отрезок между указанными вершинами. Если пересекает, то возвращается результат -1, если нет, то 1. Если же точка лежит на отрезке, то вернётся 0. В скрипт нужно передать шесть координат – координаты X, Y вершин многоугольника и координаты X, Y проверяемой точки. Все вершины многоугольника должны проверяться последовательно. При этом можно перебирать их как по часовой стрелке, так и против часовой стрелки. Вызов скрипта может происходить, например, так:

r1 = check_point(x1, y1, x2, y2, x0, y0)
r2 = check_point(x2, y2, x3, y3, x0, y0)
r3 = check_point(x3, y3, x4, y4, x0, y0)
r4 = check_point(x4, y4, x1, y1, x0, y0)

res = r1*r2*r3*r4

Собственно, скрипт проверки точки:

s_ax = argument0
s_ay = argument1
s_bx = argument2
s_by = argument3
s_mx = argument4
s_my = argument5

ax = s_ax - s_mx
ay = s_ay - s_my
bx = s_bx - s_mx
by = s_by - s_my

s = sign(ax * by - ay * bx)
if (s == 0 && (ay == 0 || by == 0) && ax * bx <= 0)
    return 0
if ((ay < 0) ^ (by < 0))
{
    if (by < 0)
        return s
    return -s
}      
return 1

Тут пример, показывающий работоспособность (все вершины можно перемещать мышкой). Действие происходит в событии draw контроллера. Использован “китайский” код, но исключительно для того, чтобы не усложнять понимание принципа работы. Например, в Студии можно все вершины передавать массивом – таким образом можно реализовать проверку с динамичным числом вершин. В примере используется многоугольник из 5 вершин, но на практике их может быть любое количество.