{"id":1152,"date":"2025-11-16T08:00:00","date_gmt":"2025-11-16T07:00:00","guid":{"rendered":"https:\/\/jorgeturiel.es\/?p=1152"},"modified":"2025-11-12T10:04:42","modified_gmt":"2025-11-12T09:04:42","slug":"ghosts-n-goblins-y-cge-parte-4","status":"publish","type":"post","link":"https:\/\/jorgeturiel.es\/?p=1152","title":{"rendered":"Ghosts \u2018n Goblins y CGE. Parte 4"},"content":{"rendered":"\n<p>En esta nueva entrada haremos que Arthur dispare su arma. Para ello veremos como crear un objeto por c\u00f3digo, como gestionarlo, y como gestionar un temporizador.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p><br>Arthur tiene como modo de defensa la capacidad de lanzar espadas. Solo puede lanzar como m\u00e1ximo dos a la vez, y las espadas vuelan paralelas al suelo. Teniendo esto en cuenta vamos a continuar programando el juego e implementaremos esto.<\/p>\n\n\n\n<p>Copia el archivo spear.png dentro de la carpeta sprites, Crea una nueva hoja de sprites y a\u00f1ade el archivo que acabas de copiar. Crea 4 animaciones, cada una con de la im\u00e1genes.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"633\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2025\/11\/image-1024x633.png\" alt=\"\" class=\"wp-image-1153\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2025\/11\/image-1024x633.png 1024w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2025\/11\/image-300x185.png 300w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2025\/11\/image-768x474.png 768w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2025\/11\/image.png 1049w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Crear animaciones del arma<\/figcaption><\/figure>\n<\/div>\n\n\n<p><br>C\u00f3mo el arma ser\u00e1 un elemento que aparecer\u00e1 en el juego por momentos y luego desparece, vamos a crearlo por c\u00f3digo.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Creaci\u00f3n del arma por c\u00f3digo.<\/h2>\n\n\n\n<p>En la secci\u00f3n <em>private<\/em> a\u00f1ade dos elementos <em>TcastleScene<\/em>. A\u00f1adimos dos elementos, porque uno sera el arma, y el otro ser\u00e1 el arma rotada 180. Para poder tener un elemento para cada direcci\u00f3n de disparo<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"545\" height=\"168\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2025\/11\/image-1.png\" alt=\"\" class=\"wp-image-1155\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2025\/11\/image-1.png 545w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2025\/11\/image-1-300x92.png 300w\" sizes=\"auto, (max-width: 545px) 100vw, 545px\" \/><figcaption class=\"wp-element-caption\">Sprites de las armas<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Siguiendo con la idea de tener lo m\u00e1s ordenado posible el c\u00f3digo crearemos un procedimiento d\u00f3nde escribiremos el c\u00f3digo necesario para inicializar las armas.<\/p>\n\n\n\n<p>En la secci\u00f3n <em>Private<\/em>, crea un procedimiento llamado <em>ConfigureWeaponSpriteScene,<\/em> puedes pulsar <em>control+shift+c <\/em>para que Lazarus cree el cuerpo del procedimiento autom\u00e1ticamente.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"606\" height=\"57\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2025\/11\/image-2.png\" alt=\"\" class=\"wp-image-1157\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2025\/11\/image-2.png 606w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2025\/11\/image-2-300x28.png 300w\" sizes=\"auto, (max-width: 606px) 100vw, 606px\" \/><figcaption class=\"wp-element-caption\">Procedimiento de configuraci\u00f3n Sprites<\/figcaption><\/figure>\n<\/div>\n\n\n<p>En el procedimiento escribimos el siguiente c\u00f3digo.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">procedure TViewMain.ConfigureWeaponSpriteScene;\nbegin\n  WeaponSpriteScene := TCastleScene.Create(FreeAtStop);\n  WeaponSpriteScene.Url := 'castle-data:\/sprites\/spear.castle-sprite-sheet';\n  WeaponSpriteScene.AutoAnimation := 'Spear1';\n  WeaponSpriteScene.Scale := Vector3(1, 1, 1);\n\n  WeaponSpriteSceneRotate := TCastleScene.Create(FreeAtStop);\n  WeaponSpriteSceneRotate.Url := 'castle-data:\/sprites\/spear.castle-sprite-sheet';\n  WeaponSpriteSceneRotate.AutoAnimation := 'Spear1';\n  WeaponSpriteSceneRotate.Scale := Vector3(1, 1, 1);\n  WeaponSpriteSceneRotate.Rotation := Vector4(0, 1, 0, Deg(180));\n\nend;        <\/pre><\/div>\n\n\n\n<p>B\u00e1sicamente lo hace este c\u00f3digo, es crear los elemento que hemos declarado en la secci\u00f3n <em>Private<\/em>. Es importante que al crearlo le indiquemos el par\u00e1metro <em>FreeAtStop<\/em> de esta manera el motor gr\u00e1fico ser\u00e1 el encargado de liberar de la memoria el objeto cuando le indiquemos que ya no lo usaremos m\u00e1s.<\/p>\n\n\n\n<p>La siguiente l\u00ednea le asignamos la hoja de sprites que debe cargar. Despu\u00e9s le indicamos que animaci\u00f3n debe ejecutar, y por \u00faltimo le indicamos que su lo represente a una escala 1,1,1. Esto es que su tama\u00f1o original.<\/p>\n\n\n\n<p>Estas tres l\u00edneas son iguales, tanto para una arma como para su \u201chomologa\u201d rotada. Pero el arma que usaremos rotada, debemos indicarle que la rote. Esto se hace indicando una rotaci\u00f3n, de la misma manera que hicimos con el personaje del juego.<\/p>\n\n\n\n<p>Por \u00faltimo debemos llamar a este procedimiento desde el procedimiento <em>Start<\/em>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"619\" height=\"340\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2025\/11\/image-3.png\" alt=\"\" class=\"wp-image-1160\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2025\/11\/image-3.png 619w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2025\/11\/image-3-300x165.png 300w\" sizes=\"auto, (max-width: 619px) 100vw, 619px\" \/><figcaption class=\"wp-element-caption\">Declaraci\u00f3n ConfigureWeaponsSpriteScene<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Para cumplir el resto de las condiciones que se comentaron antes, debemos definir las siguientes variables y temporizador, las cuales las declararemos en la secci\u00f3n <em>private<\/em><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"641\" height=\"128\" src=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2025\/11\/image-4.png\" alt=\"\" class=\"wp-image-1161\" srcset=\"https:\/\/jorgeturiel.es\/wp-content\/uploads\/2025\/11\/image-4.png 641w, https:\/\/jorgeturiel.es\/wp-content\/uploads\/2025\/11\/image-4-300x60.png 300w\" sizes=\"auto, (max-width: 641px) 100vw, 641px\" \/><figcaption class=\"wp-element-caption\">Variables para gesti\u00f3n disparo<\/figcaption><\/figure>\n<\/div>\n\n\n<p>La variable <em>CanShot(1)<\/em>, la usaremos para indicar si se puede disparar. En el caso, por ejemplo, de que ya haya dos espadas en el escenario, esta variable se valdr\u00e1 falso.<\/p>\n\n\n\n<p>La variable, TimerShot(2), es un temporizador, el cual lo usaremos para temporizar el lanzamiento. Para que el jugador no pulse la tecla de disparo y se disparen m\u00faltiples espadas.<\/p>\n\n\n\n<p>Cuando lanzamos una espada, realizamos diversas operaciones, crear el sprite, etc. Para saber que estamos haciendo \u201cla preparaci\u00f3n\u201d lo indicamos con la variable<em> Shotting(3)<\/em>.<\/p>\n\n\n\n<p>La variable<em> NumeroDisparos(4)<\/em>, indica cuantas espadas est\u00e1n actualmente en el escenario.<\/p>\n\n\n\n<p>Por \u00faltimo, el procedimiento <em>OnTimerShot(5)<\/em> es un procedimiento que se ser\u00e1 llamado cada vez que se cumpla el tiempo que especificamos en el temporizador. No es necesario que lo escribas ahora esta l\u00ednea, ya que cuando inicialicemos el temporizador, Lazarus lo crear\u00e1 por nosotros<\/p>\n\n\n\n<p>En procedimiento <em>Onstart<\/em>, debemos inicializar todas estas variables, y preparar el temporizador<\/p>\n\n\n\n<p>El siguiente c\u00f3digo se encarga de ello:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">TimerShot := TCastleTimer.Create(FreeAtStop);\n  {$IFDEF FPC}\n  TimerShot.OnTimer:=@OnTimerShot;\n  {$ELSE}\n  TimerShot.OnTimer := OnTimerShot;\n  {$ENDIF}\n  TimerShot.IntervalSeconds := 1;\n  CanShot := True;\n  shotting := False;\n  InsertBack(TimerShot);\n  NumeroDisparos := 0;  <\/pre><\/div>\n\n\n\n<p>Lo primero es crear el temporizador, que es un objeto de tipo <em>TcastleTimer.<\/em><\/p>\n\n\n\n<p>Le asignamos el evento <em>OnTimer<\/em>, el cual se ejecutar\u00e1 cada vez que el temporizador alcance el valor establecido. Recuerda que tras escribir la l\u00ednea, su pulsas <em>Ctrl+shift+C<\/em>, lazarus crear\u00e1 el procedimiento asociado, as\u00ed como su declaraci\u00f3n.<\/p>\n\n\n\n<p>Asignamos a la propiedad <em>InvervalSeconds, <\/em>el valor 1 que ser\u00e1 el intervalo en segundos de nuestro temporizador.<\/p>\n\n\n\n<p>Asignamos las variables booleanas a su estado inicial. Enviamos el temporizador \u201cal fondo\u201d para \u201ccongelarlo\u201d. Por \u00faltimo inicializamos la variable <em>NumeroDisparos<\/em> a cero.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Disparando<\/h2>\n\n\n\n<p>Con estas l\u00edneas , al iniciar el juego, tendremos todo preparado para empezar a disparar<\/p>\n\n\n\n<p>El siguiente paso es modificar la funci\u00f3n <em>FireWeapon<\/em><\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">function TViewMain.FireWeapon: boolean;\nbegin\n  Result := False;\n  if (Container.Pressed[keySpace]) and (CanShot = True) and (NumeroDisparos &lt;= 2) then\n  begin\n    Result := True;\n    StarTimerShot;\n  end;\nend; <\/pre><\/div>\n\n\n\n<p>Modificamos la instrucci\u00f3n <em>IF<\/em>, de manera que tenga en cuenta la variable <em>CanShot <\/em>sea igual a<em> TRUE<\/em> y <em>N\u00fameroDisparos<\/em> sea menor igual a 2. Adem\u00e1s llamamos al procedimiento <em>StartTimerShot<\/em>, el cual se encarga de iniciar el temporizador.<\/p>\n\n\n\n<p>Crea el procedimiento <em>StartTime<\/em><em><u>Shot<\/u><\/em>, en la secci\u00f3n <em>Private<\/em>, y escribe el siguiente c\u00f3digo dentro de ella.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">procedure TViewMain.StarTimerShot;\nbegin\n  CanShot := True;\n  InsertFrontIfNotExists(TimerShot);\nend; <\/pre><\/div>\n\n\n\n<p>Este procedimiento cambia la variable <em>CanShot<\/em> a <em>TRUE <\/em>y trae \u201cal frente\u201d el temporizador, con lo cual empieza a contar.<\/p>\n\n\n\n<p>En el procedimiento <em>Update<\/em>, gestionaremos si la funci\u00f3n <em>FireWeapon<\/em> devuelve <em>TRUE<\/em>. En tal caso debemos lanzar una espada.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">if FireWeapon then\n  begin\n    if shotting = False then\n    begin\n      TimerShot.ResetNextTimerEvent;\n      shotting := True;\n      NumeroDisparos := NumeroDisparos + 1;      \n      if Arthur.Rotation.W = 0 then\n      begin\n        VectorDireccion := Vector3(1, 0, 0);\n      end\n      else\n      begin\n        VectorDireccion := Vector3(-1, 0, 0);\n      end;\n      Shot(Arthur, Arthur.LocalToWorld(Vector3(Arthur.BoundingBox.SizeX \/ 2 + 5, 0, 0)),\n        VectorDireccion);\n      CanShot := False;\n      shotting := False;\n    end;\n  end; <\/pre><\/div>\n\n\n\n<p>Usaremos la variable, declarada en la secci\u00f3n <em>Private<\/em>, shotting la cual nos indicar\u00e1 si estamos lanzado la espada. En el caso que no sea as\u00ed, reiniciamos el temporizador para asegurar que empieza a contar desde cero. Ponemos la variable <em>Shotting<\/em> a <em>TRUE<\/em>, incrementamos el contador de n\u00famero de disparos. Y dependiendo hac\u00eda donde est\u00e9 mirando el personaje, creamos un vector de direcci\u00f3n paralelo al eje X. El sentido de este vector est\u00e1 indicado por el signo de su valor en X.<\/p>\n\n\n\n<p>Llamamos al procedimiento Shot (ahora entro en detalles sobre este procedimiento), ya por \u00faltimo indicamos que no se puede disparar cambiando a <em>FALSE<\/em> y cambiamos la variable <em>Shotting<\/em> a <em>FALSE<\/em> para indicar que hemos terminado el proceso de disparo.<\/p>\n\n\n\n<p>La variable <em>CanShot<\/em> cambiar\u00e1 a <em>TRUE<\/em>, cuando haya pasado el tiempo que establecimos en el temporizador. Para ello en el evento <em>OnTimerShot<\/em> que creamos antes, debemos escribir el siguiente c\u00f3digo.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">procedure TViewMain.OnTimerShot(Sender: Tobject);\nbegin\n  InsertBackIfNotExists(TimerShot);\n  CanShot := True;\nend;<\/pre><\/div>\n\n\n\n<p>En este procedimiento lo primero en \u201cenviar\u201d el temporizador a dormir. Y cambiamos la variable <em>CanShot<\/em> a <em>True.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Clase TWeapon<\/h2>\n\n\n\n<p>Este shot se encarga de realizar el disparo pero depende de la clase <em>Tweapon,<\/em> la cual ser\u00e1 el arma que disparamos y se encargar\u00e1 de desplazarla y calcular cuando debe desaparecer.<\/p>\n\n\n\n<p>La clase <em>Tweapon<\/em>, la debes declarar al principio de la unidad, justo debajo de d\u00f3nde declaraste la clase <em>TlevelBonus<\/em>.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">type\n\n  { TWeapon }\n\n  TWeapon = class(TCastleTransform)\n  strict private\n    FMaxDistance: Single;\n    FRBody: TCastleRigidBody;\n    FStartPoint: TVector2;\n  public\n    constructor Create(AOwner: TComponent; WeaponSpriteScene: TCastleScene); reintroduce;\n    procedure Update(const SecondsPassed: single; var RemoveMe: TRemoveType); override;\n    property RBody: TCastleRigidBody read FRBody;\n    property MaxDistance:Single read FMaxDistance write FMaxDistance;\n    property StartPoint: TVector2 read FStartPoint write FStartPoint;\n  end;                  \n<\/pre><\/div>\n\n\n\n<p>Esta clase desciende, o es hija, de <em>TcastleTransform.<\/em> Declaramos un constructor, con el argumento <em>Reintroduce<\/em>, as\u00ed podemos usar el m\u00e9todo <em>Create<\/em> que ha sido escondido por la clase padre, a\u00f1adiendo algunos argumentos m\u00e1s. En este m\u00e9todo recibe, adem\u00e1s del propietario (<em>Aowner<\/em>), que es obligatorio, un par\u00e1metro de tipo <em>TcastleScene<\/em>, que ser\u00e1 nuestra arma.<\/p>\n\n\n\n<p>Por otra parte declaramos el procedimiento <em>Update<\/em>, el cual ser\u00e1 llamada cada vez que se debe actualizar nuestra arma. Este m\u00e9todo es llamado autom\u00e1ticamente con el motor gr\u00e1fico, al ser un objeto de desciende de <em>TcastleTransform <\/em>hereda esta car\u00e1cteristica.<\/p>\n\n\n\n<p>La propiedad<em> Rbody<\/em>, es de tipo<em> TcastleRigiBody<\/em>, la cual contendr\u00e1 un<em> RigiiBody<\/em>, que es el objeto que gestionar\u00e1 las colisiones. Al igual que se lo hemos creado desde el editor de CGE, lo crearemos desde c\u00f3digo.<\/p>\n\n\n\n<p>La propiedad<em> MaxDistance<\/em>, la usaremos para almacenar la distancia m\u00e1xima que puede recorrer el arma, desde el punto de inicio, que se guarda en la propiedad<em> StartPoint<\/em>. Al ser un punto en 2D, esta ser\u00e1 un vector de tipo<em> TVector2 .<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Constructor<\/h3>\n\n\n\n<p>Veamos el c\u00f3digo del constructor<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">constructor TWeapon.Create(AOwner: TComponent; WeaponSpriteScene: TCastleScene);\nvar\n  col: TCastleBoxCollider;\nbegin\n  inherited Create(AOwner);\n\n  \/\/A\u00f1adir elemento a la escena\n  Add(WeaponSpriteScene);\n  WeaponSpriteScene.Visible := True;\n  WeaponSpriteScene.Translation := Vector3(0, 0, 1);\n  { En este caso, se a\u00f1ade TCastleRigidBody a TWeapon(TCastleTransform)\n    y no a WeaponSpriteScene para poder usar esta escena en varias armas\n  }\n  FRBody := TCastleRigidBody.Create(Self);\n  FRBody.Setup2D;\n  RBody.Dynamic := True;\n  RBody.CollisionDetection := cdContinuous;\n  RBody.MaxLinearVelocity := 0;\n  RBody.Layer := 3; \/\/Plano del protagonista\n  RBody.Gravity := False;\n  \/\/ Creamos el collider\n  col := TCastleBoxCollider.Create(Self);\n  col.Restitution := 0.0;\n  Col.Mass := 1;\n  AddBehavior(Col);\n  AddBehavior(FRBody);\nend; <\/pre><\/div>\n\n\n\n<p>Observa el c\u00f3digo y sus comentarios. Empezamos a\u00f1adiendo el arma, que hemos recibido por el par\u00e1metro <em>WeaponSpriteScene<\/em>, a la escena. Lo hacemos visible y lo situamos en el origen de coordenadas.<\/p>\n\n\n\n<p>Despu\u00e9s creamos el objeto <em>TcastleRigiBody<\/em>, ajustamos sus propiedades a un entorno 2D, su propiedad <em>Dinamic<\/em> la ponemos a True, para que su desplazamiento se gestionado por el motor de f\u00edsicas. La detecci\u00f3n de colisi\u00f3n (<em>CollisionDectection<\/em>) a continuo, la velocidad a cero, en el mismo plano del protagonista, e indicamos que no le afecte la gravedad.<\/p>\n\n\n\n<p>Ya por \u00faltimo, creamos el volumen de colisi\u00f3n o <em>collider<\/em>.<\/p>\n\n\n\n<p>Con todo esto listo, los a\u00f1adimos a \u201ccomportamientos\u201d de nuestro objeto.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Update<\/h3>\n\n\n\n<p>Por otra parte, tenemos el procedimiento <em>Update<\/em><\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">procedure TWeapon.Update(const SecondsPassed: single; var RemoveMe: TRemoveType);\nvar\n  Posicion: TVector2;\nbegin\n  inherited Update(SecondsPassed, RemoveMe);\n  Posicion := FStartPoint - Self.translationXY;\n  if (Abs(Posicion.x) &gt; FMaxDistance) then\n  begin\n    Self.Visible := False;\n    Self.Exists := False;\n    RemoveMe := rtRemoveAndFree;\n  end;\nend;    <\/pre><\/div>\n\n\n\n<p><br>En este procedimiento, comprobaremos si la posici\u00f3n actual, restada a la posici\u00f3n de inicio es mayor que <em>FmaxDistance<\/em>. En tal caso cambiamos las propiedades <em>Visible <\/em>y <em>Exists<\/em> a <em>False<\/em>. Y cambiando la variable <em>RemoveMe<\/em>, que hemos recibido como par\u00e1metro, al valor <em>rtRemoveAndFree<\/em>, indicamos al motor gr\u00e1fico que debe borrar este objeto. El motivo de cambiar las variables <em>Visible <\/em>y <em>Exists<\/em> a <em>False,<\/em> es para que mientras no se destruye, no se visible para jugador y al \u201cno existir\u201d no se tendr\u00e1 en cuenta para futuras colisiones<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Procedimiento Shot.<\/h2>\n\n\n\n<p>En este procedimiento crearemos un objeto <em>Tweapon<\/em>, y lo inicializamos con los datos que necesitamos.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">procedure TViewMain.Shot(WeaponOwner: TComponent; const Origen, Direccion: TVector3);\nvar\n  Weapon: TWeapon;\nbegin\n    if Direccion.X &lt; 0 then\n  begin\n    Weapon := TWeapon.Create(WeaponOwner, WeaponSpriteSceneRotate);\n  end\n  else\n  begin\n    Weapon := TWeapon.Create(WeaponOwner, WeaponSpriteScene);\n  end;\n  Weapon.StartPoint := Vector2(Origen.X,Origen.Y);\n  Weapon.MaxDistance:=ViewPort1.Camera.Orthographic.EffectiveRect.Width \/ 2;\n  Weapon.Translation := Origen;\n  Weapon.RBody.LinearVelocity := Direccion * Vector3(150, 0, 0);\n  ViewPort1.Items.Add(Weapon);\nend;                <\/pre><\/div>\n\n\n\n<p>Dependiendo de la direcci\u00f3n que indica el par\u00e1metro <em>Direcci\u00f3n<\/em>, crearemos el objeto con un sprite u otro y asign\u00e1ndole e un padre, en este caso es el que hemos pasado por el par\u00e1metro <em>WeaponOwner<\/em>.<\/p>\n\n\n\n<p>Indicamos el punto de inicio, y la distancia m\u00e1xima que ser\u00e1 la mitad de ancho de la c\u00e1mara. Cuando se alcanza esta distancia estamos fuera de la vista de la c\u00e1mara.<\/p>\n\n\n\n<p>Ajustamos su posici\u00f3n al origen. Cuando creamos el objeto este estaba en el origen de coordenadas. Ahora lo ponemos d\u00f3nde nos interesa.<\/p>\n\n\n\n<p>Ya solo nos queda asignar una velocidad, multiplicada por la direcci\u00f3n, as\u00ed el arma ir\u00e1 hac\u00eda un lado u otro.<\/p>\n\n\n\n<p>Ya solo nos queda a\u00f1adir nuestra arma, al <em>ViewPort<\/em>, para que el motor gr\u00e1fico se encargue de gestionarlo.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><br> Actualizar el n\u00famero de disparos<\/h2>\n\n\n\n<p>Para saber en cualquier momento el n\u00famero de espadas que hay en cada momento, podemos buscar el n\u00famero de objetos de tipo Tweapon que hay en el <em>Viewport. <\/em>Para ello vamos a crear un un procedimiento llamado <em>UpdateNumberWeapons<\/em> el cual lo llamaremos en el procedimiento <em>FireWeapon.<\/em><\/p>\n\n\n\n<p>El procedimiento <em>UpdateNumberWeapons<\/em> recorrer\u00e1 los elemento que hay en <em>Viewport<\/em> y obtendr\u00e1 el total de los que sean de tipo <em>Tweapon<\/em> actualizando la variable <em>NumeroDisparos.<\/em><\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">procedure TViewMain.UpdateNumberWeapons;\nvar\n  I: integer;\nbegin\n  NumeroDisparos := 0;\n  I := 0;\n  while I &lt; ViewPort1.Items.Count do\n  begin\n    if ViewPort1.Items[I].ClassType = TWeapon then\n    begin\n      if ViewPort1.Items[i].Exists = True then\n      begin\n        NumeroDisparos := NumeroDisparos + 1;\n      end;\n    end;\n    I := I + 1;\n  end;<\/pre><\/div>\n\n\n\n<p><br>Modificaremos el procedimiento <em>FireWeapon<\/em> para que llame a este procedimiento, y dependiendo del valor de la variable <em>NumeroDisparos<\/em>, devolver\u00e1 <em>True<\/em> o <em>False.<\/em><\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">function TViewMain.FireWeapon: boolean;\nbegin\n  Result := False;\n  UpdateNumberWeapons;\n  if (Container.Pressed[keySpace]) and (CanShot = True) and (NumeroDisparos &lt;= 2) then\n  begin\n    NumeroDisparos := NumeroDisparos + 1;\n    Result := True;\n    StarTimerShot;\n  end;\nend; <\/pre><\/div>\n\n\n\n<p>Tienes todo el c\u00f3digo completo en el <a href=\"https:\/\/github.com\/Blueicaro\/GhostAndGoblins_CGE-.git\" target=\"_blank\" rel=\"noreferrer noopener\">Github<\/a>.<\/p>\n\n\n\n<p>Saludos<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>En esta nueva entrada haremos que Arthur dispare su arma. Para ello veremos como crear un objeto por c\u00f3digo, como gestionarlo, y como gestionar un temporizador.<\/p>\n","protected":false},"author":2,"featured_media":1164,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[57,56,25,48],"tags":[49,32,23,21,24],"class_list":["post-1152","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-castle-game-engine","category-cge","category-pascal","category-videojuegos","tag-castle-game-engine","tag-free-pascal","tag-lazarus","tag-pascal","tag-programacion"],"_links":{"self":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/1152","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=1152"}],"version-history":[{"count":12,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/1152\/revisions"}],"predecessor-version":[{"id":1173,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/1152\/revisions\/1173"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/media\/1164"}],"wp:attachment":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1152"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1152"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1152"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}