{"id":710,"date":"2024-06-16T22:15:02","date_gmt":"2024-06-16T21:15:02","guid":{"rendered":"https:\/\/jorgeturiel.es\/?p=710"},"modified":"2024-07-15T10:30:36","modified_gmt":"2024-07-15T09:30:36","slug":"castle-game-engine-traslacion-y-rotacion","status":"publish","type":"post","link":"https:\/\/jorgeturiel.es\/?p=710","title":{"rendered":"Castle Game Engine. Traslaci\u00f3n y rotaci\u00f3n"},"content":{"rendered":"\n<p>En esta entrada aprenderemos a aplicar traslaciones objetos y rotaciones, no solo desde en entorno de Castle Game Engine, sino que lo haremos desde c\u00f3digo.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Preparando la escena.<\/h2>\n\n\n\n<p>Vamos a preparar una escena en tres dimensiones. Si tienes dudas de como empezar con Castle Game Engine, puede visitar esta <a href=\"https:\/\/jorgeturiel.es\/?p=623\">entrada del blog<\/a>.<\/p>\n\n\n\n<p>Crea una escena 3D, y a\u00f1ade un rect\u00e1ngulo en el centro, modifica las dimensiones del rect\u00e1ngulo para su tama\u00f1o en X sea igual a uno, en Y sea igual a siete y en Z sea igual a uno.<\/p>\n\n\n\n<p>Ahora modifica su posici\u00f3n, para ello cambia la propiedad <em>translation <\/em>del rect\u00e1ngulo que acabas de crear. Y ajusta su valor Y a tres y medio.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"487\" height=\"517\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/Captura-de-pantalla-2024-06-02-220315.png\" alt=\"\" class=\"wp-image-715\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/Captura-de-pantalla-2024-06-02-220315.png 487w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/Captura-de-pantalla-2024-06-02-220315-283x300.png 283w\" sizes=\"auto, (max-width: 487px) 100vw, 487px\" \/><figcaption class=\"wp-element-caption\">Ajustes de Box1<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Acabas de realizar tu primera traslaci\u00f3n. Pero lo interesante ser\u00eda realizar desde c\u00f3digo, respondiendo a la pulsaci\u00f3n de unas teclas.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Usando los componentes en el c\u00f3digo<\/h2>\n\n\n\n<p>Para ello, lo primero es a\u00f1adir el rect\u00e1ngulo al c\u00f3digo. Abre el editor de c\u00f3digo pulsando F12, y a\u00f1ade la clausula <em>CastleScene<\/em> en la secci\u00f3n uses. Y el en la secci\u00f3n <em>published<\/em> a\u00f1ade una variable llamada Box1, del tipo TCastleBox<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >uses Classes,\n  CastleVectors, CastleComponentSerialize,\n  CastleUIControls, CastleControls, CastleKeysMouse, CastleScene, CastleLog,\n  CastleWindow;\n  \n  { Main view, where most of the application logic takes place. }  \n  TViewMain = class(TCastleView)\n  private\n\tOrigen: TVector3;\n\tCentro: TVector3;\n\tRotacion: TVector4;\n  published\n  { Components designed using CGE editor.&lt;\n    These fields will be automatically initialized at Start. }\n\tLabelFps: TCastleLabel;\n    Box1: TCastleBox;    \/\/a\u00f1adimos variable tipo TcastleBox\n\t(...)<\/pre><\/div>\n\n\n\n<p>El siguiente paso es asignar el rect\u00e1ngulo que tenemos en el editor, a la variable Box1, que acabamos de crear. Esto se hace en el procedimiento <em>Start<\/em>, tal como se muestra en el c\u00f3digo m\u00e1s abajo<sup data-fn=\"0788bbf8-ab19-421a-9726-ccd22e596612\" class=\"fn\"><a href=\"#0788bbf8-ab19-421a-9726-ccd22e596612\" id=\"0788bbf8-ab19-421a-9726-ccd22e596612-link\">1<\/a><\/sup>.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \" >procedure TViewMain.Start;\nbegin\n  inherited;\n  {En algunos casos no es necesario, ver comentario de \n  Michail al final de la entrada   \n  Box1 := DesignedComponent('Box1') as TCastleBox;\n  }\n  end;<\/pre><\/div>\n\n\n\n<p>Observa, que la variable que creamos anteriormente, le asignamos un el componente <em>Box1<\/em> (que es como se llama en el editor), y le indicamos que es de tipo <em>TCastleBox<\/em>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Traslaciones por c\u00f3digo<\/h2>\n\n\n\n<p>Ahora, solo tenemos que ir al procedimiento <em>Press, <\/em>y a\u00f1adir el el siguiente 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;\nvar\n  posicion: TVector3;\nbegin\n  Result := inherited;\n  if Result then Exit; \/\/ allow the ancestor to handle keys\n\n  { This virtual method is executed when user presses\n    a key, a mouse button, or touches a touch-screen.\n\n    Note that each UI control has also events like OnPress and OnClick.\n    These events can be used to handle the \"press\", if it should do something\n    specific when used in that UI control.\n    The TViewMain.Press method should be used to handle keys\n    not handled in children controls.\n  }\n\n  \/\/ Use this to handle keys:\n\n  if Event.IsKey(keyL) then\n  begin\n    Box1.Translation := Box1.Translation + Vector3(0.5, 0, 0);\n    Exit(True);\n  end;\n\n  if Event.IsKey(keyj) then\n  begin\n    Box1.Translation := Box1.Translation + Vector3(-0.5, 0, 0);\n    Exit(True);\n  end;\n\nend;                 <\/pre><\/div>\n\n\n\n<p>Observa, que para desplazar el rect\u00e1ngulo, simplemente sumamos un nuevo vector a su propiedad <em>Translation<\/em>. El motivo de sumar un vector, es que los objetos est\u00e1 situados en el espacio, y tiene tres coordenadas. En este caso se le suma 0.5 unidades en la coordenada X.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Rotaciones por c\u00f3digo.<\/h2>\n\n\n\n<p>Ahora, podemos aplicar una rotaci\u00f3n, podemos hacer los mismo que con la traslaci\u00f3n, sumar a la rotaci\u00f3n actual una nueva rotaci\u00f3n, pero ello usaremos la propiedad <em>Rotation<\/em>. Observa este c\u00f3digo.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \" >box1.Rotation := Box1.Rotation + Vector4(0, 0, 1, -DegToRad(1));<\/pre><\/div>\n\n\n\n<p>En este caso, la rotaci\u00f3n se expresa por un vector de cuatro componentes. Los tres primeros indican los ejes a los que se le aplica la rotaci\u00f3n. Si el valor de un eje determinada es uno, se le aplicar\u00e1 una rotaci\u00f3n, cuyo valor es indicado en el \u00faltimo componente del vector. Este valor es indicado en radianes. Como es m\u00e1s c\u00f3modo o intuitivo trabajar con grados, el valor es convertido de grados a radianes.<\/p>\n\n\n\n<p>La rotaci\u00f3n de un elemento se produce desde d\u00f3nde est\u00e1 su centro. Observa el rect\u00e1ngulo en el editor. En esta imagen se puede ver el punto de rotaci\u00f3n, indicado por un eje de coordenadas.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"670\" height=\"565\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/Captura-de-pantalla-2024-06-02-223027.png\" alt=\"\" class=\"wp-image-717\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/Captura-de-pantalla-2024-06-02-223027.png 670w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2024\/06\/Captura-de-pantalla-2024-06-02-223027-300x253.png 300w\" sizes=\"auto, (max-width: 670px) 100vw, 670px\" \/><\/figure>\n<\/div>\n\n\n<p>Si deseamos que la rotaci\u00f3n se realice desde otro punto diferente, debemos desplazar el el centro del objeto a d\u00f3nde nos interese. En el este ejemplo, la rotaci\u00f3n del rect\u00e1ngulo se produce desde su punto de apoyo.<\/p>\n\n\n\n<p>Observa el v\u00eddeo.<\/p>\n\n\n\n<figure class=\"wp-block-embed aligncenter is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Rotaciones y traslaciones en Castle Game Engine\" width=\"640\" height=\"360\" src=\"https:\/\/www.youtube.com\/embed\/0iEZCpmPv5Y?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<p>Aqu\u00ed tiene el c\u00f3digo fuente con alg\u00fan detalle m\u00e1s. Si se pulsa la tecla retroceso, el rect\u00e1ngulo vuelve a su origen. As\u00ed mismo si se pulsa la tecla escape se termina la aplicaci\u00f3n.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \" >{ Main view, where most of the application logic takes place.\n\n  Feel free to use this code as a starting point for your own projects.\n  This template code is in public domain, unlike most other CGE code which\n  is covered by BSD or LGPL (see https:\/\/castle-engine.io\/license). }\nunit GameViewMain;\n\ninterface\n\nuses Classes,\n  CastleVectors, CastleComponentSerialize,\n  CastleUIControls, CastleControls, CastleKeysMouse, CastleScene, CastleLog,\n  CastleWindow;\n\ntype\n  { Main view, where most of the application logic takes place. }\n  TViewMain = class(TCastleView)\n  private\n    Origen: TVector3;\n    Centro: TVector3;\n    Rotacion: TVector4;\n  published\n    { Components designed using CGE editor.\n      These fields will be automatically initialized at Start. }\n    LabelFps: TCastleLabel;\n    Box1: TCastleBox;\n\n  public\n    constructor Create(AOwner: TComponent); override;\n    procedure Start; override;\n    procedure Update(const SecondsPassed: single; var HandleInput: boolean); override;\n    function Press(const Event: TInputPressRelease): boolean; override;\n  end;\n\nvar\n  ViewMain: TViewMain;\n\nimplementation\n\nuses SysUtils, Math;\n\n  { TViewMain ----------------------------------------------------------------- }\n\nconstructor TViewMain.Create(AOwner: TComponent);\nbegin\n  inherited;\n  DesignUrl := 'castle-data:\/gameviewmain.castle-user-interface';\nend;\n\nprocedure TViewMain.Start;\nbegin\n  inherited;\n  Box1 := DesignedComponent('Box1') as TCastleBox;\n  Origen := Box1.Translation;\n  Rotacion := Box1.Rotation;\n  Box1.Center := Vector3(0, -Box1.Size.Y \/ 2, 0);\nend;\n\nprocedure TViewMain.Update(const SecondsPassed: single; var HandleInput: boolean);\nbegin\n  inherited;\n  { This virtual method is executed every frame (many times per second). }\n  Assert(LabelFps &lt;&gt; nil,\n    'If you remove LabelFps from the design, remember to remove also the assignment \"LabelFps.Caption := ...\" from code');\n  LabelFps.Caption := 'FPS: ' + Container.Fps.ToString;\nend;\n\nfunction TViewMain.Press(const Event: TInputPressRelease): boolean;\nvar\n  posicion: TVector3;\nbegin\n  Result := inherited;\n  if Result then Exit; \/\/ allow the ancestor to handle keys\n\n  { This virtual method is executed when user presses\n    a key, a mouse button, or touches a touch-screen.\n\n    Note that each UI control has also events like OnPress and OnClick.\n    These events can be used to handle the \"press\", if it should do something\n    specific when used in that UI control.\n    The TViewMain.Press method should be used to handle keys\n    not handled in children controls.\n  }\n\n  \/\/ Use this to handle keys:\n\n  if Event.IsKey(keyL) then\n  begin\n    Box1.Translation := Box1.Translation + Vector3(0.5, 0, 0);\n    Exit(True);\n  end;\n\n  if Event.IsKey(keyj) then\n  begin\n    Box1.Translation := Box1.Translation + Vector3(-0.5, 0, 0);\n    Exit(True);\n  end;\n\n  if Event.IsKey(keyBackSpace) then\n  begin\n    Box1.Translation := Origen;\n    Box1.Rotation := Vector4(0, 0, 0, 1);\n    Exit(True);\n  end;\n\n  if Event.IsKey(keyA) then\n  begin\n\n    if box1.Rotation.W &lt;= 0 then\n    begin\n      Box1.Center := Vector3(box1.Size.x \/ 2, -Box1.Size.Y \/ 2, 0);\n    end\n    else\n    begin\n      Box1.Center := Vector3(-box1.Size.x \/ 2, -Box1.Size.Y \/ 2, 0);\n    end;\n\n    box1.Rotation := Box1.Rotation + Vector4(0, 0, 1, DegToRad(1));\n    WritelnLog('Box1', Box1.Rotation.ToString);\n    WritelnLog('Center', Box1.Center.ToString);\n\n\n    Exit(True);\n  end;\n  if Event.IsKey(keyD) then\n  begin\n    if box1.Rotation.W &lt;= 0 then\n    begin\n      Box1.Center := Vector3(box1.Size.x \/ 2, -Box1.Size.Y \/ 2, 0);\n    end\n    else\n    begin\n      Box1.Center := Vector3(-box1.Size.x \/ 2, -Box1.Size.Y \/ 2, 0);\n    end;\n    box1.Rotation := Box1.Rotation + Vector4(0, 0, 1, -DegToRad(1));\n    WritelnLog('Box1', Box1.Rotation.ToString);\n    WritelnLog('Center', Box1.Center.ToString);\n    Exit(True);\n  end;\n  if Event.IsKey(keyEscape) then\n  begin\n    Application.Terminate;\n    Exit(true);\n  end;\nend;\n\nend.<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusiones.<\/h2>\n\n\n\n<p>En esta entrada hemos visto:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>C\u00f3mo usar los objetos definidos en el editor desde c\u00f3digo.<\/li>\n\n\n\n<li>C\u00f3mo trasladar objetos desde c\u00f3digo.<\/li>\n\n\n\n<li>C\u00f3mo rotar objetos desde c\u00f3digo.<\/li>\n<\/ul>\n\n\n\n<p>Saludos<\/p>\n\n\n<ol class=\"wp-block-footnotes\"><li id=\"0788bbf8-ab19-421a-9726-ccd22e596612\">Editada la entrada. No siempre es necesario realizar este paso. Seg\u00fan el comentario Michalis, para m\u00e1s informaci\u00f3n visitar: <a href=\"https:\/\/castle-engine.io\/wp\/2022\/10\/16\/published-state-fields-are-now-automatically-initialized-no-need-in-most-cases-for-designedcomponent-calls\/ .\">https:\/\/castle-engine.io\/wp\/2022\/10\/16\/published-state-fields-are-now-automatically-initialized-no-need-in-most-cases-for-designedcomponent-calls\/ <\/a> <a href=\"#0788bbf8-ab19-421a-9726-ccd22e596612-link\" aria-label=\"Saltar a la referencia de la nota 1\">\u21a9\ufe0e<\/a><\/li><\/ol>","protected":false},"excerpt":{"rendered":"<p>En esta entrada aprenderemos a aplicar traslaciones objetos y rotaciones, no solo desde en entorno de Castle Game Engine, sino que lo haremos desde c\u00f3digo.<\/p>\n","protected":false},"author":2,"featured_media":712,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"[{\"content\":\"Editada la entrada. No siempre es necesario realizar este paso. Seg\u00fan el comentario Michalis, para m\u00e1s informaci\u00f3n visitar: <a href=\\\"https:\/\/castle-engine.io\/wp\/2022\/10\/16\/published-state-fields-are-now-automatically-initialized-no-need-in-most-cases-for-designedcomponent-calls\/ .\\\">https:\/\/castle-engine.io\/wp\/2022\/10\/16\/published-state-fields-are-now-automatically-initialized-no-need-in-most-cases-for-designedcomponent-calls\/ <\/a>\",\"id\":\"0788bbf8-ab19-421a-9726-ccd22e596612\"}]"},"categories":[57,27,25],"tags":[49,32,23],"class_list":["post-710","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-castle-game-engine","category-lazarus","category-pascal","tag-castle-game-engine","tag-free-pascal","tag-lazarus"],"_links":{"self":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/710","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=710"}],"version-history":[{"count":17,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/710\/revisions"}],"predecessor-version":[{"id":838,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/710\/revisions\/838"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/media\/712"}],"wp:attachment":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=710"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=710"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=710"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}