суббота, 20 августа 2011 г.

Закончен скрипт перемещения слоёв!

Автор: Серёжа

Всё-таки нашёл время и довёл скрипт совсем до ума!
Что изменилось:
  • Нет привязки к глобальной переменной в game.loop
  • Методов стало 2 - для "эксклюзивного" скролла (движется только наш слой) и для асинхронного, когда выполнение всех команд продолжается
  • Передвигаются не только Entity, а так же регионы (region).
  • Небольшая оптимизация, всё стало двигаться чуточку плавнее.
Что ещё можно было бы сделать:
  • Перемещение регионов вместе со слоём, сейчас они просто перескакивают
  • Исправление алгоритма: сейчас время, указываемое в функции не соответствует действительности =(
  •  Контроль активности регионов во время перемещения (активны или нет)...
  • ...следовательно, сделать функцию перегружаемой (не факт, что это вообще возможно) .
Небольшой readme к скрипту и сам скрипт под катом.
------------------ЗАЧЕМ-ЭТО-НАДО?-------------------
Мне не понравилось, что работа с прокруктой сцены в WME - вещь весьма неочевидная и привязанная, по большей части, к перемещению персонажа, что не всегда удобно. Мне нужно было получить полный контроль над происходящим, что бы организовать более красивую и плавную иллюзию перемещения камеры в меню, где персонажа нету, а на переднем плане висит неподвижный, относительно камеры, текст. Стандартными средствами движка такого достичь не получилось, так что пришлось писать самому. Тем более, я посчитал, что это-весьма перспективно для будущих головоломок.

----------------------ОПИСАНИЕ----------------------
Скрипт добавляет 2 новых метода для объекта layer:
* Scroll (x,y,v) -перемещает слой (целиком, как entity, так и region). При этом игра приостанавливается до завершения перемещения.
* ScrollAsync(x,y,v) -тоже самое, только выполнение остальных скриптов продолжается, слой будет "ехать" на заднем фоне.
, где:
x,y - ВЕЛИЧИНА ПЕРЕМЕЩЕНИЯ по x и y соотвественно, (т.е. если взять x=-10, y=0, то слой переедет на 10 пикселей влево)
v - время, через которое слой приедет в указанную точку. Указыватся в милисекундах.
Почему так? Да потому что так удобнее. Лично я, при планировке сцен, уже знаю, какая область будет в камере и на сколько ей надо переехать.
Что касается скорости, то здесь тоже всё очевидно - важно рассчитывать время прибытия слоёв относительно друг друга. Т.е., если слои должны закончить перемещение одновременно, то достаточно просто указать одинаковые значения, а не высчитывать, сколько кому ехать.

---------------------ИСПОЛЬЗОВНИЕ---------------------
1. Положить файл layer.script в папку /scripts/

2. Ассоциировать переменную со слоем. Для этого в скрипте, где Вам нужно двигать слой пишите:
var l1=Scene.GetLayer("int_obj"); //l1-имя переменной, может быть любой, int_obj -имя слоя, пишется в кавычках. Должно соответствовать имени вашего слоя! Или можно написать просто номер, без кавычек

 3. Прикрепить скрипт к объекту (слою).
l1.AttachScript("scripts\layer.script");

 4. Собственно, подвинуть слой:
l1.ScrollAsync (-1066,0,3000); //Двигает слой int_obj на 1066 пикселей влево. Слой прибудет в конечный пункт через ~3 секунды.


Примечание: Если вы однажды уже прикрепили к слою скрипт, то нигде более этого делать не надо, они уже надёжно связаны.
Например, у меня 2 кнопки. При нажатии на первую камера смещается так, чтобы было видно вторую. При нажатии на вторую камера ползёт обратно. В этом случае, я буду привязывать скрипт к слою (пункт 3) только один раз: в скрипте первой кнопки, хотя объявлять переменную придётся 2 раза.
 Кстати, если хотите, можно объявлять всего один раз, написав вместо "var" "global", т.е. получится:
global l1=Scene.GetLayer("int_obj");

Затем, в скрипте второй кнопки просто "подключиться" к этой глобальной переменной, написав в самом-самом начале скрипта
global l1;


 Вот и всё =) Задавайте вопросы, с радостью отвечу!

 ____________________________________________________________________________
САМ СКРИПТ 
____________________________________________________________________________
 #include "scripts\base.inc"

method Scroll (var x, var y, var v)
{
var h=10;
var b=this.NumNodes;
if (b!=0)
{
//двигаем регионы
for (var j=0; j<b ;j=j+1)
{
var tempNode=this.GetNode(j);
var type = tempNode.Type;
var Reg=tempNode.Region;
if (Reg!=null)
{
for (var k=0; k<Reg.NumPoints; k=k+1)
{
var tempP=Reg.GetPoint(k);
tempP.newX=tempP.X+this.x;
tempP.newY=tempP.Y+this.y;
Reg.SetPoint(k , tempP.newX , tempP.newY);
}
}
}
//закончили двигать
var d;
d.x=(x*h)/v;
d.y=(y*h)/v;
var c=true;
var t1;
var curNode=this.GetNode(0);
var X3, Y3;
var X1=curNode.X;
var Y1=curNode.Y;
var X2=X1+x;
var Y2=Y1+y;
var X0, Y0;
for (j=0; j<b ;j=j+1)
{
curNode=this.GetNode(j);
X3[j]=curNode.X;
Y3[j]=curNode.Y;
X0[j]=curNode.X+x;
Y0[j]=curNode.Y+y;
}
while (c)
{
t1=Game.CurrentTime;
for (j=0; j<b ;j=j+1)
{
curNode=this.GetNode(j);
X3[j]=X3[j]+d.x;
Y3[j]=Y3[j]+d.y;
curNode.SkipTo(X3[j],Y3[j]);
}
X1=X1+d.x;
Y1=Y1+d.y;
if (x>0 && ((X1-X2)>0))
c=false;
if (x<0 && ((X1-X2)<0))
c=false;
if (y>0 && ((Y1-Y2)>0))
c=false;
if (y<0 && ((Y1-Y2)<0))
c=false;
Sleep (t1+h-Game.CurrentTime);
}
for (var i=0 ; i<b ; i=i+1)
{
curNode=this.GetNode(i);
curNode.SkipTo(X0[i],Y0[i]);
}
}
}

method ScrollAsync(var x, var y, var v)
{
this.x=x;
this.y=y;
this.v=v;
this.ApplyEvent ("move");
}

on "move"
{
var h=10;
var b=this.NumNodes;
if (b!=0)
{
//двигаем регионы
for (var j=0; j<b ;j=j+1)
{
var tempNode=this.GetNode(j);
var type = tempNode.Type;
var Reg=tempNode.Region;
if (Reg!=null)
{
for (var k=0; k<Reg.NumPoints; k=k+1)
{
var tempP=Reg.GetPoint(k);
tempP.newX=tempP.X+this.x;
tempP.newY=tempP.Y+this.y;
Reg.SetPoint(k , tempP.newX , tempP.newY);
}
}
}
//закончили двигать
var d;
d.x=(this.x*h)/this.v;
d.y=(this.y*h)/this.v;
var c=true;
var t1;
var curNode=this.GetNode(0);
var X3, Y3;
var X1=curNode.X;
var Y1=curNode.Y;
var X2=X1+this.x;
var Y2=Y1+this.y;
var X0, Y0;
for (j=0; j<b ;j=j+1)
{
curNode=this.GetNode(j);
X3[j]=curNode.X;
Y3[j]=curNode.Y;
X0[j]=curNode.X+this.x;
Y0[j]=curNode.Y+this.y;
}
while (c)
{
t1=Game.CurrentTime;
for (j=0; j<b ;j=j+1)
{
curNode=this.GetNode(j);
X3[j]=X3[j]+d.x;
Y3[j]=Y3[j]+d.y;
curNode.SkipTo(X3[j],Y3[j]);
}
X1=X1+d.x;
Y1=Y1+d.y;
if (this.x>0 && ((X1-X2)>0))
c=false;
if (this.x<0 && ((X1-X2)<0))
c=false;
if (this.y>0 && ((Y1-Y2)>0))
c=false;
if (this.y<0 && ((Y1-Y2)<0))
c=false;
Sleep (t1+h-Game.CurrentTime);
}
for (var i=0 ; i<b ; i=i+1)
{
curNode=this.GetNode(i);
curNode.SkipTo(X0[i],Y0[i]);
}
}
}
   ____________________________________________________________________________  

1 комментарий: