{"id":760,"date":"2024-06-29T18:30:00","date_gmt":"2024-06-29T17:30:00","guid":{"rendered":"https:\/\/jorgeturiel.es\/?p=760"},"modified":"2024-07-09T10:21:23","modified_gmt":"2024-07-09T09:21:23","slug":"la-forma-incorrecta-de-jugar-ajedrez-diversion-fisica-en-3d-usando-castle-game-engine-parte-2","status":"publish","type":"post","link":"https:\/\/jorgeturiel.es\/?p=760","title":{"rendered":"La forma incorrecta de jugar ajedrez: Diversi\u00f3n f\u00edsica en 3D usando Castle Game Engine (Parte 2)"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Traducci\u00f3n del <a href=\"https:\/\/castle-engine.io\/bad-chess\/castle_game_engine_bad_chess_2.html\">art\u00edculo original<\/a> de Michalis Kamburelis.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Introducci\u00f3n<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Bienvenido a la segunda parte del art\u00edculo sobre c\u00f3mo crear un juego sencillo de f\u00edsica en 3D utilizando Castle Game Engine.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Castle Game Engine es un motor de juego 3D y 2D multiplataforma (escritorio, m\u00f3vil, consolas) que utiliza Pascal moderno. Es gratuito, de c\u00f3digo abierto y compatible con FPC y Delphi.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">En la primera parte, aprendimos a utilizar el editor visual y dise\u00f1amos un tablero de ajedrez con piezas de ajedrez. Luego utilizamos f\u00edsica para lanzar una pieza de ajedrez de manera que colisionara y derribara otras piezas. Recuerda que esta es una mala manera de jugar ajedrez, \u00a1pero es realmente divertido!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Si te perdiste la primera parte, a\u00fan puedes \u00absaltar\u00bb en este punto. Simplemente descarga Castle Game Engine desde <a href=\"https:\/\/castle-engine.io\/\">https:\/\/castle-engine.io\/<\/a> y configura el tablero de ajedrez y las piezas de ajedrez t\u00fa mismo, o utiliza nuestro proyecto de ejemplo listo desde<a href=\" https:\/\/github.com\/castle-engine\/bad-chess\/\"> https:\/\/github.com\/castle-engine\/bad-chess\/<\/a> en el subdirectorio project\/version_1_designed_in_editor. Esta versi\u00f3n del proyecto es un buen punto de partida para esta parte del art\u00edculo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Te animamos a seguir este art\u00edculo y realizar todos los pasos por ti mismo, para crear un juguete similar. Si te quedas atascado en alg\u00fan momento, siempre puedes consultar el proyecto terminado. Est\u00e1 disponible en el subdirectorio project\/version_2_with_code en el mismo repositorio, <a href=\"https:\/\/github.com\/castle-engine\/bad-chess\/\">https:\/\/github.com\/castle-engine\/bad-chess\/<\/a>. Es el proyecto final, con todo lo descrito en este art\u00edculo hecho y funcionando.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Y si realmente solo quieres jugar la peor versi\u00f3n de ajedrez ahora mismo, puedes descargar el juego compilado listo (para Linux o Windows) desde <a href=\"https:\/\/castle-engine.itch.io\/bad-chess\">https:\/\/castle-engine.itch.io\/bad-chess<\/a>. \u00a1Disfruta!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Codificaci\u00f3n del juego<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">En esta parte nos enfocaremos en aprender c\u00f3mo usar c\u00f3digo Pascal para hacer que las cosas sucedan en tu juego.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">El n\u00facleo de Castle Game Engine son simplemente un conjunto de unidades Pascal que pueden compilarse utilizando FPC y Delphi. Esto significa que los juegos que creamos son programas Pascal regulares que utilizan algunas unidades espec\u00edficas de Castle Game Engine. Esto te permite utilizar el flujo de trabajo que ya conoces y prefieres, con el editor de texto y el compilador Pascal que elijas.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">En particular, soportamos Delphi, Lazarus, VS Code o cualquier otro editor personalizado (como Emacs). Tenemos una documentaci\u00f3n dedicada con consejos espec\u00edficos para cada IDE en<a href=\" https:\/\/castle-engine.io\/manual_ide.php\"> https:\/\/castle-engine.io\/manual_ide.php<\/a>. B\u00e1sicamente, abre en el editor de Castle Game Engine el panel \u00abPreferences \u2192 Code Editor\u00bb, configura all\u00ed el IDE Pascal que utilizas y todo deber\u00eda funcionar sin problemas. Si haces doble clic en un archivo Pascal desde el editor de CGE, se abrir\u00e1 en el editor de texto que configuraste.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Espec\u00edficamente para los usuarios de VS Code, la p\u00e1gina <a href=\"https:\/\/castle-engine.io\/vscode\">https:\/\/castle-engine.io\/vscode<\/a> contiene informaci\u00f3n sobre c\u00f3mo configurar VS Code con el servidor LSP de Castle Game Engine para obtener una excelente finalizaci\u00f3n de c\u00f3digo. Tenemos una extensi\u00f3n dedicada que proporciona una integraci\u00f3n perfecta de <em>Castle Game Engine<\/em> con <em>VS Code<\/em>. Proporciona resaltado de sintaxis Pascal, autocompletado de c\u00f3digo y la capacidad de compilar, ejecutar o depurar un proyecto de <em>Castle Game Engine<\/em> directamente desde <em>VS Code<\/em>. En este enlace puedes descargar los archivos necesarios <a href=\"https:\/\/castle-engine.io\/vscode\">https:\/\/castle-engine.io\/vscode<\/a> y m\u00e1s documentaci\u00f3n.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"579\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/editor_and_vscode-1024x579.png\" alt=\"\" class=\"wp-image-763\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/editor_and_vscode-1024x579.png 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/editor_and_vscode-300x170.png 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/editor_and_vscode-768x434.png 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/editor_and_vscode-1536x868.png 1536w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/editor_and_vscode.png 1851w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Es importante destacar que, aunque el enfoque de este cap\u00edtulo sea escribir c\u00f3digo Pascal, no dejamos de utilizar el editor de Castle Game Engine. Hay varias cosas que puedes hacer en el editor para que el dise\u00f1o sea \u00abamigable\u00bb a la manipulaci\u00f3n de c\u00f3digo, y las exploraremos en este art\u00edculo. Por lo tanto, escribir c\u00f3digo Pascal y editar el dise\u00f1o visualmente van de la mano.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Ejercicios<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Manejar una pulsaci\u00f3n de tecla para cambiar la posici\u00f3n de un objeto.<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Empecemos con algo sencillo. Nuestro primer objetivo: cuando el usuario presione la tecla x, queremos elevar un poco la pieza del rey negro de ajedrez. Es una prueba simple que podemos hacer:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Reaccionar a la entrada del usuario (pulsaci\u00f3n de tecla).<\/li>\n\n\n\n<li>En respuesta, hacer algo interesante en el mundo 3D (mover una pieza de ajedrez).<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">La mayor\u00eda del c\u00f3digo que escribas en Castle Game Engine se coloca en una unidad asociada con una vista. Hablamos sobre qu\u00e9 es una vista en Castle Game Engine en la parte anterior del art\u00edculo; en resumen, utilizas vistas de manera similar a como usas formularios en una aplicaci\u00f3n t\u00edpica de Delphi FMX \/ VCL o Lazarus LCL: una vista es un dise\u00f1o visual (en data\/gameviewmain.castle-user-interface) y el c\u00f3digo asociado (en code\/gameviewmain.pas).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As\u00ed que abramos el archivo code\/gameviewmain.pas en tu IDE Pascal favorito. En el editor de Castle Game Engine, simplemente usa el panel \u00abFiles\u00bb en la parte inferior. Entra en el subdirectorio code y haz doble clic en el archivo gameviewmain.pas. Alternativamente, puedes abrir tu IDE Pascal y desde all\u00ed abrir el proyecto Pascal. Los archivos b\u00e1sicos del proyecto (como my_project.dproj para Delphi o my_project.lpi para Lazarus) ya han sido generados para ti.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Mant\u00e9n abierto tambi\u00e9n el editor visual de Castle Game Engine, con nuestro dise\u00f1o visual en data\/gameviewmain.castle-user-interface. Ajustaremos o consultaremos nuestro dise\u00f1o visual ocasionalmente, para asegurarnos de que sea \u00fatil para nuestra l\u00f3gica de c\u00f3digo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Para empezar, queremos saber el nombre del componente que representa al rey negro. Como has visto al dise\u00f1ar formularios en Lazarus y Delphi, cada componente tiene un nombre que corresponde a c\u00f3mo se puede acceder a ese componente desde el c\u00f3digo. Puedes editar el nombre del componente en Castle Game Engine ya sea editando la fila \u00abName\u00bb en el \u00abObject Inspector\u00bb (a la derecha) o editando el nombre en la jerarqu\u00eda (a la izquierda). Simplemente haz clic en el nombre del componente en la jerarqu\u00eda o presiona F2 para entrar en la edici\u00f3n de nombres. En la captura de pantalla a continuaci\u00f3n, puedes ver que el rey negro est\u00e1 nombrado como SceneBlackKing1. Puedo usar Ctrl+C para copiar esto al portapapeles.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"579\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/name-1024x579.png\" alt=\"\" class=\"wp-image-765\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/name-1024x579.png 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/name-300x170.png 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/name-768x434.png 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/name-1536x868.png 1536w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/name.png 1850w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Claro, aqu\u00ed tienes la traducci\u00f3n:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ten en cuenta que, para este primer ejercicio de c\u00f3digo, asumimos que la pieza de ajedrez (SceneBlackKing1) no tiene ning\u00fan componente de f\u00edsica. Si has a\u00f1adido componentes TCastleRigidBody o TCastleXxxCollider como comportamientos de SceneBlackKing1, por favor elim\u00ednalos por ahora. Los restauraremos en el pr\u00f3ximo ejercicio.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ahora tenemos que declarar la variable con el mismo nombre exacto en la vista. Se inicializar\u00e1 autom\u00e1ticamente para apuntar al componente cuando iniciemos la vista. Haz esto en la secci\u00f3n<strong> <\/strong>\u00abpublished\u00bb de la clase TViewMain. Este es c\u00f3mo deber\u00eda lucir el resultado final:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">uses Classes,\n  CastleVectors, CastleComponentSerialize,\n  CastleUIControls, CastleControls, CastleKeysMouse, CastleScene;\n\ntype\n  { Main view, where most of the application logic takes place. }\n  TViewMain = class(TCastleView)\n  published\n    { Components designed using CGE editor.\n      These fields will be automatically initialized at Start. }\n    LabelFps: TCastleLabel;\n    SceneBlackKing1: TCastleScene; \/\/&lt; new line\n  public\n  ...<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Nota: En este momento, el editor de Castle Game Engine no hace esto autom\u00e1ticamente por ti. Es decir, no actualizamos autom\u00e1ticamente tus fuentes Pascal para declarar todos los componentes. Tenemos planes de implementar esto pronto. La experiencia del usuario tendr\u00e1 que ser un poco diferente a la de los formularios en Delphi y Lazarus, porque los dise\u00f1os visuales de juegos pueden tener f\u00e1cilmente cientos de componentes que no se supone que se utilicen desde el c\u00f3digo, por lo que sincronizarlos todos con el c\u00f3digo Pascal crear\u00eda ruido innecesario en tu unidad Pascal. En su lugar, haremos un bot\u00f3n para exponer solo un subconjunto de componentes dise\u00f1ados para el c\u00f3digo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Una vez que hayas declarado el campo \u00abpublished\u00bb, podemos acceder a SceneBlackKing1 desde el c\u00f3digo, obteniendo y estableciendo sus propiedades, llamando a sus m\u00e9todos donde queramos. Para este ejercicio, modificaremos la propiedad Translation de nuestra pieza de ajedrez, que cambia la posici\u00f3n del objeto.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Es una propiedad de tipo TVector3. TVector3 es un registro avanzado en Castle Game Engine que representa un vector 3D, en este caso una posici\u00f3n, pero tambi\u00e9n lo usamos en muchos otros casos, por ejemplo, para representar una direcci\u00f3n o incluso un color RGB. Hay varias funciones \u00fatiles definidas para ayudarte a trabajar con TVector3, en particular:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>La funci\u00f3n Vector3(\u2026) devuelve un nuevo<strong> <\/strong>valor TVector3 con las coordenadas proporcionadas.<\/li>\n\n\n\n<li>Los operadores aritm\u00e9ticos como + funcionan con valores TVector3.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Esto significa que podemos mover el objeto f\u00e1cilmente escribiendo un c\u00f3digo como este:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">SceneBlackKing1.Translation := SceneBlackKing1.Translation + Vector3(0, 1, 0);<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">\u00bfD\u00f3nde poner esta declaraci\u00f3n? En general, puedes usar este c\u00f3digo en cualquier lugar de tu vista (siempre que se ejecute despu\u00e9s de que la vista se haya iniciado). En este caso, queremos reaccionar cuando el usuario presione la tecla x. Para lograr esto, podemos editar el m\u00e9todo TViewMain.Press en la vista. La implementaci\u00f3n vac\u00eda de este m\u00e9todo ya est\u00e1 presente, con algunos comentarios \u00fatiles, as\u00ed que simplemente podemos llenarlo con nuestro c\u00f3digo:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">function TViewMain.Press(const Event: TInputPressRelease): Boolean;\nbegin\n  Result := inherited;\n  if Result then Exit; \/\/ allow the ancestor to handle keys\n\n  if Event.IsKey(keyX) then\n  begin\n    SceneBlackKing1.Translation := SceneBlackKing1.Translation + Vector3(0, 1, 0);\n    Exit(true); \/\/ key was handled\n  end;\nend;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Compila y ejecuta el juego (por ejemplo, presionando F9 en el editor de Castle Game Engine, o en Delphi, o en Lazarus) y presiona X para ver c\u00f3mo funciona.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Empujar la pieza de ajedrez utilizando f\u00edsica<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Vamos a empujar (lanzar, arrojar) una pieza de ajedrez utilizando f\u00edsica. Asegur\u00e9monos de que podemos usar c\u00f3digo para este prop\u00f3sito en este ejercicio. La pieza de ajedrez que empujaremos y la direcci\u00f3n en la que la empujaremos estar\u00e1n codificadas en este ejercicio, pero ganaremos confianza en nuestra capacidad para utilizar la f\u00edsica desde el c\u00f3digo Pascal.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Utilizaremos nuevamente el rey negro.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Para hacer esto, aseg\u00farate de agregar los componentes de f\u00edsica a la pieza de ajedrez relevante. Describimos c\u00f3mo hacer esto en la primera parte del art\u00edculo. Un breve resumen: haz clic derecho en el componente (SceneBlackKing1 en este caso) y en el men\u00fa contextual elige \u00abAgregar Comportamiento \u2192 F\u00edsica \u2192 Collider \u2192 Caja (TCastleBoxCollider)\u00bb. Aseg\u00farate tambi\u00e9n de tener f\u00edsica activada en el tablero de ajedrez (con TCastleMeshCollider), de lo contrario, la pieza de ajedrez caer\u00eda debido a la gravedad tan pronto como ejecutes el juego.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Deber\u00eda tener un aspecto similar a este:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"579\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/chess_piece_physics-1024x579.png\" alt=\"\" class=\"wp-image-769\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/chess_piece_physics-1024x579.png 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/chess_piece_physics-300x170.png 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/chess_piece_physics-768x434.png 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/chess_piece_physics-1536x868.png 1536w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/chess_piece_physics.png 1850w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Para empujarlo usando f\u00edsica, queremos utilizar el m\u00e9todo ApplyImpulse del componente TCastleRigidBody asociado a la pieza de ajedrez.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Puedes obtener el componente TCastleRigidBody utilizando el m\u00e9todo SceneBlackKing1.FindBehavior(TCastleRigidBody), como se muestra a continuaci\u00f3n.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Alternativamente, tambi\u00e9n podr\u00edas declarar y acceder a RigidBody1: TCastleRigidBody en la secci\u00f3n published de tu vista. No mostramos este enfoque aqu\u00ed simplemente porque el uso de FindBehavior parece m\u00e1s educativo en este punto, es decir, encontrar\u00e1s FindBehavior \u00fatil en m\u00e1s situaciones.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">El m\u00e9todo ApplyImpulse toma dos par\u00e1metros: la direcci\u00f3n del impulso (como TVector3; la longitud de este vector determina la fuerza del impulso) y la posici\u00f3n desde la cual proviene el impulso (es m\u00e1s simple usar simplemente la posici\u00f3n de la pieza de ajedrez aqu\u00ed).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Al final, esta es la versi\u00f3n modificada de TViewMain.Press que debes utilizar:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">function TViewMain.Press(const Event: TInputPressRelease): Boolean;\nvar\n  MyBody: TCastleRigidBody;\nbegin\n  Result := inherited;\n  if Result then Exit; \/\/ allow the ancestor to handle keys\n\n  if Event.IsKey(keyX) then\n  begin\n    MyBody := SceneBlackKing1.FindBehavior(TCastleRigidBody) as TCastleRigidBody;\n    MyBody.ApplyImpulse(Vector3(0, 10, 0), SceneBlackKing1.WorldTranslation);\n    Exit(true); \/\/ key was handled\n  end;\nend;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Arriba usamos el vector de direcci\u00f3n Vector3(0, 10, 0), lo cual significa \u00abhacia arriba, con fuerza 10\u00bb. Puedes experimentar con diferentes direcciones y fuerzas. Si quisi\u00e9ramos empujar la pieza de ajedrez horizontalmente, usar\u00edamos una direcci\u00f3n con valores no nulos en X y\/o Z, y dejar\u00edamos el eje Y en cero.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">En la cl\u00e1usula uses, agrega tambi\u00e9n la unidad CastleTransform, para tener definida la clase TCastleRigidBody.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Como de costumbre, compila y ejecuta el juego para probarlo. Al presionar X ahora deber\u00eda hacer que la pieza de ajedrez se eleve.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Puedes presionar X repetidamente, incluso cuando la pieza de ajedrez ya est\u00e1 en el aire. Como se puede ver en el c\u00f3digo, no lo hemos asegurado, as\u00ed que permitimos empujar un objeto que ya est\u00e1 volando. No cubriremos esto en este ejercicio, pero podr\u00edas usar MyBody.PhysicsRayCast para lanzar un rayo con direcci\u00f3n Vector3(0, -1, 0) y ver si la pieza de ajedrez ya est\u00e1 en el aire.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"609\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/chess_piece_thrown-1024x609.png\" alt=\"\" class=\"wp-image-771\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/chess_piece_thrown-1024x609.png 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/chess_piece_thrown-300x178.png 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/chess_piece_thrown-768x457.png 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/chess_piece_thrown-1536x913.png 1536w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/chess_piece_thrown.png 1564w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\">Hacer que el c\u00f3digo reconozca \u00abqu\u00e9 es una pieza de ajedrez\u00bb utilizando comportamientos<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Para implementar nuestra l\u00f3gica deseada, el c\u00f3digo debe saber de alguna manera \u00abqu\u00e9 es una pieza de ajedrez\u00bb. Hasta ahora, nuestro mundo 3D es una colecci\u00f3n de componentes TCastleScene, pero esto no nos proporciona suficiente informaci\u00f3n para distinguir entre piezas de ajedrez y otros objetos (como un tablero de ajedrez). \u00a1Queremos hacer algo loco, pero no queremos voltear el tablero de ajedrez! Al menos no esta vez \ud83d\ude42<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Para \u00abmarcar\u00bb que el componente TCastleScene dado es una pieza de ajedrez, inventaremos una nueva clase llamada TChessPieceBehavior que desciende de la clase TCastleBehavior. Luego adjuntaremos instancias de esta clase a los componentes TCastleScene que representan piezas de ajedrez. En el futuro, esta clase puede tener m\u00e1s campos (que contengan informaci\u00f3n espec\u00edfica de esta pieza de ajedrez) y m\u00e9todos. Para empezar, la mera existencia de una instancia TCastleBehavior adjunta a una escena indica \u00abesto es una pieza de ajedrez\u00bb.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Para obtener m\u00e1s informaci\u00f3n sobre c\u00f3mo funcionan nuestros comportamientos, consulta la documentaci\u00f3n y ejemplos en<a href=\" https:\/\/castle-engine.io\/behaviors\"> https:\/\/castle-engine.io\/behaviors<\/a>. Tambi\u00e9n puedes crear un nuevo proyecto a partir de la plantilla \u00abJuego FPS 3D\u00bb y ver c\u00f3mo se define y utiliza la clase TEnemy (descendiente de TCastleBehavior). Los comportamientos son un concepto muy flexible para agregar informaci\u00f3n y mec\u00e1nicas a tu mundo, y recomendamos utilizarlos en muchas situaciones.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Realmente no hay nada dif\u00edcil en nuestra definici\u00f3n inicial de TChessPieceBehavior. Es casi una clase vac\u00eda. Decid\u00ed agregar solo un campo Booleano que indique si la pieza de ajedrez es blanca o negra:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">type\n  TChessPieceBehavior = class(TCastleBehavior)\n  public\n    Black: Boolean;\n  end;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Puedes declararlo al principio de la secci\u00f3n de interfaz de la unidad GameViewMain. Aunque las clases de comportamiento m\u00e1s grandes podr\u00edan merecer ser colocadas en sus propias unidades.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u00bfC\u00f3mo adjuntar las instancias de comportamiento a las escenas?<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Puedes hacerlo visualmente registrando la clase TChessPieceBehavior en el editor de Castle Game Engine. Este m\u00e9todo es muy poderoso porque te permite a\u00f1adir y configurar visualmente las propiedades del comportamiento. Consulta <a href=\"https:\/\/castle-engine.io\/custom_components\">https:\/\/castle-engine.io\/custom_components<\/a> para ver c\u00f3mo utilizarlo.<\/li>\n\n\n\n<li>O puedes hacerlo desde el c\u00f3digo. En este art\u00edculo, he decidido seguir este enfoque. Esto es un poco m\u00e1s f\u00e1cil si necesitas adjuntar efectivamente el comportamiento 32 veces, a todas las piezas de ajedrez, y no es necesario configurar espec\u00edficamente el estado inicial del comportamiento. Hacer clic 32 veces en \u00abAgregar Comportamiento\u00bb ser\u00eda un poco tedioso y tambi\u00e9n innecesario en nuestro caso simple (para esta demostraci\u00f3n, todas las piezas de ajedrez realmente funcionan de la misma manera), as\u00ed que en su lugar utilizaremos c\u00f3digo para inicializar f\u00e1cilmente las piezas de ajedrez.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Para adjuntar un comportamiento a nuestra SceneBlackKing1, simplemente crear\u00edamos una instancia de TChessPieceBehavior en el m\u00e9todo Start de nuestra vista, y la a\u00f1adir\u00edamos usando SceneBlackKing1.AddBehavior. As\u00ed:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">procedure TViewMain.Start;\nvar\n  ChessPiece: TChessPieceBehavior;\nbegin\n  inherited;\n  ChessPiece := TChessPieceBehavior.Create(FreeAtStop);\n  ChessPiece.Black := true;\n  SceneBlackKing1.AddBehavior(ChessPiece);\nend;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Pero esto no es lo suficientemente bueno para nuestra aplicaci\u00f3n. Anteriormente agregamos TChessPieceBehavior solo a una pieza de ajedrez. Queremos agregarlo a las 32 piezas de ajedrez. \u00bfC\u00f3mo podemos hacerlo f\u00e1cilmente? Necesitamos de alguna manera iterar sobre todas las piezas de ajedrez. Y para establecer el campo booleano Black, tambi\u00e9n debemos saber de alguna manera si esta es una pieza blanca o negra. Hay m\u00faltiples soluciones:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Podr\u00edamos suponer que todas las piezas de ajedrez tienen nombres como SceneWhiteXxx o SceneBlackXxx. Entonces podr\u00edamos iterar sobre los hijos de Viewport1.Items y verificar si su nombre comienza con el prefijo dado.<\/li>\n\n\n\n<li>O podr\u00edamos observar el valor de la etiqueta (Tag) de las escenas, y tener una convenci\u00f3n, por ejemplo, que Tag = 1 significa pieza de ajedrez negra, Tag = 2 significa pieza de ajedrez blanca, y otras etiquetas (Tag = 0 es el predeterminado, en particular) significan que no es una pieza de ajedrez.<\/li>\n\n\n\n<li>Tambi\u00e9n podr\u00edamos introducir componentes de transformaci\u00f3n adicionales que agrupen las piezas de ajedrez negras por separado de las piezas de ajedrez blancas y por separado de otros elementos (como el tablero de ajedrez).<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Decid\u00ed seguir con este \u00faltimo enfoque, ya que la introducci\u00f3n de \u00abcomponentes adicionales TCastleTransform para agrupar los existentes\u00bb es un mecanismo poderoso en muchas otras situaciones. Por ejemplo, luego puedes ocultar o mostrar f\u00e1cilmente un grupo dado utilizando la propiedad Exists de TCastleTransform.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Para hacer esto, haz clic derecho en Viewport1.Items y elige en el men\u00fa contextual \u00abAgregar Transformaci\u00f3n \u2192 Transformaci\u00f3n (TCastleTransform)\u00bb.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"579\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/adding_transform-1024x579.png\" alt=\"\" class=\"wp-image-775\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/adding_transform-1024x579.png 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/adding_transform-300x170.png 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/adding_transform-768x434.png 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/adding_transform-1536x868.png 1536w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/adding_transform.png 1850w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Nombre este nuevo componente como \u00abPiezasNegras\u00bb. Luego, arrastra y suelta en la jerarqu\u00eda del editor todas las piezas de ajedrez negras (componentes SceneBlackXxx) para que sean hijos de PiezasNegras. Puedes seleccionar f\u00e1cilmente las 16 escenas que representan las piezas negras en la jerarqu\u00eda manteniendo presionada la tecla Shift y luego arrastr\u00e1ndolas todas juntas dentro de PiezasNegras.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">El resultado final deber\u00eda ser algo as\u00ed en la jerarqu\u00eda:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"579\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/black_pieces_group-1024x579.png\" alt=\"\" class=\"wp-image-777\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/black_pieces_group-1024x579.png 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/black_pieces_group-300x170.png 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/black_pieces_group-768x434.png 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/black_pieces_group-1536x868.png 1536w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/black_pieces_group.png 1850w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">No te preocupes si solo SceneBlackKing1 tiene los componentes de f\u00edsica. Pronto tambi\u00e9n configuraremos los componentes de f\u00edsica usando c\u00f3digo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ahora repite el proceso para agregar un grupo WhitePieces.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"579\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/white_pieces_group-1024x579.png\" alt=\"\" class=\"wp-image-778\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/white_pieces_group-1024x579.png 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/white_pieces_group-300x170.png 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/white_pieces_group-768x434.png 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/white_pieces_group-1536x868.png 1536w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/white_pieces_group.png 1850w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Esta preparaci\u00f3n en el editor facilita nuestra tarea de c\u00f3digo. Agrega a la secci\u00f3n publicada de la declaraci\u00f3n de TViewMain los campos BlackPieces y WhitePieces, de tipo TCastleTransform:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">TViewMain = class(TCastleView)\n  published\n    ... \/\/ manten los otros campos\n    BlackPieces, WhitePieces: TCastleTransform;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Ahora itera sobre los grupos de las 2 piezas de ajedrez en el m\u00e9todo Start:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">procedure TViewMain.Start;\n\n  procedure ConfigureChessPiece(const Child: TCastleTransform; const Black: Boolean);\n  var\n    ChessPiece: TChessPieceBehavior;\n  begin\n    ChessPiece := TChessPieceBehavior.Create(FreeAtStop);\n    ChessPiece.Black := true;\n    Child.AddBehavior(ChessPiece);\n  end;\n\nvar\n  Child: TCastleTransform;\nbegin\n  inherited;\n  for Child in BlackPieces do\n    ConfigureChessPiece(Child, true);\n  for Child in WhitePieces do\n    ConfigureChessPiece(Child, false);\nend;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Ser\u00eda prudente a\u00f1adir una \u00abverificaci\u00f3n b\u00e1sica\u00bb en este punto. Vamos a registrar el n\u00famero de piezas de ajedrez que tiene cada lado. A\u00f1ade el siguiente c\u00f3digo al final del m\u00e9todo Start:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">WritelnLog('Configured %d black and %d white chess pieces', [\n  BlackPieces.Count,\n  WhitePieces.Count\n]);<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Para hacer que WritelnLog est\u00e9 disponible, a\u00f1ade la unidad CastleLog a la cl\u00e1usula uses. Ahora, al ejecutar el juego, deber\u00edas ver un registro.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Configured 16 black and 16 white chess pieces<\/em><br><br>En mi primera ejecuci\u00f3n, me di cuenta de que ten\u00eda 17 piezas de ajedrez en cada lado por accidente. Por error, a\u00f1ad\u00ed 3 caballos en lugar de 2 (uno de los caballos estaba exactamente en la misma posici\u00f3n que otro, por lo que no era obvio). Gracias a este registro, elimin\u00e9 las piezas de caballo adicionales. Detectar este tipo de errores es precisamente la raz\u00f3n por la cual a\u00f1adimos registros y realizamos pruebas, as\u00ed que te animo a que tambi\u00e9n lo hagas.<br><br>Aprovechando esta oportunidad, podemos asegurarnos de que todas las piezas de ajedrez tengan componentes f\u00edsicos (TCastleRigidBody y TCastleBoxCollider). As\u00ed que no necesitas a\u00f1adirlos manualmente a cada una. Este enfoque es razonable si los componentes no necesitan ajustes manuales espec\u00edficos por cada pieza de ajedrez.<br><br>Para hacer esto, ampliemos nuestro m\u00e9todo ConfigureChessPiece:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">procedure ConfigureChessPiece(const Child: TCastleTransform; const Black: Boolean);\n  begin\n    ... \/\/ keep previous code too\n    if Child.FindBehavior(TCastleRigidBody) = nil then\n      Child.AddBehavior(TCastleRigidBody.Create(FreeAtStop));\n    if Child.FindBehavior(TCastleCollider) = nil then\n      Child.AddBehavior(TCastleBoxCollider.Create(FreeAtStop));\n  end;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Como ves arriba, este enfoque es bastante directo: si no tienes el componente necesario, simplemente agr\u00e9galo. No nos molestamos en configurar ninguna propiedad en las nuevas instancias de TCastleRigidBody y TCastleBoxCollider, ya que sus valores predeterminados son adecuados para nuestro prop\u00f3sito.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Todo esto fue un buen \u00abtrabajo preliminar\u00bb para la parte restante del art\u00edculo. En realidad, no ha ocurrido ning\u00fan cambio funcional en nuestro juego; deber\u00edas ejecutarlo y ver que\u2026 nada ha cambiado. Las 32 piezas de ajedrez siguen en su lugar, al principio.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Seleccionar objetos 3D usando el mouse<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Resaltar la pieza de ajedrez bajo el mouse y permitir seleccionarla <\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Para implementar la interacci\u00f3n real, queremos permitir al usuario elegir qu\u00e9 pieza de ajedrez lanzar usando el mouse. Castle Game Engine proporciona una funci\u00f3n lista que te indica qu\u00e9 objeto est\u00e1 siendo se\u00f1alado por la posici\u00f3n actual del mouse (o la \u00faltima pulsaci\u00f3n en dispositivos m\u00f3viles). Esta funci\u00f3n es TCastleViewport.TransformUnderMouse.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Para empezar, aseg\u00farate de declarar la instancia del viewport en la secci\u00f3n publicada de la clase TViewMain, de esta manera:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>MainViewport: TCastleViewport;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Aseg\u00farate de que el nombre de tu viewport coincida con el designado en el dise\u00f1o. Agrega la unidad CastleViewport a la cl\u00e1usula uses para hacer que el tipo TCastleViewport sea conocido.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Vamos a utilizar esta funci\u00f3n para resaltar la pieza de ajedrez actual en la posici\u00f3n del mouse. Simplemente seguiremos verificando el valor de MainViewport.TransformUnderMouse en cada llamada a Update.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Nota: Alternativamente, podr\u00edamos verificar MainViewport.TransformUnderMouse en cada llamada a Motion, que ocurre solo cuando cambia la posici\u00f3n del mouse (o el toque). Pero hacerlo en Update es un poco mejor: como estamos utilizando f\u00edsica, algunas piezas de ajedrez a\u00fan pueden estar en movimiento debido a la f\u00edsica, por lo que la pieza de ajedrez bajo el mouse puede cambiar incluso si la posici\u00f3n del mouse no cambia.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Para mostrar realmente el resaltado, utilizaremos un efecto listo disponible para cada TCastleScene que se puede activar configurando MyScene.RenderOptions.WireframeEffect con algo distinto de weNormal. Esta es la forma m\u00e1s sencilla de mostrar el resaltado (discutiremos otras formas en una secci\u00f3n posterior).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Antes de pasar al c\u00f3digo, te animo a experimentar con la configuraci\u00f3n perfecta de RenderOptions para el resaltado en el editor. Simplemente edita cualquier pieza de ajedrez elegida hasta que tenga un resaltado atractivo, y recuerda las opciones elegidas. Las propiedades m\u00e1s \u00fatiles para ajustar son WireframeEffect, WireframeColor, LineWidth, SilhouetteBias, SilhouetteScale. Puedes verlas enfatizadas abajo: el editor muestra las propiedades que tienen valores no predeterminados usando una fuente en negrita.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"552\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/render_options-1-1024x552.webp\" alt=\"\" class=\"wp-image-783\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/render_options-1-1024x552.webp 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/render_options-1-300x162.webp 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/render_options-1-768x414.webp 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/render_options-1-1536x828.webp 1536w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/render_options-1.webp 1845w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">He decidido mostrar la pieza de ajedrez actualmente resaltada (en la posici\u00f3n del mouse) con un alambre de color azul claro. Esta pieza de ajedrez tambi\u00e9n se establece como el valor del campo privado ChessPieceHover.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Adem\u00e1s, una vez que el usuario hace clic con el mouse (podemos detectarlo en Press), la pieza de ajedrez se considera seleccionada y obtiene un resaltado amarillo. Esta pieza de ajedrez se establece como el valor de ChessPieceSelected.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Recordar los valores de ChessPieceHover y ChessPieceSelected es \u00fatil para algunas cosas. Por un lado, podemos desactivar el efecto m\u00e1s adelante (cuando la pieza ya no est\u00e9 resaltada o seleccionada). Adem\u00e1s, nos permitir\u00e1 lanzar la pieza ChessPieceSelected en las pr\u00f3ximas secciones.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Podr\u00edamos almacenarlos como referencias a TCastleScene o TChessPieceBehavior. Es decir, podr\u00edamos declarar:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>O bien ChessPieceHover, ChessPieceSelected: TChessPieceBehavior; \u2026<\/li>\n\n\n\n<li>\u2026 o ChessPieceHover, ChessPieceSelected: TCastleScene;<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Ambas declaraciones ser\u00edan v\u00e1lidas para nuestra aplicaci\u00f3n. Es decir, tenemos que elegir una u otra ya que implicar\u00e1 un c\u00f3digo un poco diferente, pero las diferencias son realmente menores. Al final, siempre podemos obtener una instancia de TChessPieceBehavior de un TCastleScene correspondiente (si sabemos que es una pieza de ajedrez) y podemos obtener un TCastleScene de un TChessPieceBehavior.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Para obtener TChessPieceBehavior del TCastleScene correspondiente, har\u00edamos lo siguiente:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">var\n  MyBehavior: TChessPieceBehavior;\n  MyScene: TCastleScene;\nbegin\n  ...\n  MyBehavior := MyScene.FindBehavior(TChessPieceBehavior) as TChessPieceBehavior;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Para obtener TCastleScene a partir de un TChessPieceBehavior correspondiente, har\u00edas lo siguiente:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">var\n  MyBehavior: TChessPieceBehavior;\n  MyScene: TCastleScene;\nbegin\n  ...\n  MyScene := MyBehavior.Parent as TCastleScene;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Si decides seguir mi enfoque exactamente, agrega esto a la secci\u00f3n privada de la clase TViewMain:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">ChessPieceHover, ChessPieceSelected: TChessPieceBehavior;\n{ Turn on \/ off the highlight effect, depending on whether\n  Behavior equals ChessPieceHover, ChessPieceSelected or none of them.\n  This accepts (and ignores) Behavior = nil value. }\nprocedure ConfigureEffect(const Behavior: TChessPieceBehavior);<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Entonces agrega la unidad CastleColors a la cl\u00e1usula uses (ya sea en la interfaz o la implementaci\u00f3n) de la unidad GameViewMain, no importa en este caso, para definir la utilidad HexToColorRGB.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Finalmente, este es el c\u00f3digo actualizado de los m\u00e9todos Update, Press y del ayudante ConfigureEffect:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">procedure TViewMain.ConfigureEffect(const Behavior: TChessPieceBehavior);\nvar\n  Scene: TCastleScene;\nbegin\n  if Behavior = nil then\n    Exit;\n  { Behavior can be attached to any TCastleTransform.\n    But in our case, we know TChessPieceBehavior is attached to TCastleScene. }\n  Scene := Behavior.Parent as TCastleScene;\n  if (Behavior = ChessPieceHover) or\n     (Behavior = ChessPieceSelected) then\n  begin\n    Scene.RenderOptions.WireframeEffect := weSilhouette;\n    if Behavior = ChessPieceSelected then\n      Scene.RenderOptions.WireframeColor := HexToColorRGB('FFEB00')\n    else\n      Scene.RenderOptions.WireframeColor := HexToColorRGB('5455FF');\n    Scene.RenderOptions.LineWidth := 10;\n    Scene.RenderOptions.SilhouetteBias := 20;\n    Scene.RenderOptions.SilhouetteScale := 20;\n  end else\n  begin\n    Scene.RenderOptions.WireframeEffect := weNormal;\n  end;\nend;\n\nprocedure TViewMain.Update(const SecondsPassed: Single; var HandleInput: Boolean);\nvar\n  OldHover: TChessPieceBehavior;\nbegin\n  inherited;\n\n  LabelFps.Caption := 'FPS: ' + Container.Fps.ToString;\n\n  OldHover := ChessPieceHover;\n\n  if MainViewport.TransformUnderMouse &lt;&gt; nil then\n  begin\n    ChessPieceHover := MainViewport.TransformUnderMouse.FindBehavior(TChessPieceBehavior)\n      as TChessPieceBehavior;\n  end else\n    ChessPieceHover := nil;\n\n  if OldHover &lt;&gt; ChessPieceHover then\n  begin\n    ConfigureEffect(OldHover);\n    ConfigureEffect(ChessPieceHover);\n  end;\nend;\n\nfunction TViewMain.Press(const Event: TInputPressRelease): Boolean;\nvar\n  MyBody: TCastleRigidBody;\n  OldSelected: TChessPieceBehavior;\nbegin\n  Result := inherited;\n  if Result then Exit; \/\/ allow the ancestor to handle keys\n\n  \/\/ ... if you want, keep here the handling of keyX from previous exercise\n\n  if Event.IsMouseButton(buttonLeft) then\n  begin\n    OldSelected := ChessPieceSelected;\n    if (ChessPieceHover &lt;&gt; nil) and\n       (ChessPieceHover &lt;&gt; ChessPieceSelected) then\n    begin\n      ChessPieceSelected := ChessPieceHover;\n      ConfigureEffect(OldSelected);\n      ConfigureEffect(ChessPieceSelected);\n    end;\n    Exit(true); \/\/ mouse click was handled\n  end;\nend;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Como siempre, recuerda compilar y ejecutar el c\u00f3digo para asegurarte de que funcione correctamente.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Notar\u00e1s que MainViewport.TransformUnderMouse detecta lo que est\u00e1 debajo del mouse, pero trata a cada pieza de ajedrez como una caja. Por lo tanto, la detecci\u00f3n no es precisa visualmente. Para corregir esto, establece PreciseCollisions en true en todas las piezas de ajedrez. Puedes hacer esto f\u00e1cilmente seleccionando todas las piezas de ajedrez en el editor usando Shift o Ctrl y luego cambiando PreciseCollisions en el Inspector de Objetos.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"542\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/precise_collisions-1024x542.png\" alt=\"\" class=\"wp-image-787\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/precise_collisions-1024x542.png 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/precise_collisions-300x159.png 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/precise_collisions-768x406.png 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/precise_collisions-1536x813.png 1536w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/precise_collisions-720x380.png 720w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/precise_collisions.png 1845w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">He decidido mover la c\u00e1mara en este punto tambi\u00e9n (para mostrar ambas partes, negra y blanca, desde una vista lateral).<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"579\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/better_camera-1024x579.png\" alt=\"\" class=\"wp-image-788\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/better_camera-1024x579.png 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/better_camera-300x170.png 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/better_camera-768x434.png 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/better_camera-1536x868.png 1536w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/better_camera.png 1850w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"601\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/highlight-1024x601.png\" alt=\"\" class=\"wp-image-789\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/highlight-1024x601.png 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/highlight-300x176.png 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/highlight-768x451.png 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/highlight.png 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\">Nota adicional: Otras formas de mostrar un resaltado<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Existen otras formas de resaltar la pieza de ajedrez seleccionada (o resaltada).<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Cambiar din\u00e1micamente el color del material. Esto se logra accediendo a una instancia de TPhysicalMaterialNode dentro de los nodos de la escena (TCastleScene.RootNode) y modificando TPhysicalMaterialNode.BaseColor. Consulta por ejemplo el ejemplo del motor en examples\/viewport_and_scenes\/collisions\/ que utiliza este enfoque.<\/li>\n\n\n\n<li>A\u00f1adir\/eliminar din\u00e1micamente un efecto de sombreado. Esto implica agregar nodos TEffectNode y TEffectPartNode a la escena e implementar el efecto usando GLSL (Lenguaje de Sombreado de OpenGL). Consulta por ejemplo el ejemplo del motor en examples\/viewport_and_scenes\/shader_effects\/ que demuestra este m\u00e9todo.<\/li>\n\n\n\n<li>A\u00f1adir una caja adicional que rodee el objeto elegido. El editor CGE mismo utiliza esta t\u00e9cnica para mostrar objetos 3D resaltados\/seleccionados. Utiliza la clase TDebugTransformBox para implementar esto f\u00e1cilmente.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Si tienes curiosidad, espero que la informaci\u00f3n y ejemplos anteriores te orienten en la direcci\u00f3n correcta.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Nota adicional: Sombras<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">He decidido activar las sombras en este punto. Simplemente establece Shadows en true en la fuente de luz principal. Adem\u00e1s, establece RenderOptions.WholeSceneManifold en true en las piezas de ajedrez. Esto deber\u00eda hacer que todo proyecte sombras agradables. Las sombras son din\u00e1micas, lo que significa que cambiar\u00e1n adecuadamente cuando movamos las piezas de ajedrez.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Consulta <a href=\"https:\/\/castle-engine.io\/shadow_volumes\">https:\/\/castle-engine.io\/shadow_volumes<\/a> para obtener m\u00e1s informaci\u00f3n sobre sombras en Castle Game Engine.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"579\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/shadows-1024x579.png\" alt=\"\" class=\"wp-image-790\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/shadows-1024x579.png 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/shadows-300x170.png 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/shadows-768x434.png 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/shadows-1536x868.png 1536w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/shadows.png 1850w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\">Permitir al usuario elegir el \u00e1ngulo y la fuerza para lanzar la pieza de ajedrez<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Una vez que el usuario ha seleccionado una pieza de ajedrez, queremos permitirle configurar la direcci\u00f3n y la fuerza con la que lanzar el objeto elegido. Ya sabemos que \u00ablanzar\u00bb la pieza de ajedrez t\u00e9cnicamente significa \u00abaplicar una fuerza f\u00edsica al cuerpo r\u00edgido de la pieza de ajedrez seleccionada\u00bb. Casi tenemos todo lo que necesitamos, pero necesitamos permitir que el usuario elija la direcci\u00f3n y la fuerza de esta fuerza.<br><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Dise\u00f1ando una flecha 3D<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Para visualizar la fuerza deseada, utilizaremos un modelo simple de flecha 3D, que se rotar\u00e1 y escalar\u00e1 seg\u00fan corresponda. Aunque podr\u00edamos dise\u00f1ar este modelo en Blender u otro software de autor\u00eda 3D, en este caso es m\u00e1s f\u00e1cil hacerlo completamente en el editor Castle Game Engine. La flecha es una composici\u00f3n de dos formas simples: un cono (para la punta de la flecha) y un cilindro.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Adem\u00e1s, dise\u00f1aremos la flecha de manera independiente, como un dise\u00f1o separado. El nuevo dise\u00f1o contendr\u00e1 una jerarqu\u00eda de componentes, con la ra\u00edz siendo TCastleTransform. Lo guardaremos como un archivo force_gizmo.castle-transform en el subdirectorio de datos del proyecto. Luego lo a\u00f1adiremos al dise\u00f1o principal (gameviewmain.castle-user-interface) y alternaremos la existencia, rotaci\u00f3n y escala de la fuerza visualizada.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Utilizar un archivo de dise\u00f1o separado para la flecha 3D, aunque no sea estrictamente necesario en este caso, es una t\u00e9cnica poderosa. Cuando algo se guarda como un archivo de dise\u00f1o separado, se puede reutilizar libremente e instanciar muchas veces (en tiempo de dise\u00f1o o mediante la creaci\u00f3n din\u00e1mica durante la ejecuci\u00f3n del juego). Esto es, por ejemplo, c\u00f3mo tener criaturas en tu juego: objetos 3D que comparten l\u00f3gica com\u00fan y que pueden generarse cuando sea necesario.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Para comenzar a dise\u00f1ar la flecha, elige el elemento de men\u00fa del editor \u00abDise\u00f1o \u2192 Nuevo Transform (Transformaci\u00f3n vac\u00eda como ra\u00edz)\u00bb.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"579\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/new_transform-1024x579.png\" alt=\"\" class=\"wp-image-792\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/new_transform-1024x579.png 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/new_transform-300x170.png 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/new_transform-768x434.png 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/new_transform-1536x868.png 1536w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/new_transform.png 1850w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Debajo de esto, agrega dos componentes: TCastleCylinder y TCastleCone.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ajusta su Altura, Radio (en el cilindro), RadioBase (en el cono) y su Posici\u00f3n para formar una flecha 3D agradable.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ajusta su Color a algo diferente al predeterminado para embellecer las cosas. Recuerda que la flecha ser\u00e1 iluminada por las luces que hemos configurado en el dise\u00f1o principal (gameviewmain.castle-user-interface), por lo que probablemente ser\u00e1 m\u00e1s brillante de lo que observas ahora.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Puedes seguir los valores que he elegido en las capturas de pantalla a continuaci\u00f3n, pero en realidad son solo ejemplos. Adelante y crea tu propia flecha 3D como prefieras.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"553\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/cone-1024x553.png\" alt=\"\" class=\"wp-image-794\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/cone-1024x553.png 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/cone-300x162.png 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/cone-768x415.png 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/cone-1536x830.png 1536w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/cone.png 1845w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"553\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/cylinder-1024x553.png\" alt=\"\" class=\"wp-image-795\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/cylinder-1024x553.png 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/cylinder-300x162.png 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/cylinder-768x415.png 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/cylinder-1536x830.png 1536w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/cylinder.png 1845w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Ahora viene una parte un poco dif\u00edcil. Queremos tener una flecha que pueda rotar f\u00e1cilmente alrededor de una caja ficticia (en el juego real, rotar\u00e1 alrededor de una pieza de ajedrez). Idealmente, la flecha tambi\u00e9n deber\u00eda escalar f\u00e1cilmente para visualizar la fuerza de empuje. Uso la palabra \u00abf\u00e1cilmente\u00bb para enfatizar que no queremos solo rotarla en el editor, sino que tambi\u00e9n permitiremos al usuario rotarla durante el juego. Por lo tanto, la rotaci\u00f3n y la escala que nos interesan deben ser muy f\u00e1ciles de obtener y establecer desde el c\u00f3digo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Para hacer esto, primero agrega una caja ficticia que represente una pieza de ajedrez. Yo la llam\u00e9 DebugBoxToBeHidden y configur\u00e9 su tama\u00f1o a 2 3 2 para tener en cuenta piezas altas (eje Y grande). M\u00e1s tarde haremos que la caja sea invisible estableciendo su propiedad Exists en false.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Una vez que tengas la caja, quieres agregar componentes TCastleTransform intermedios para:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Rotar la flecha (cono y cilindro) para que sea horizontal.<\/li>\n\n\n\n<li>Mover la flecha lejos de la caja.<\/li>\n\n\n\n<li>Rotar la flecha alrededor de la caja.<\/li>\n\n\n\n<li>Escalar la flecha.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Hay m\u00faltiples formas v\u00e1lidas de lograr esto. El consejo clave es no dudar en hacer una composici\u00f3n anidada, es decir, colocar TCastleTransform dentro de otro TCastleTransform y as\u00ed sucesivamente. Permite que cada TCastleTransform realice una sola funci\u00f3n. T\u00f3matelo paso a paso y llegar\u00e1s a una soluci\u00f3n v\u00e1lida (y realmente hay varias formas posibles de organizar esto).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Mira mi disposici\u00f3n en las capturas de pantalla a continuaci\u00f3n. Si te quedas atascado, simplemente usa el dise\u00f1o de nuestro proyecto resultante en <a href=\"https:\/\/github.com\/castle-engine\/bad-chess\/\">https:\/\/github.com\/castle-engine\/bad-chess\/<\/a> (en el subdirectorio project\/version_2_with_code).<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"402\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/arrow_1-1024x402.png\" alt=\"\" class=\"wp-image-797\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/arrow_1-1024x402.png 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/arrow_1-300x118.png 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/arrow_1-768x302.png 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/arrow_1-1536x604.png 1536w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/arrow_1.png 1845w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"402\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/arrow_2-1024x402.png\" alt=\"\" class=\"wp-image-799\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/arrow_2-1024x402.png 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/arrow_2-300x118.png 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/arrow_2-768x302.png 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/arrow_2-1536x604.png 1536w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/arrow_2.png 1845w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"402\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/arrow_3-1024x402.png\" alt=\"\" class=\"wp-image-800\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/arrow_3-1024x402.png 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/arrow_3-300x118.png 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/arrow_3-768x302.png 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/arrow_3-1536x604.png 1536w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/arrow_3.png 1845w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">El resultado de mi dise\u00f1o es que s\u00e9 que desde el c\u00f3digo puedo:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Ajustar la propiedad Rotation del componente TransformForceAngle para que sea una simple rotaci\u00f3n alrededor del eje X. El \u00e1ngulo de esta rotaci\u00f3n puede ser elegido por el usuario y efectivamente la flecha orbitar\u00e1 alrededor de la caja ficticia (pieza de ajedrez).<\/li>\n\n\n\n<li>Ajustar Y de la propiedad Scale del componente TransformForceStrength. El usuario puede elegir la cantidad de esta escala para visualizar la fuerza.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Recuerda establecer Exists del componente DebugBoxToBeHidden en false una vez que hayas terminado.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">A\u00f1ade la flecha al dise\u00f1o principal.<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Para probar que funciona, agrega el dise\u00f1o de la flecha al dise\u00f1o principal usando el editor.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Guarda el dise\u00f1o force_gizmo.castle-transform, abre nuestro dise\u00f1o principal en gameviewmain.castle-user-interface, selecciona el componente Items dentro de MainViewport y arrastra y suelta el archivo force_gizmo.castle-transform (desde el panel \u00abFiles\u00bb abajo) en la jerarqu\u00eda.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">El resultado deber\u00eda ser que se cree un nuevo componente llamado DesignForceGizmo1 y se coloque como hijo de Items. La clase del componente es TCastleTransformDesign, lo que significa que es una instancia de TCastleTransform cargada desde otro archivo con extensi\u00f3n .castle-transform. La propiedad URL de este componente deber\u00eda establecerse autom\u00e1ticamente para indicar nuestro archivo force_gizmo.castle-transform.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Renombra este componente simplemente como DesignForceGizmo (como prefieras, pero creo que hace las cosas m\u00e1s claras, ya que solo necesitaremos un gizmo de este tipo). Adem\u00e1s, cambia la propiedad Exists de este componente a false porque inicialmente no queremos que este componente sea visible ni seleccionable por el rat\u00f3n.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La captura de pantalla a continuaci\u00f3n muestra el estado justo antes de establecer Exists en false.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"579\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/design_in_main-1024x579.png\" alt=\"\" class=\"wp-image-803\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/design_in_main-1024x579.png 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/design_in_main-300x170.png 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/design_in_main-768x434.png 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/design_in_main-1536x868.png 1536w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/design_in_main.png 1850w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Permitir al usuario controlar la flecha<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Necesitamos declarar e inicializar los campos que describen el \u00e1ngulo y la fuerza actuales.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Agrega esto a la secci\u00f3n privada de la clase TViewMain:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">const\n  MinStrength = 1;\n  MaxStrength = 1000;\n\n  MinStrengthScale = 1;\n  MaxStrengthScale = 3;\n\n  StrengthChangeSpeed = 30;\n  AngleAChangeSpeed = 10;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Agrega a la cl\u00e1usula uses las nuevas unidades necesarias: Math, CastleUtils.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Finalmente, a\u00f1ade al m\u00e9todo Start de TViewMain el c\u00f3digo adicional para inicializar todo:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">TransformForceAngle := DesignForceGizmo.DesignedComponent('TransformForceAngle')\n    as TCastleTransform;\n  TransformForceStrength := DesignForceGizmo.DesignedComponent('TransformForceStrength')\n    as TCastleTransform;\n  ForceAngle := 0; \/\/ 0 is default value of Single field anyway\n  TransformForceAngle.Rotation := Vector4(1, 0, 0, ForceAngle);\n  ForceStrength := 10; \/\/ set some sensible initial value\n  TransformForceStrength.Scale := Vector3(1,\n    MapRange(ForceStrength, MinStrength, MaxStrength, MinStrengthScale, MaxStrengthScale),\n    1);<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Ten en cuenta que inicializamos los componentes dentro de nuestro dise\u00f1o DesignForceGizmo usando la llamada DesignForceGizmo.DesignedComponent(\u2026\u200b). Esto es necesario, ya que en general puedes tener m\u00faltiples instancias del dise\u00f1o force_gizmo.castle-transform colocadas en tu vista. Por lo tanto, los campos publicados de la vista no pueden asociarse autom\u00e1ticamente con componentes en dise\u00f1os anidados.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Adem\u00e1s, sincronizamos los campos Single ForceStrength y ForceAngle con sus instancias correspondientes TCastleTransform. Single en Pascal es un n\u00famero de punto flotante simple, que es muy f\u00e1cil de manipular. Tratamos las dos instancias TCastleTransform mencionadas anteriormente como una forma elegante de visualizar estos n\u00fameros como rotaci\u00f3n y escala en 3D.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Puede que desees consultar qu\u00e9 hace la funci\u00f3n MapRange en la referencia de la API de Castle Game Engine. En resumen, es una forma c\u00f3moda de realizar una interpolaci\u00f3n lineal, convirtiendo de un rango a otro.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ahora que hemos inicializado todo, vamos a mostrar realmente el DesignForceGizmo cuando el usuario selecciona una pieza de ajedrez. Ya tenemos un c\u00f3digo para seleccionar la pieza de ajedrez con un clic de rat\u00f3n. Solo modif\u00edcalo para mostrar el DesignForceGizmo y reposicionarlo en la pieza de ajedrez seleccionada.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">if Event.IsMouseButton(buttonLeft) then\nbegin\n  OldSelected := ChessPieceSelected;\n  if (ChessPieceHover &lt;&gt; nil) and\n     (ChessPieceHover &lt;&gt; ChessPieceSelected) then\n  begin\n    ... \/\/ conserva el c\u00f3digo anterior\n    \/\/ new lines:\n    DesignForceGizmo.Exists := true;\n    DesignForceGizmo.Translation := ChessPieceSelected.Parent.WorldTranslation;\n  end;\n  Exit(true); \/\/ el click del rat\u00f3n ha sido gestionado\nend;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Nota: Puede que te preguntes acerca de un enfoque alternativo, donde no reposicionamos DesignForceGizmo, sino que en su lugar cambiamos din\u00e1micamente su padre, como en DesignForceGizmo.Parent := ChessPieceSelected.Parent. Esto tambi\u00e9n funcionar\u00eda, aunque con algunas complicaciones adicionales: la rotaci\u00f3n del objeto seleccionado, una vez que lo impulsamos, tambi\u00e9n rotar\u00eda el gizmo. Esto complicar\u00eda el c\u00e1lculo de la \u00abdirecci\u00f3n de impulso deseada\u00bb m\u00e1s adelante. Por eso decid\u00ed optar por el enfoque m\u00e1s simple de simplemente reposicionar el DesignForceGizmo. Si deseas experimentar con el enfoque complicado alternativo, adelante; una soluci\u00f3n ser\u00eda dise\u00f1ar DesignForceGizmo de manera que luego puedas hacer TransformForceAngle.GetWorldView(WorldPos, WorldDir, WorldUp) y usar WorldDir resultante como direcci\u00f3n de fuerza.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pero como mantenemos las cosas simples\u2026 casi hemos terminado. Puedes ejecutar el juego y ver que seleccionar una pieza de ajedrez muestra correctamente el gizmo de flecha. Solo queda permitir al usuario cambiar la direcci\u00f3n y la fuerza. Podemos hacer esto observando las teclas que el usuario presiona en el m\u00e9todo Update. El c\u00f3digo a continuaci\u00f3n permite rotar la flecha (hacer que orbite alrededor de la pieza de ajedrez) usando las teclas de flecha izquierda y derecha, y cambiar la fuerza del impulso (escalar la flecha) usando las teclas de flecha arriba y abajo. A\u00f1ade este c\u00f3digo a tu m\u00e9todo Update existente:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">procedure TViewMain.Update(const SecondsPassed: Single; var HandleInput: Boolean);\nbegin\n  ... \/\/ keep existing code\n  if Container.Pressed[keyArrowLeft] then\n    ForceAngle := ForceAngle - SecondsPassed * AngleAChangeSpeed;\n  if Container.Pressed[keyArrowRight] then\n    ForceAngle := ForceAngle + SecondsPassed * AngleAChangeSpeed;\n  if Container.Pressed[keyArrowUp] then\n    ForceStrength := Min(MaxStrength, ForceStrength + SecondsPassed * StrengthChangeSpeed);\n  if Container.Pressed[keyArrowDown] then\n    ForceStrength := Max(MinStrength, ForceStrength - SecondsPassed * StrengthChangeSpeed);\n\n  TransformForceAngle.Rotation := Vector4(1, 0, 0, ForceAngle);\n  TransformForceStrength.Scale := Vector3(1,\n    MapRange(ForceStrength, MinStrength, MaxStrength, MinStrengthScale, MaxStrengthScale),\n    1);\nend;<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">\u00a1Lanza esa pieza de ajedrez!<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\u00abParece que tenemos todo el conocimiento que necesitamos.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Sabemos c\u00f3mo lanzar la pieza de ajedrez,<\/li>\n\n\n\n<li>Sabemos qu\u00e9 pieza de ajedrez lanzar,<\/li>\n\n\n\n<li>Conocemos la direcci\u00f3n y la fuerza del lanzamiento.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Puedes consultar el c\u00f3digo que hicimos algunas secciones antes, en el ejercicio &#8216;Push the chess piece using physics&#8217;. Nuestro nuevo c\u00f3digo ser\u00e1 similar. Agr\u00e9galo a la implementaci\u00f3n del m\u00e9todo Press:\u00bb<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">function TViewMain.Press(const Event: TInputPressRelease): Boolean;\nvar\n  ... \/\/ keep existing variables used by other inputs\n  ChessPieceSelectedScene: TCastleScene;\n  ForceDirection: TVector3;\nbegin\n  Result := inherited;\n  if Result then Exit; \/\/ allow the ancestor to handle keys\n\n  ... \/\/ conserva el c\u00f3digo anterior que gestiona las entradas\n\n  if Event.IsKey(keyEnter) and (ChessPieceSelected &lt;&gt; nil) then\n  begin\n    ChessPieceSelectedScene := ChessPieceSelected.Parent as TCastleScene;\n    MyBody := ChessPieceSelectedScene.FindBehavior(TCastleRigidBody) as TCastleRigidBody;\n    ForceDirection := RotatePointAroundAxis(\n      Vector4(0, 1, 0, ForceAngle), Vector3(-1, 0, 0));\n    MyBody.ApplyImpulse(\n      ForceDirection * ForceStrength,\n      ChessPieceSelectedScene.WorldTranslation);\n    \/\/ unselect after flicking; not strictly necessary, but looks better\n    ChessPieceSelected := nil;\n    DesignForceGizmo.Exists := false;\n    Exit(true); \/\/ entrada gestionada\n  end;\nend;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">\u00abDependiendo de c\u00f3mo hayas dise\u00f1ado el dise\u00f1o force_gizmo.castle-transform, es posible que necesites ajustar el c\u00e1lculo de ForceDirection, en particular el segundo par\u00e1metro de RotatePointAroundAxis que es la direcci\u00f3n utilizada cuando el \u00e1ngulo es cero. No hay nada m\u00e1gico en nuestro valor Vector3(-1, 0, 0), simplemente sigue el dise\u00f1o de nuestro force_gizmo.castle-transform.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u00a1Ejecuta el juego y verifica que ahora puedes lanzar las piezas de ajedrez!<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Selecciona la pieza de ajedrez haciendo clic con el rat\u00f3n.<\/li>\n\n\n\n<li>Rota la fuerza con las teclas de flecha izquierda y derecha.<\/li>\n\n\n\n<li>Cambia la fuerza con las teclas de flecha arriba y abajo.<\/li>\n\n\n\n<li>Lanza la pieza de ajedrez presionando Enter.<\/li>\n\n\n\n<li>\u00a1Repite :)\u00bb<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"609\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/game_4-1024x609.png\" alt=\"\" class=\"wp-image-808\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/game_4-1024x609.png 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/game_4-300x178.png 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/game_4-768x457.png 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/game_4-1536x913.png 1536w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/game_4.png 1564w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\"><strong>Conclusi\u00f3n e ideas para el futuro<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\u00a1Invita a un amigo a jugar contigo! Hagan turnos usando el mouse para lanzar sus piezas de ajedrez y divi\u00e9rtanse \ud83d\ude42<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Estoy seguro de que ahora puedes inventar m\u00faltiples formas de hacer esto a\u00fan mejor.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u00bfQuiz\u00e1s cada jugador deber\u00eda poder lanzar solo sus propias piezas de ajedrez? Ya sabemos qu\u00e9 pieza de ajedrez es negra o blanca (el campo booleano Black en TChessPieceBehavior), aunque no lo usamos para nada anteriormente. Debes rastrear qu\u00e9 jugador lanz\u00f3 el objeto por \u00faltima vez (negro o blanco) y solo permitir elegir al lado opuesto la pr\u00f3xima vez.<\/li>\n\n\n\n<li>\u00bfQuiz\u00e1s quieras mostrar alguna interfaz de usuario, como una etiqueta, para indicar de qui\u00e9n es el turno? Simplemente coloca un componente TCastleLabel en la vista y cambia la leyenda cuando lo desees.<\/li>\n\n\n\n<li>\u00bfQuiz\u00e1s quieras mostrar el \u00e1ngulo y la fuerza actuales\u2009\u2014\u2009ya sea como n\u00fameros o como barras de colores? Usa TCastleRectangleColor para un rect\u00e1ngulo trivial con borde opcional y opcionalmente relleno de un color.<\/li>\n\n\n\n<li>\u00bfQuiz\u00e1s quieras implementar un juego de ajedrez real? Claro, simplemente sigue en el c\u00f3digo todas las piezas de ajedrez y las casillas del tablero de ajedrez\u2009\u2014\u2009qu\u00e9 est\u00e1 donde. Luego agrega una l\u00f3gica que permita al jugador seleccionar qu\u00e9 pieza y d\u00f3nde mover. Agrega alguna validaci\u00f3n. Agrega juego con un oponente inform\u00e1tico si lo deseas\u2009\u2014\u2009existen protocolos estandarizados para comunicarse con \u00abmotores de ajedrez\u00bb, por lo que no necesitas implementar tu propia inteligencia artificial de ajedrez desde cero.<\/li>\n\n\n\n<li>\u00bfQuiz\u00e1s quieras usar redes? Puedes usar varias soluciones de redes (cualquier biblioteca Pascal) junto con Castle Game Engine. Consulta <a href=\"https:\/\/castle-engine.io\/manual_network.php\">https:\/\/castle-engine.io\/manual_network.php<\/a>. Hemos utilizado el motor con Indy y RNL (Realtime Network Library). En el futuro, planeamos integrar el motor con Nakama, un marco de servidor y cliente de c\u00f3digo abierto para juegos multijugador.<\/li>\n\n\n\n<li>\u00bfQuiz\u00e1s quieras implementar este juego en otras plataformas, en particular en m\u00f3viles? Adelante. El c\u00f3digo que escribimos anteriormente ya es multiplataforma y se puede compilar con Castle Game Engine para cualquier dispositivo Android o iOS. Nuestra herramienta de compilaci\u00f3n hace todo por ti, obtienes un archivo APK, AAB o IPA listo para instalar en tu tel\u00e9fono. Consulta la documentaci\u00f3n del motor en <a href=\"https:\/\/castle-engine.io\/manual_cross_platform.php\">https:\/\/castle-engine.io\/manual_cross_platform.php<\/a>.<\/li>\n\n\n\n<li>Aunque los controles de teclado no funcionar\u00e1n en m\u00f3viles. Necesitas inventar e implementar una nueva interfaz de usuario para girar la fuerza, cambiar la fuerza y lanzar realmente la pieza de ajedrez. Lo m\u00e1s sencillo es mostrar botones clicables para realizar las acciones relevantes. La clase TCastleButton del motor es un bot\u00f3n con una apariencia completamente personalizable.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Si deseas aprender m\u00e1s sobre el motor, lee la documentaci\u00f3n en https:\/\/castle-engine.io\/ y \u00fanete a nuestra comunidad en el foro y Discord:<a href=\" https:\/\/castle-engine.io\/talk.php\"> https:\/\/castle-engine.io\/talk.php<\/a>. Por \u00faltimo, pero no menos importante, si te gusta este art\u00edculo y el motor, apreciaremos tu apoyo en Patreon <a href=\"https:\/\/www.patreon.com\/castleengine\">https:\/\/www.patreon.com\/castleengine<\/a>. Realmente contamos con tu apoyo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Finalmente, sobre todo, \u00a1divi\u00e9rtete! Crear juegos es un proceso emocionante y experimentar con la sensaci\u00f3n de \u00ablo que se siente bien\u00bb es la forma correcta de hacerlo. \u00a1Espero que lo disfrutes!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Bienvenido a la segunda parte del art\u00edculo sobre c\u00f3mo crear un juego sencillo de f\u00edsica en 3D utilizando Castle Game Engine.<\/p>\n<p>Castle Game Engine es un motor de juego 3D y 2D multiplataforma (escritorio, m\u00f3vil, consolas) que utiliza Pascal moderno. Es gratuito, de c\u00f3digo abierto y compatible con FPC y Delphi.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[57,61,27],"tags":[49,22,32,23,21],"class_list":["post-760","post","type-post","status-publish","format-standard","hentry","category-castle-game-engine","category-free-pascal","category-lazarus","tag-castle-game-engine","tag-delphi","tag-free-pascal","tag-lazarus","tag-pascal"],"_links":{"self":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/760","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=760"}],"version-history":[{"count":35,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/760\/revisions"}],"predecessor-version":[{"id":825,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/760\/revisions\/825"}],"wp:attachment":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=760"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=760"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=760"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}