Comunidad de diseño web y desarrollo en internet online

Balanceo de un péndulo en Actionscript

Como su título indica, esta escrito con el propósito de dar una manera sistemática de hacer que objetos tales como péndulos o similares oscilen de una manera realista, dando además multitud de posibilidades, como la de frenarse o no con el paso del tiempo o la de poder dar varias vueltas sobre el punto de rotación sin perder el efecto de realismo. Por supuesto, es completamente personalizable para conseguir distintas velocidades.

Para la comprensión de este tutorial no es necesario tener unos conocimientos avanzados de ActionScript, tan solo unas nociones básicas.

Preparando el péndulo

Para comenzar, crea un documento nuevo de dimensiones amplias (sobre todo a lo alto), con el color de fondo que prefieras y con una velocidad de fotogramas por segundo de 40 fps, que es la que yo utilizo. En una nueva capa, dibuja algo parecido a un péndulo que este "colgado" de una línea (cuanto más larga la hagas, mejor se apreciará el efecto) en una posición de reposo total (no le des ninguna inclinación inicial al dibujarlo), conviértelo en un MovieClip y dale un nombre de instancia ("punch" en mi caso). El punto de registro debe quedar sobre la "cuerda" de la que está colgado el péndulo, sobre donde quieres que se balancee. Así quedó mi "péndulo":

A continuación, ya podemos darle una rotación (-30º por ejemplo) y pasar a escribir el código.

Definición de variables imprescindibles

Para comenzar, vamos a definir una serie de variables que serán necesarias para más tarde conseguir el movimiento de balanceo. Escribimos estas líneas de código en el MovieClip:

onClipEvent (load)
{ 
	//Velocidad inicial, 0 preferiblemente 
	velocidad = 0;
	//Variable "peso" del péndulo, no mayor que 0.3 aproximadamente para un efecto realista 
	peso = 0.15;
	//Será negativo si la inclinación es opuesta a la predeterminada para satisfacer las ecuaciones gracias a las tres siguientes lineas  
	if (this._rotation>0) { 
	peso *= -1;
	} 
} 

El hecho de que el peso sea positivo para esta rotación y no al revés se debe tan solo a la manera a la que he planteado las ecuaciones.

Estas primeras líneas de código servirán para definir las dos variables imprescindibles para el movimiento. Las explicaré en el siguiente paso al escribir la fórmula que lo producirá.

Movimiento oscilante sin deceleración

Ahora escribimos estas lineas también en el MovieClip:

onClipEvent (enterFrame) 
{ 
	//Fórmula fundamental del efecto  
	velocidad += peso; 
	//Traduce la fórmula anterior a la rotación del objeto  
	this._rotation += velocidad;
	//Este condicional es verdadero al bajar de derecha a izquierda 
	if (this._rotation>0 && this._rotation<90 && peso>0) 
	{ 
		this._rotation = 0.1;
		peso *= -1; 
	} 
	//Este condicional es verdadero al bajar de izquierda a derecha  
	if (this._rotation<0 & this._rotation>-90 && peso<0) 
	{ 
		this._rotation = -0.1;
		peso *= -1; 
	} 
}

Ahora explicaré un poco esto: lo que hace este comportamiento es, en cada fotograma, sumar a la velocidad el peso que le hayamos dado, con lo cual cada vez será mayor (esto conseguirá el efecto de aceleración). Suponiendo que la rotación inicial sea negativa (es decir, que este inclinado a la derecha), y que por lo tanto el peso inicial sea mayor que cero, al llegar a una rotación ligeramente mayor que cero se activará el primer condicional y cambiará el peso de signo (lo de this._rotation = 0.1; es para que no se "atasque"), y por lo tanto se ira decelerando hasta que la velocidad llegue a 0. En ese momento, el péndulo irá girando cada vez más rápido en sentido contrario, hasta que llegue -con un peso negativo, recordemos- a una rotación algo menor que 0, que será cuando se active el segundo condicional, y el peso vuelva a tener signo positivo.

Hasta aqui y con estas pocas líneas se consigue ya un efecto de balanceo; el único inconveniente es que no se frena nunca. Remediemos eso:

Movimiento oscilante con deceleración

Ahora tenemos que añadir una nueva variable: la resistencia, que tomará parte sólo cuando el péndulo esté "subiendo", para así ir frenándolo.

Añadamos estas líneas en la parte onClipEvent (load) { }:

//Resistencia inicial, establecer en 0.  
resistencia = 0;

No necesita explicación. Ahora, en onClipEvent (enterFrame) { }, sustituimos velocidad += peso; por lo siguiente:

if (this._rotation > 0) 
{ 
	velocidad = velocidad+peso-resistencia;
} 

if (this._rotation < 0) 
{ 
	velocidad = velocidad+peso+resistencia;
} 

Esto es para que no frene hacia un lado y acelere hacia el otro. También podríamos cambiar el signo de la resistencia como hemos hecho con el peso, pero sería un tanto más complicado.

Ahora tendremos que definir un comportamiento que diferencie cuándo el péndulo está subiendo y cuándo no. Para ello añadimos subiendo = true; en cada uno de los dos condicionales que teníamos antes y la cosa queda así:

//Este condicional es verdadero al bajar de derecha a izquierda 
if (this._rotation>0 && this._rotation<90 && peso>0) 
{ 
	this._rotation = 0.1;
	peso *= -1; 
	subiendo = true;
} 


//Este condicional es verdadero al bajar de izquierda a derecha  
if (this._rotation<0 & this._rotation>-90 && peso<0) 
{ 
	this._rotation = -0.1;
	peso *= -1; 
	subiendo = true;
} 
//Nuevas líneas, son las que controlan el valor de la resistencia  
if (subiendo == true) 
{ 
	resistencia = 0.04;
} 
if (velocidad<0.2 && velocidad>-0.2) 
{ 
	subiendo = false;
	resistencia = 0;
}

Las nuevas líneas no necesitan mucha explicación: cuando el péndulo está subiendo, la resistencia deja de ser nula, y en el instante en el que la velocidad esta pasando de ser positiva a negativa o viceversa (que es la señal de que está llegando al punto máximo y por tanto va a bajar), subiendo es false y la resistencia es nula.

Esto tiene un problema, y es que llega un momento en que el péndulo se queda vibrando sin detenerse y el resultado puede llegar a ser demencial en algunos casos (aumenta el zoom si no lo ves). Por ello, introduciremos otra variable: yo la he llamado coeficiente de estabilización, o CE.

Para resumir, diremos que el código queda finalmente así:

onClipEvent (load) 
{ 
	//Velocidad inicial, 0 preferiblemente 
	velocidad = 0;
	//Variable "peso" del péndulo, no mayor que 0.3 aproximadamente para un efecto realista 
	peso = 0.15;
	//Será negativo si la inclinación es opuesta a la predeterminada para satisfacer las  
	//ecuaciones 
	if (this._rotation>0) 
	{ 
		peso *= -1;
	} 
	//Resistencia inicial, establecer en 0.  
	resistencia = 0;
	CE = 0.1;
} 
 
onClipEvent (enterFrame) 
{ 
	if (CE<10) 
	{ 
		//Fórmula fundamental del efecto 
		if (this._rotation>0) 
		{ 
			velocidad = velocidad+peso-resistencia;
		} 
		if (this._rotation<0) 
		{ 
			velocidad = velocidad+peso+resistencia;
		} 
		//Traduce la fórmula anterior a la rotación del objeto  
		this._rotation += velocidad;
		//Este condicional es verdadero al bajar de derecha a izquierda 
		if (this._rotation>0 && this._rotation<90 && peso>0) 
		{ 
			this._rotation = 0.1;
			peso *= -1;
			CE *= 1.1;
			subiendo = true;
		} 
		//Este condicional es verdadero al bajar de izquierda a derecha  
		if (this._rotation<0 & this._rotation>-90 && peso<0) 
		{ 
			this._rotation = -0.1;
			peso *= -1;
			CE *= 1.1;
			subiendo = true;
		} 
		if (subiendo == true) 
		{ 
			resistencia = 0.04;
		} 
		if (velocidad<0.2 && velocidad>-0.2) 
		{ 
			subiendo = false;
			resistencia = 0;
		} 
	}
	else 
	{ 
		this._rotation = 0;
	} 
}

No necesita mucha explicación: cada vez que la rotación cambia de positiva a negativa o viceversa, se multiplica por 1,1 el CE; así, cuando llega a 10, dejan de ejecutarse los comportamientos que producen el balanceo y el péndulo se para.

Con esto ya podríamos dar por terminado nuestro tutorial, pero aún queda algo interesante que podemos hacer.

Apéndice: Con varias vueltas de más

Imaginemos que tienes en tu película algún sistema para impulsar el péndulo. Si este llegara a tener suficiente velocidad como para llegar a darse la vuelta, con las líneas que hemos escrito no es suficiente: tenemos que añadir un par de condicionales más. No son nada del otro mundo, tienen una sintaxis análoga a la de los otros dos:

//Este condicional es verdadero al llegar hasta arriba desde la derecha  
if (this._rotation>90 && peso>0) 
{ 
	this._rotation = 180;
	peso *= -1;
	CE = 0.1;
	subiendo = false;
	resistencia = 0;
} 
//Este condicional es verdadero al llegar hasta arriba desde la izquierda  
if (this._rotation<-90 && peso<0) 
{ 
	this._rotation = -180;
	peso *= -1;
	CE = 0.1;
	subiendo = false;
	resistencia = 0;
}

El hecho de poner el CE a 0 es necesario para que no llegue al valor que especificamos para que se detuviera el péndulo antes de tiempo.

Completando el código que ya teníamos con estos dos últimos condicionales, nuestro péndulo puede dar ya todas las vueltas que sean necesarias sin peligro de errores.

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Descargar Archivo

Publica tu comentario

El autor de este artículo ha cerrado los comentarios. Si tienes preguntas o comentarios, puedes hacerlos en el foro

Entra al foro y participa en la discusión

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate