Artikulu honetan, Unity-n 2D plataformarako karaktere kontrolatzaile bat garatzen jarraitzen dugu, kontrolak konfiguratzeko eta optimizatzeko urrats bakoitza ondo aztertuz. Aurreko artikuluan, " ", pertsonaiaren oinarria nola sortu xehetasunez eztabaidatu genuen, bere portaera fisikoa eta oinarrizko mugimendua barne. Orain, alderdi aurreratuagoetara pasatzeko garaia da, esate baterako, sarrera-kudeaketa eta kameraren jarraipen dinamikoa. Nola sortu 2D karaktere kontrolatzailea Unity-n: 1. zatia Artikulu honetan, Unity-ren sarrera-sistema berria konfiguratzen sakonduko dugu, pertsonaia kontrolatzeko ekintza aktiboak sortuz, jauziak ahalbidetuz eta jokalarien aginduei erantzun egokiak ziurtatuz. Artikulu honetan deskribatutako aldaketa guztiak zuk zeuk inplementatu nahi badituzu, artikulu honen oinarriak dituen " " biltegiaren adarra deskarga dezakezu. Bestela, " " adarra deskarga dezakezu azken emaitzarekin. Pertsonaia gorputza Caracter Controller Sarrera-sistema konfiguratzea Gure pertsonaia kontrolatzeko kodea idazten hasi aurretik, sarrera-sistema konfiguratu behar dugu proiektuan. Gure plataformarako, duela urte batzuk aurkeztutako Unity-ren Sarrera Sistema berria aukeratu dugu, sistema tradizionalarekiko dituen abantailengatik garrantzitsua izaten jarraitzen duena. Sarrera-sistemak sarrera-kudeaketarako ikuspegi modular eta malguagoa eskaintzen du, garatzaileek hainbat gailuren kontrolak erraz konfigura ditzakete eta sarrerako eszenatoki konplexuagoak onartzen dituzte inplementazio-gastu gehigarririk gabe. Lehenik eta behin, instalatu Input System paketea. Ireki paketeen kudeatzailea menu nagusitik Leihoa → Paketeen kudeatzailea hautatuta. Unity Registry atalean, bilatu "Input System" paketea eta egin klik "Instalatu". Ondoren, joan proiektuaren ezarpenetara Editatu → Proiektuaren ezarpenak menuaren bidez. Hautatu Erreproduzitzailea fitxa, bilatu Sarrera-kudeaketa aktiboa atala eta ezarri "Sarrera-sistemaren paketea (Berria). Urrats hauek amaitu ondoren, Unity-k berrabiarazteko eskatuko dizu. Berrabiarazi ondoren, dena prest egongo da gure kapitainaren kontrolak konfiguratzeko. Sarrera-ekintzak sortzea karpetan, sortu Sarrerako Ekintzak menu nagusiaren bidez: . Izendatu fitxategiari "Kontrolak". Ezarpenak Aktiboak → Sortu → Sarrerako Ekintzak Unity's Input System sarrera kudeatzeko tresna indartsu eta malgu bat da, garatzaileek pertsonaien eta joko-elementuen kontrolak konfiguratzeko aukera ematen diena. Hainbat sarrera-gailu onartzen ditu. Sortzen dituzun sarrera-ekintzek sarrera-kudeaketa zentralizatua eskaintzen dute, konfigurazioa erraztuz eta interfazea intuitiboagoa bihurtuz. Egin klik bikoitza fitxategian editatzeko irekitzeko, eta gehitu "Pertsonaia" izeneko karaktereak kontrolatzeko . Kontrolak ekintza-mapa Unity-ko Ekintza-Mapa bat jokoko zeregin zehatzak egiteko hainbat kontrolagailu eta teklarekin lotu daitezkeen ekintzen bilduma da. Kontrolak antolatzeko modu eraginkorra da, garatzaileei sarrerak esleitu eta doitzeko aukera ematen die kodea berridatzi gabe. Xehetasun gehiago lortzeko, ikus ofiziala. Sarrera-sistemaren dokumentazio Lehenengo ekintzak "Mugitu" izango da. Ekintza honek pertsonaiaren mugimenduaren norabidea definituko du. Ezarri "Balioa" eta "Vector2"-n lau norabidetan mugimendua gaitzeko. Ekintza Mota Kontrol Mota Esleitu ekintza honi loturak Gehitu gora/behera/eskuinekoa/ezkerreko konposatua hautatuz eta WASD tekla ezagunak dagozkien norabideetan esleitu. Ez ahaztu zure ezarpenak gordetzea sakatuta. Konfigurazio honek bermatzen du "Mugitu" ekintzarako loturak berriro esleitu ditzakezula, adibidez, gezi-teklak edo are gehiago gamepad joystick batera. Gorde aktiboa Ondoren, gehitu ekintza berri bat - "Jauzi". Mantendu "Botoi" gisa, baina gehitu berri bat - "Sakatu", eta ezarri "Sakatu eta Askatu", botoia sakatu eta askatu hartu behar baitugu. Ekintza Mota Interakzio Trigger Jokabidea Honek karaktereen kontrolaren eskema osatzen du. Hurrengo urratsa ekintza hauek kudeatzeko osagai bat idaztea da. Pertsonaia ezkerrera eta eskuinera mugituz Pertsonaien kontrolerako sortu ditugun Sarrera Ekintzak osagaiarekin lotzeko garaia da, pertsonaia gure kontrol komandoen arabera eszenan zehar aktiboki mugitzeko aukera emanez. CharacterBody Horretarako, mugimenduaren kontrolaz arduratzen den script bat sortuko dugu eta izendatuko dugu argitasunerako. Script honetan, lehenik eta behin oinarrizko eremu batzuk definituko ditugu. osagaiari erreferentzia bat gehituko diogu, , scriptak zuzenean kontrolatuko duena. CharacterController CharacterBody _characterBody Pertsonaiaren mugimendu-abiadura ( ) eta jauziaren altuera ( ) parametroak ere ezarriko ditugu. Gainera, eremuaren helburua zehaztuko dugu. _speed _jumpHeight _stopJumpFactor Baliteke 2Dko plataforma askotan jauzien altuera kontrolatu daitekeela konturatu izana. Zenbat eta luzeagoa izan jauzi botoia, orduan eta gorago egingo du jauzi pertsonaiak. Funtsean, hasierako goranzko abiadura ezartzen da jauziaren hasieran, eta abiadura hori murriztu egiten da botoia askatzean. ek jauzi botoia askatzean goranzko abiadura zenbateraino murrizten den zehazten du. _stopJumpFactor Hona hemen idatziko dugun kodearen adibide bat: // CharacterController.cs public class CharacterController : MonoBehaviour { [SerializeField] private CharacterBody _characterBody; [Min(0)] [SerializeField] private float _speed = 5; [Min(0)] [SerializeField] private float _jumpHeight = 2.5f; [Min(1)] [SerializeField] private float _stopJumpFactor = 2.5f; } Ondoren, pertsonaia ezkerrera eta eskuinera mugitzeko gaitasuna ezarriko dugu. Mugimendu-botoia sakatuta edukitzean, pertsonaiak zehaztutako mugimendu-abiadura mantendu behar du oztopoak gorabehera. Hori lortzeko, aldagai bat gehituko dugu scriptean uneko mugimendu-abiadura gainazalean gordetzeko (edo, besterik gabe, horizontalean pertsonaia airean dagoenean): // CharacterController.cs private float _locomotionVelocity; osagaian, abiadura hau ezartzeko metodo bat aurkeztuko dugu: CharacterBody // CharacterBody.cs public void SetLocomotionVelocity(float locomotionVelocity) { Velocity = new Vector2(locomotionVelocity, _velocity.y); } Gure jokoa ez denez gainazal maldarik agertzen, metodo hau nahiko erraza da. Eszenatoki konplexuagoetan, gorputzaren egoera eta gainazaleko malda kontuan hartu beharko genituzke. Oraingoz, abiaduraren osagai bertikala mantentzen dugu, koordenatu horizontala soilik aldatzen dugun bitartean. x Ondoren, balio hau metodoan ezarriko dugu fotograma guztietan: Update // CharacterController.cs private void Update() { _characterBody.SetLocomotionVelocity(_locomotionVelocity); } Sarrera Ekintzaren seinaleak kudeatzeko metodo bat definituko dugu: Move // CharacterController.cs public void OnMove(InputAction.CallbackContext context) { var value = context.ReadValue<Vector2>(); _locomotionVelocity = value.x * _speed; } ekintza gisa definitzen denez, testuinguruak balio bektorial bat emango du sakatzen edo askatzen diren teklaren arabera. Adibidez, tekla sakatzean metodoak bektorea jasoko du (1, 0). eta biak aldi berean sakatuz gero (1, 1) izango da. Tekla guztiak askatuz gero, abiaraziko da (0, 0) balioarekin. Move Vector2 D OnMove D W OnMove gakoarentzat, bektorea (-1, 0) izango da. metodoan, jasotako bektorearen osagai horizontala hartu eta zehaztutako mugimendu-abiaduraz biderkatuko dugu, . A OnMove _speed Pertsonaiari jauzi egiten irakastea Lehenik eta behin, osagaia jauziak maneiatzen irakatsi behar diogu. Horretarako, jauziaren ardura duen metodo bat gehituko dugu: CharacterBody // CharacterBody.cs public void Jump(float jumpSpeed) { Velocity = new Vector2(_velocity.x, jumpSpeed); State = CharacterState.Airborne; } Gure kasuan, metodo hau zuzena da: abiadura bertikala ezartzen du eta berehala aldatzen du pertsonaiaren egoera . Airborne Ondoren, pertsonaiak salto egin behar duen abiadura zehaztu behar dugu. Dagoeneko definitu dugu jauziaren altuera eta badakigu grabitateak etengabe eragiten duela gorputzean. Horren arabera, hasierako jauzi-abiadura kalkula daiteke formula hau erabiliz: Non jauziaren altuera den eta grabitazio-azelerazioa den. osagaian dagoen grabitate biderkatzailea ere kontuan hartuko dugu. Eremu berri bat gehituko dugu hasierako jauzi-abiadura definitzeko eta honela kalkulatuko dugu: h g CharacterBody // CharacterController.cs private float _jumpSpeed; private void Awake() { _jumpSpeed = Mathf.Sqrt(2 * Physics2D.gravity.magnitude * _characterBody.GravityFactor * _jumpHeight); } Beste eremu bat beharko dugu pertsonaia unean jauzi egiten ari den ala ez jarraitzeko, beraz, jauzi-abiadura dagokion momentuan mugatu ahal izango dugu. Gainera, jokalariak lurreratu arte salto-botoiari eusten badio, guk geuk berrezarri beharko genuke bandera hau. metodoan egingo da: Update // CharacterController.cs private bool _isJumping; private void Update() { if (_characterBody.State == CharacterState.Grounded) { _isJumping = false; } //... } Orain, idatzi dezagun ekintza kudeatzeko metodoa: Jump // CharacterController.cs public void OnJump(InputAction.CallbackContext context) { if (context.started) { Jump(); } else if (context.canceled) { StopJumping(); } } ekintza botoi bat denez, testuingurutik zehaztu dezakegu botoia sakatzea hasi ( ) ala amaitu ( ). Horretan oinarrituta, saltoa hasi edo gelditzen dugu. Jump context.started context.canceled Hona hemen saltoa exekutatzeko metodoa: // CharacterController.cs private void Jump() { if (_characterBody.State == CharacterState.Grounded) { _isJumping = true; _characterBody.Jump(_jumpSpeed); } } Salto egin aurretik, pertsonaia lurrean dagoen egiaztatzen dugu. Hala bada, bandera ezarriko dugu eta gorputza jauzi egingo dugu arekin. _isJumping _jumpSpeed Orain, inplementatu dezagun stop-jauzi portaera: // CharacterController.cs private void StopJumping() { var velocity = _characterBody.Velocity; if (_isJumping && velocity.y > 0) { _isJumping = false; _characterBody.Velocity = new Vector2( velocity.x, velocity.y / _stopJumpFactor); } } bandera aktibatuta badago soilik gelditzen dugu jauzia. Beste baldintza garrantzitsu bat pertsonaia gorantz mugitzea da. Horrek erorketa-abiadura mugatzea eragozten du jauzi-botoia beherantz mugitzean askatzen bada. Baldintza guztiak betetzen badira, bandera berrezartzen dugu eta abiadura bertikala faktore batean murrizten dugu. _isJumping _isJumping _stopJumpFactor Pertsonaia konfiguratzea Osagai guztiak prest daudenez, gehitu eta osagaiak eszenako objektuari. Ziurtatu sortu dugun osagaia hautatzen duzula, ez 3D karaktereak kontrolatzeko diseinatutako Unity osagai estandarra. PlayerInput CharacterController Captain CharacterController i, esleitu lehendik dagoen osagaia karaktereari. erako, ezarri aurretik sortutako eremuan. CharacterController CharacterBody PlayerInput Kontrolak Actions Ondoren, konfiguratu PlayerInput osagaia CharacterController-etik metodo egokiak deitzeko. Zabaldu Gertaerak eta Pertsonaiak atalak editorean, eta lotu dagozkien metodoak Mugitu eta Salto ekintzekin. Orain, dena prest dago jokoa exekutatzeko eta konfiguratutako osagai guztiek elkarrekin nola funtzionatzen duten probatzeko. Kameraren mugimendua Orain, kamerak pertsonaia joan den lekuan jarraitu behar dugu. Unity-k kamera kudeatzeko tresna indartsua eskaintzen du — . Cinemachine Cinemachine Unity-ko kamera kontrolatzeko soluzio iraultzaile bat da, garatzaileei gaitasun ugari eskaintzen dizkiena, joko-beharretara egokitzen diren kamera-sistema dinamiko eta ondo sintonizatuak sortzeko. Tresna honek kameraren teknika konplexuak ezartzea errazten du, hala nola pertsonaien jarraipena, fokuaren doikuntza automatikoa eta askoz gehiago, eszena bakoitzari bizitasuna eta aberastasuna gehituz. Lehenik eta behin, kokatu objektua eszenan, eta gehitu osagaia. Kamera Nagusia CinemachineBrain Ondoren, sortu objektu berri bat izeneko eszenan. Hauxe izango da kapitaina jarraitzen duen kamera, kameralari profesional bat bezala. Gehitu osagaia. Ezarri eremua kapitainari, aukeratu eremurako eta ezarri parametroa 4. CaptainCamera CinemachineVirtualCamera Jarraitu Framing Transposer Gorputza Lens Ortho Size Gainera, beste osagai bat beharko dugu kameraren desplazamendua pertsonaiarekiko definitzeko — . Ezarri balioa 1,5ean eta balioa -15ean. CinemachineCameraOffset Y Z Orain, proba dezagun kamerak nola jarraitzen duen gure izaera. Nahiko ondo atera dela uste dut. Kamerak tarteka totelka egiten duela ohartu nintzen. Hau konpontzeko, Kamera Nagusiaren objektuaren Blend Update Method eremuan FixedUpdate ezarri dut. Jauziak hobetzea Probatu ditzagun eguneratutako mekanika. Saiatu korrika eta etengabe salto egiten. Jokalari esperientziadunek jauziak ez direla beti erregistratzen ohartuko dira. Joko gehienetan, hau ez da arazo bat. Bihurtzen da zaila dela lurreratzeko ordu zehatza aurreikustea berriro salto botoia sakatzeko. Jokoa barkagarriagoa egin behar dugu, jokalariei lurreratu aurretik salto apur bat sakatu eta pertsonaia lurreratzean berehala salto egin dezaten. Jokalariek ohituta daudenarekin bat dator jokabide hau. Hau ezartzeko, aldagai berri bat sartuko dugu, , aukera sortzen bada salto bat abiarazi daitekeen denbora-leihoa adierazten duena. _jumpActionTime // CharacterController.cs [Min(0)] [SerializeField] private float _jumpActionTime = 0.1f; eremu bat gehitu dut, salto ekintzaren leihoaren amaiera markatzen duena. Beste era batera esanda, iritsi arte, pertsonaiak salto egingo du aukera sortzen bada. Eguneratu dezagun ekintza-kudeatzailea ere. _jumpActionEndTime _jumpActionEndTime Jump // CharacterController.cs private float _jumpActionEndTime; public void OnJump(InputAction.CallbackContext context) { if (context.started) { if (_characterBody.State == CharacterState.Grounded) { Jump(); } else { _jumpActionEndTime = Time.unscaledTime + _jumpActionTime; } } else if (context.canceled) { StopJumping(); } } Salto botoia sakatzen denean, pertsonaia lurrean badago, berehala egiten dute salto. Bestela, saltoa oraindik egin daitekeen denbora-leihoa gordetzen dugu. Kendu dezagun egoeraren egiaztapena metodotik bertatik. Grounded Jump // CharacterController.cs private void Jump() { _isJumping = true; _characterBody.Jump(_jumpSpeed); } Stop-jauzi metodoa ere egokituko dugu. Botoia lurreratu aurretik askatu bazen, ez litzateke jauzirik gertatu behar, beraz, berrezarri dugu. _jumpActionEndTime // CharacterController.cs private void StopJumping() { _jumpActionEndTime = 0; //... } Noiz egiaztatu behar dugu pertsonaia lurreratu dela eta salto bat eragin? egoera -n prozesatzen da, ekintza prozesatzea geroago gertatzen den bitartean. edo den kontuan hartu gabe, lurreratzea eta jauziaren artean fotograma bateko atzerapena gerta daiteke, eta hori nabaria da. CharacterBody FixedUpdate Update FixedUpdate gertaera bat gehituko dugu n lurreratzeari berehala erantzuteko. Lehenengo argumentua aurreko egoera izango da, eta bigarrena uneko egoera. StateChanged CharacterBody // CharacterBody.cs public event Action<CharacterState, CharacterState> StateChanged; Egoeraren kudeaketa egokituko dugu egoera aldaketa gertaera abiarazteko eta berridatziko dugu. FixedUpdate // CharacterBody.cs [field: SerializeField] private CharacterState _state; public CharacterState State { get => _state; private set { if (_state != value) { var previousState = _state; _state = value; StateChanged?.Invoke(previousState, value); } } } nola kudeatzen den ere findu nuen -n. surfaceHit FixedUpdate // CharacterBody.cs private void FixedUpdate() { //... if (_velocity.y <= 0 && slideResults.surfaceHit) { var surfaceHit = slideResults.surfaceHit; Velocity = ClipVector(_velocity, surfaceHit.normal); if (surfaceHit.normal.y >= _minGroundVertical) { State = CharacterState.Grounded; return; } } State = CharacterState.Airborne; } -en, gertaerara harpidetuko gara eta kudeatzaile bat gehituko dugu. CharacterController StateChanged // CharacterController.cs private void OnEnable() { _characterBody.StateChanged += OnStateChanged; } private void OnDisable() { _characterBody.StateChanged -= OnStateChanged; } private void OnStateChanged(CharacterState previousState, CharacterState state) { if (state == CharacterState.Grounded) { OnGrounded(); } } egoera egiaztatzea kenduko dugu eta era eramango dugu. Update Grounded OnGrounded // CharacterController.cs private void Update() { _characterBody.SetLocomotionVelocity(_locomotionVelocity); } private void OnGrounded() { _isJumping = false; } Orain, gehitu kodea jauzi bat abiarazi behar den egiaztatzeko. // CharacterController.cs private void OnGrounded() { _isJumping = false; if (_jumpActionEndTime > Time.unscaledTime) { _jumpActionEndTime = 0; Jump(); } } uneko ordua baino handiagoa bada, jauzi botoia duela gutxi sakatu dela esan nahi du, beraz, berrezarri eta jauzia egiten dugu. _jumpActionEndTime _jumpActionEndTime Orain, saiatu etengabe jauzi egiten pertsonaiarekin. Konturatuko zara salto-botoia sentikorragoa dela eta pertsonaia kontrolatzea leunagoa dela. Hala ere, ikusi nuen zenbait egoeratan, beheko ilustrazioan ageri den izkinan adibidez, egoerak atzerapen apur bat jasaten duela, jauzi-katea eten egiten duela. Grounded Honi aurre egiteko, osagaiko eremua 0.05ean ezarri nuen 0.01-en ordez. Balio honek gorputza egoeran sartzeko gainazal baterako gutxieneko distantzia adierazten du. CharacterBody Surface Anchor Grounded Cliff Jumping Konturatuko zara gainazal bertikaletatik korrika egiten ari zaren bitartean salto egiten saiatzeak ez duela beti funtzionatzen. Salto botoiak batzuetan ez duela erantzuten sentitu daiteke. Hau da 2D plataformako bat garatzeko ñabardura bat. Jokalariek jauzi egiteko gaitasuna behar dute jauzi botoia sakatzean berandu samar bada ere. Kontzeptu hau bitxia dirudien arren, plataformako jokalari gehienek nola funtzionatzen dute. Emaitza airea bultzatzen duen pertsonaia bat da, beheko animazioan erakusten den moduan. karaktere kontrolatzaile Ezar dezagun mekanika hau. Eremu berri bat sartuko dugu denbora-leihoa (segundotan) gordetzeko, zeinetan pertsonaiak oraindik ere salto egin dezakeen egoera galdu ondoren. Grounded // CharacterController.cs [Min(0)] [SerializeField] private float _rememberGroundTime = 0.1f; Beste eremu bat ere gehituko dugu denbora-zigilua gordetzeko, eta ondoren, egoera "ahazten" da. Grounded // CharacterController.cs private float _lostGroundTime; Egoera honen jarraipena egingo da gertaera erabiliz. kudeatzailea egokituko dugu horretarako. CharacterBody OnStateChanged // CharacterController.cs private void OnStateChanged(CharacterState previousState, CharacterState state) { if (state == CharacterState.Grounded) { OnGrounded(); } else if (previousState == CharacterState.Grounded) { _lostGroundTime = Time.unscaledTime + _rememberGroundTime; } } Garrantzitsua da bereiztea pertsonaiak egoera galdu duen nahitako salto baten ondorioz edo beste arrazoi batengatik. Dagoeneko dugu bandera, deitzen den bakoitzean desgaituta dagoena ekintza erredundanteak saihesteko. Grounded _isJumping StopJumping Beste bandera bat ez sartzea erabaki nuen, jauzi erredundanteak bertan behera uzteak ez duelako jokatzeko eraginik. Anima zaitez esperimentatzen. bandera orain pertsonaia salto egin ondoren lurreratzen denean bakarrik garbituko da. Eguneratu dezagun kodea horren arabera. _isJumping // CharacterController.cs private void StopJumping() { _jumpActionEndTime = 0; var velocity = _characterBody.Velocity; if (_isJumping && velocity.y > 0) { _characterBody.Velocity = new Vector2( velocity.x, velocity.y / _stopJumpFactor); } } Azkenik, metodoa berrikusiko dugu. OnJump // CharacterController.cs public void OnJump(InputAction.CallbackContext context) { if (context.started) { if (_characterBody.State == CharacterState.Grounded || (!_isJumping && _lostGroundTime > Time.unscaledTime)) { Jump(); } else { _jumpActionEndTime = Time.unscaledTime + _jumpActionTime; } } else if (context.canceled) { StopJumping(); } } Orain, gainazal bertikaletatik jauzi egiteak ez du jokatzeko erritmoa apurtzen eta askoz naturalagoa sentitzen da, itxurazko absurdua izan arren. Pertsonaiak literalki airetik bota dezake, logikoa dirudiena baino urrunago joanez. Baina hori da gure plataformarako behar dena. Pertsonaia Flip Azken ukitua pertsonaia mugimenduaren norabideari aurre egitea da. Modurik errazenean inplementatuko dugu, pertsonaiaren eskala x ardatzean zehar aldatuz. Balio negatiboa ezartzeak gure kapitainak kontrako noranzkoari begira jarriko du. Lehenik eta behin, gorde dezagun jatorrizko eskala 1etik desberdina bada. // CharacterController.cs public class CharacterController : MonoBehaviour { //... private Vector3 _originalScale; private void Awake() { //... _originalScale = transform.localScale; } } Orain, ezkerrera edo eskuinera mugitzean, eskala positiboa edo negatiboa aplikatuko dugu. // CharacterController.cs public class CharacterController : MonoBehaviour { public void OnMove(InputAction.CallbackContext context) { //... // Change character's direction. if (value.x != 0) { var scale = _originalScale; scale.x = value.x > 0 ? _originalScale.x : -_originalScale.x; transform.localScale = scale; } } } Proba dezagun emaitza. Biltzea Artikulu hau nahiko zehatza izan zen, baina pertsonaien kontrolaren funtsezko alderdi guztiak 2D plataforma batean estaltzea lortu genuen. Oroigarri gisa, azken emaitza biltegiko " " adarrean ikus dezakezu. Caracter Controller Hau eta aurreko artikulua lagungarri gustatu bazaizu edo gustatu bazaizu, eskertuko nizuke GitHub-en atsegin eta izarrak. Ez izan zalantzarik eta jar zaitez harremanetan arazoren bat aurkitzen baduzu edo akatsak aurkitzen badituzu. Eskerrik asko zure arretagatik!