function Сцена(состояние, состояниЯ, события, тела, адресИгры)
{
    this.создать = function()
    {
        this.задано = {};
        this.сцены = null;
        this.состояниеИгрока = null;
        события.подписать(this);
    };

    this.загрузитьСцену = function(имя)
    {
        let z64 = this.сцены[имя];
        window.location = адресИгры + z64;
    };

    this.загрузитьОглавление = function(адрес)
    {
        var тут = this;
        var запрос = new XMLHttpRequest();
        запрос.onreadystatechange = function()
        {
            if (this.readyState == 4)
            {
                if (this.status == 200)
                {
                    тут.разобратьОглавление(this.responseText);
                }
                else
                {
                    console.error("Не удалось загрузить оглавление сцен:", this.status);
                }
            }
        }
        запрос.open("GET", адрес);
        запрос.send();
    };

    this.задатьСостояниеИгрока = function(идёт, направление)
    {
        let стоятьЛ = this.задано["игрок.стоять.0"];
        let стоятьП = this.задано["игрок.стоять.1"];
        let идтиЛ = this.задано["игрок.идти.0"];
        let идтиП = this.задано["игрок.идти.1"];
        if (!стоятьЛ || !стоятьП || !идтиЛ || !идтиП)
        {
            return;
        }

        var название = идтиЛ;
        if (идёт && направление > 0)
        {
            название = идтиП;
        }
        else if (!идёт && направление < 0)
        {
            название = стоятьЛ;
        }
        else if (!идёт && направление > 0)
        {
            название = стоятьП;
        }

        if (this.состояниеИгрока != название)
        {
            состояниЯ.применить(название);
            this.состояниеИгрока = название;
        }
    };

    this.обновить = function()
    {
        this.переместитьИгрока();
    };

    this.обработатьКлюч = function(ключ, путь, значение)
    {
        if (путь[0] != "сцена")
        {
            return;
        }

        var свойство = путь.slice(1).join(".");
        this.задано[свойство] = значение;
        if (свойство == "оглавление")
        {
            this.загрузитьОглавление(значение);
        }
    };
    
    this.обработатьНажатиеМышиУказатьИНажать = function(x, y, указатель)
    {
        let цель = this.задано["цель"];
        if (!this.типИгрыУказатьИНажать() || !цель)
        {
            return;
        }
        let тело = тела.тела[цель];
        if (!тело)
        {
            return;
        }

        var пр = [
          тело.bounds.min.x,
          тело.bounds.min.y,
          тело.bounds.max.x - тело.bounds.min.x,
          тело.bounds.max.y - тело.bounds.min.y,
        ]
        let ширина = пр[2];
        пр[0] = x - ширина;

        состояние.разобрать({
            тела: {
                [цель]: {
                    пр: пр,
                },
            },
        });
    };

    this.обработатьСобытие = function(событие)
    {
        let мышь = "мышь/нажатие/";
        let сцена = "сцена/";
        if (событие.startsWith(мышь))
        {
            let значения = событие.substring(мышь.length).split("/");
            let x = Number(значения[0]);
            let y = Number(значения[1]);
            let указатель = значения[2];
            this.обработатьНажатиеМышиУказатьИНажать(x, y, указатель);
        }
        else if (событие.startsWith(сцена))
        {
            let название = событие.substring(сцена.length);
            this.загрузитьСцену(название);
        }
    };

    this.переместитьИгрока = function()
    {
        let цель = this.задано["цель"];
        let объект = this.задано["игрок.объект"];
        let скоростьX = this.задано["игрок.скорость.0"];
        if (!this.типИгрыУказатьИНажать() || !цель || !объект || !скоростьX)
        {
            return;
        }

        let игрок = `объекты-${объект}`;
        let телоЦели = тела.тела[цель];
        let телоИгрока = тела.тела[игрок];
        if (!телоЦели || !телоИгрока)
        {
            return;
        }

        let игрокX = телоИгрока.position.x;
        let цельX = телоЦели.position.x;
        let ширина = телоЦели.bounds.max.x - телоЦели.bounds.min.x;
        let расстояние = цельX - игрокX;
        let направление = расстояние > 0 ? 1 : -1;

        if (Math.abs(расстояние) < ширина / 2)
        {
            this.задатьСостояниеИгрока(false, направление);
            return;
        }

        this.задатьСостояниеИгрока(true, направление);
        Matter.Sleeping.set(телоИгрока, false);
        Matter.Body.setVelocity(телоИгрока, { x: скоростьX * направление, y: 0 });
    };

    this.разобратьОглавление = function(содержимое)
    {
        let код = "this.сцены = " + содержимое;
        eval(код);
    };

    this.типИгрыУказатьИНажать = function()
    {
        var тип = this.задано["тип"];
        return тип && тип == "указать и нажать";
    };

    // Конструктор.
    this.создать();
};