Tutorial: Control de personaje, parte 3 Año: 2011 V.: AS3
[e]
Este tutorial es como si fuera la continuación del tip (Controlar el personaje de un juego mediante los eventos de teclado) si no los has leído aún y quieres comprender el resto de código no comentado, te recomiendo echarle un vistazo antes, ya que voy a reutilizar el mismo ejemplo del tip anterior.
Los cambios realizados en este ejemplo en comparación con el anterior los diferenciareis porque son los únicos que están comentados.
En esta ocasión lo que vamos a hacer es dotar al mapa de la posibilidad de girar manteniendo siempre la posición respecto a nuestro personaje.
Lo primero que debemos hacer es preparar el escenario.
En mi ejemplo e creado un movieclip vacío y le he dado el nombre de instancia «world» con el punto de registro en el centro, luego e creado un segundo movieclip vacío con nombre de instancia «mapa», también con el punto de registro en el centro. Al mc «mapa» le introducido unas texturas de hierva y luego e metido el mc «mapa» dentro del mc «world».
Posteriormente e creado otro movieclip con nombre de instancia «hero» con su respectiva animación en su interior y lo e colocado centrado en el escenario por encima del mc «world».
En principio eso es todo, sencillo ¿no?. Ahora vamos a pasar al código y su explicación.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
import flash.events.Event; stage.addEventListener(Event.ENTER_FRAME, onFrame); //VARIABLES DE CONTROL DE DESPLAZAMIENTO; /* Declaramos la variable speedRotationKeyBoard esta variable nos servirá para especificar la velocidad de rotación del mapa con las teclas de dirección left y rigth. */ var speedRotationKeyBoard:int = 4; /* Declaramos la variable xyVel que nos servirá para indicar la velocidad de desplazamiento de nuestro personaje. En este caso especificamos una sola variable para X e Y, porque al utilizar funciones trigonométricas y aunque solo desplacemos el mapa hacia la izquierda, necesitaremos siempre utilizar las propiedades X e Y a la vez. . Si especificáramos un valor independiente y diferente para cada propiedad nos encontraremos que el personaje no se desplazara acorde con el mapa. */ var xyVel:int = 10; /* Declaramos una variable como una constante que nos servirá mas adelante para pasar de grados a radianes y reutilizarla en las funciones de seno y coseno, de esta manera nos ahorramos el tener que procesar cada vez esta división. */ var consPi:Number = Math.PI / 180; /* Declaramos la variable mapa como object y la inicializamos con la ruta del movieclip mapa que se encuentra dentro del movieclip world, así nos ahorramos escribir cada vez toda la ruta. */ var mapa:Object = world.mapa; //CONTROL DEL TECLADO stage.addEventListener(KeyboardEvent.KEY_DOWN,onKey); stage.addEventListener(KeyboardEvent.KEY_UP,outKey); var key:int; function onKey(event:KeyboardEvent):void { var code:int = event.keyCode; if (key != code) { keyEvent(code,1); key = code; } } function outKey(event:KeyboardEvent):void { var code:int = event.keyCode; keyEvent(code,0); if (key == code) { key = 0; } } var ka:Array = new Array(); /* Si os fijáis en la función keyEvent he eliminado las líneas que se encargaban de setear la velocidad de X e Y de manera independiente, ahora ya no son necesarias como en el ejemplo del tutorial anterior. */ function keyEvent(k,s) { if (k == 65 || k == 68 || k == 37 || k == 39 || k == 87 || k == 40 || k == 38 || k == 83) { ka[k] = s; if ((ka[87]||ka[38])&&ka[68]) {//Key[W] or Key[Up] and Key[D] then move UpRigth("ArribaDerecha"); goTo("move",-150); } else if (ka[68]&&(ka[40]||ka[83])) {//Key[D] and Key[S] or Key[Down] then move DownRigth("AbajoDerecha"); goTo("atras",150); } else if ((ka[40]||ka[83])&&ka[65]) {//Key[S] or Key[Down] and Key[A] then move DownLeft("AbajoIzquierda"); goTo("atras",-150); } else if (ka[65]&&(ka[87]||ka[38])) {//Key[A] and Key[W] or Key[Up] then move UpLeft("IzquierdaArriba"); goTo("move",150); } else if (ka[87] || ka[38]) {//Key[W] or Key[Up] then move Up("Arriba"); goTo("move",180); } else if (ka[68]) {//Key[D] then move Rigth("Derecha"); hero.scaleX = -1; goTo("desplzLateral",200); } else if (ka[83] || ka[40]) {//Key[S] or Key[Down] then move Down("Abajo"); goTo("atras",180); } else if (ka[65]) {//Key[A] then move Left("Izquierda"); goTo("desplzLateral",160); hero.scaleX = 1; } else if (ka[37]) {//Key[Left] then rotate Left("Rotar Izquierda"); goTo("relax",180); } else if (ka[39]) {//Key[Rigth] then rotate Rigth("Rotar Derecha"); goTo("relax",180); } else {//No Key? then Relax goTo("relax",180); } }//End if check Keys } function goTo(action,rotate):void { action == "relax" ? hero.gotoAndStop(action):hero.gotoAndPlay(action); hero.rotation = rotate; } /* Aquí viene el mayor cambio en comparación con el ejemplo anterior y la magia de este sencillo código. Primeramente utilizamos la función onFrame que se actualiza indefinidamente y que se encargara de mover el mapa. Dentro detectaremos las teclas que están siendo pulsada reutilizando el mismo array que hemos usado en la función keyEvent para almacenar las teclas, pero en este caso la sentencias if si se cumplirán indefinidamente mientras mantengamos pulsada la tecla, todo lo contrario de lo que nos interesaba en la función keyEvent. */ function onFrame(e:Event):void { /* Si la tecla izquierda(left) del teclado de dirección esta pulsada entonces.. */ if (ka[37]) {//- rotate left /* Rotamos el clip world en sentido de las agujas del reloj a la velocidad especificada en speedRotationKeyboard. */ world.rotation += speedRotationKeyBoard; /* Si la tecla izquierda no esta pulsada pero la tecla derecha (right) si lo esta entonces... Es importante utilizar un if else porque son dos teclas que no deben estar pulsadas a la vez. */ } else if (ka[39]) {//- rotate right /* Rotamos el mapa en sentido contrario a las agujas del reloj. */ world.rotation -= speedRotationKeyBoard; } // Si la tecla [A] esta pulsada entonces.. if (ka[65]) {//- move left /* Convertimos de grados a radianes la rotación del mapa y resolvemos el coseno. */ mapa.y-= xyVel*Math.cos((world.rotation-90)*consPi); /* Convertimos de grados a radianes la rotación del mapa y resolvemos el seno. */ mapa.x-= xyVel*Math.sin((world.rotation-90)*consPi); //Ídem } else if (ka[68]) {//- move right //Ídem mapa.y-= -xyVel*Math.cos((world.rotation-90)*consPi); //Ídem mapa.x-= -xyVel*Math.sin((world.rotation-90)*consPi); } if (ka[38] || ka[87]) {//- move up //Ídem mapa.x+= xyVel*Math.cos((world.rotation-90)*consPi); //Ídem mapa.y-= xyVel*Math.sin((world.rotation-90)*consPi); } else if (ka[40] || ka[83]) {//- move down mapa.x+= -xyVel*Math.cos((world.rotation-90)*consPi); mapa.y-= -xyVel*Math.sin((world.rotation-90)*consPi); } } |
Mismo código sin comentarios:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
import flash.events.Event; stage.addEventListener(Event.ENTER_FRAME, onFrame); var speedRotationKeyBoard:int = 4; var xyVel:int = 10; var consPi:Number = Math.PI / 180; var mapa:Object = world.mapa; stage.addEventListener(KeyboardEvent.KEY_DOWN,onKey); stage.addEventListener(KeyboardEvent.KEY_UP,outKey); var key:int; function onKey(event:KeyboardEvent):void { var code:int = event.keyCode; if (key != code) { keyEvent(code,1); key = code; } } function outKey(event:KeyboardEvent):void { var code:int = event.keyCode; keyEvent(code,0); if (key == code) { key = 0; } } var ka:Array = new Array(); function keyEvent(k,s) { if (k == 65 || k == 68 || k == 37 || k == 39 || k == 87 || k == 40 || k == 38 || k == 83) { ka[k] = s; if ((ka[87]||ka[38])&&ka[68]) { goTo("move",-150); } else if (ka[68]&&(ka[40]||ka[83])) { goTo("atras",150); } else if ((ka[40]||ka[83])&&ka[65]) { goTo("atras",-150); } else if (ka[65]&&(ka[87]||ka[38])) { goTo("move",150); } else if (ka[87] || ka[38]) { goTo("move",180); } else if (ka[68]) { hero.scaleX = -1; goTo("desplzLateral",200); } else if (ka[83] || ka[40]) { goTo("atras",180); } else if (ka[65]) { goTo("desplzLateral",160); hero.scaleX = 1; } else if (ka[37]) { goTo("relax",180); } else if (ka[39]) { goTo("relax",180); } else { goTo("relax",180); } } } function goTo(action,rotate):void { action == "relax" ? hero.gotoAndStop(action):hero.gotoAndPlay(action); hero.rotation = rotate; } function onFrame(e:Event):void { if (ka[37]) {//- rotate left world.rotation += speedRotationKeyBoard; } else if (ka[39]) {//- rotate right world.rotation -= speedRotationKeyBoard; } if (ka[65]) {//- move left mapa.y-= xyVel*Math.cos((world.rotation-90)*consPi); mapa.x-= xyVel*Math.sin((world.rotation-90)*consPi); } else if (ka[68]) {//- move right mapa.y-= -xyVel*Math.cos((world.rotation-90)*consPi); mapa.x-= -xyVel*Math.sin((world.rotation-90)*consPi); } if (ka[38] || ka[87]) {//- move up mapa.x+= xyVel*Math.cos((world.rotation-90)*consPi); mapa.y-= xyVel*Math.sin((world.rotation-90)*consPi); } else if (ka[40] || ka[83]) {//- move down mapa.x+= -xyVel*Math.cos((world.rotation-90)*consPi); mapa.y-= -xyVel*Math.sin((world.rotation-90)*consPi); } } |
Y aquí tenemos el ejemplo con algunos detallitos, no os preocupéis por los efectos 3D, tan sólo hay que añadir los objetos mc dentro del clip mapa, agregarles un filtro de sombra o manipularlos con las herramientas 3D en tiempo de edición y flash se encarga de tratarlos automáticamente en tiempo de ejecución sin necesidad de código añadido.
Utiliza las teclas [W] [A] [S] [D] o las teclas de dirección [UP] [DOWN] [LEFT] [RIGHT]
.
[download id=»26″ format=»2″]
.
Como veis en poco mas de 200 líneas de código hemos conseguido un resultado bastante bueno, no se si existirá alguna formula mas optimizada y con menos código para conseguir el mismo resultado pero este fue el resultado al que llegue después de investigar y no se me ocurre nada mejor, si alguien sabe alguna manera mas eficiente de hacer lo mismo lo invito a compartirlo en el blog.
Mas adelante intentare hacer un tip sobre trigonometría para comprender mejor las formulas que he utilizado en este ejemplo.
Saludos.
2 comments on “AS3 – Tutorial – Control de personaje – Parte 3 – Rotar mapa respecto la posición del personaje con trigonometría”
A NOVΑCOBE compete no pаtamar da exceⅼência. https://www.linkedin.com/pulse/remodelações-de-interiores-melhor-lisboa-obrasnet-remodelações/