Logo

Főoldal

Blog

Elmélet

3D Studio

Adatvédelmi nyilatkozat

GY.I.K.

Házirend

Szerző: Marosi Csaba / marosi.csaba@3d-studio.hu

DiscordGitHubLinkedIn
Developedia
Developedia
/Feladatgyűjtemény
Feladatgyűjtemény
/Térbeli Programozás
Térbeli Programozás
Térbeli Programozás

Térbeli Programozás

‣
Távolság kiszámítása

Írj függvényt, ami visszaadja 2 darab Vector2 típusú paraméterként kapott helyvektor távolságát.

A megoldáshoz ne használd a Vector2.Distance metódust!

‣
A megoldás és a Unity komponens a teszteléshez
using UnityEngine;
    
class TestingComponent: MonoBehaviour
{
    [SerializeField] Vector2 a, b;    // Bemeneti változók    
    [SerializeField] float result;    // Kimeneti változó
    
    void OnValidate()
    {
        result = GetDistance(a, b);
    }

    // ... Megoldás függvény helye
}
‣
Hol lehet mindennek haszna a játékfejlesztésben?

Például az ellenség ki akarja számolni távolságát a játékostól. Ha az egy bizonyos határértéken belül van, akkor támad.

‣
Megoldás
using UnityEngine;

float GetDistance(Vector2 p1, Vector2 p2)
{
	return (p1 - p2).magnitude;
}

Alternatív megoldás:

‣
Irányvektor pontból pontba

Írj függvényt, ami 2 helyvektort kap Vector3 típusú paraméterként!

A függvényt visszaadja a pontból b pontba mutató, 1 egység hosszúságú vektort.

‣
Unity komponens a megoldás tesztelése
using UnityEngine;
    
class TestingComponent: MonoBehaviour
{
	[SerializeField] Vector3 a, b;      // Bemeneti változók    
	[SerializeField] Vector3 result;    // Kimeneti változó
    
	void OnValidate()
	{
		result = NormalFromAToB(a, b);
	}

	// ... Megoldás függvény helye
}
‣
Megoldás
Vector3 NormalFromAToB(Vector3 a, Vector3 b)
{
	Vector3 v = b - a;    // Ez a-ból b-be mutató vektor
	return v.normalized;  // Ennek a normalizált (1 hosszú) alakja kell.
}
‣
Hol lehet mindennek haszna a játékfejlesztésben?

Például az a feladat, hogy egy objektum fix sebességgel kövessen egy másikat.

Ehhez szükségünk van egy olyan vektorra, ami az egyikből a másik felé mutat.

Hogy a sebességet kontrolálni tudjuk a vektor hossza fixen egy egység kell legyen.

‣
Towards függvény

Írd meg a Vector3.MoveTowards függvény saját változatát!

Ha szükséges, nézzetek utána a magadott függvények működésének a Unity dokumentációban!

‣
Unity komponens a megoldás tesztelése
using UnityEngine;
    
class TestingComponent: MonoBehaviour
{
	[SerializeField] Transform target;
	[SerializeField] float speed = 1;

	void Update()
	{
		transform.position = MoveTowards(
		transform.position,
		target.position,
		speed * Time.deltaTime);
	}

	// ... Megoldás függvény helye
}
‣
Megoldás
‣
Vektor átalakítás

Írj függvényt, ami egy paraméterben kapott Vektor2-t átalakít Vektor3-má úgy, hogy a 2D vektor y komponense legyen a 3D vektor z pozíciója. A kapott 3D vektor Y komponense legyen mindig nulla.

‣
Unity komponens a megoldás tesztelése
using UnityEngine;
    
class TestingComponent: MonoBehaviour
{
	[SerializeField] Vector2 v2;    // Bemeneti változó    
	[SerializeField] Vector3 v3;    // Kimeneti változó
    
	void OnValidate()
	{
		v3 = ToVector3(v2);
	}

	// ... Megoldás függvény helye
}
‣
Megoldás
Vector3 ToVector3(Vector2 v2)
{
	return new Vector3(v2.x, 0, v2.y);
}
‣
Hol lehet mindennek haszna a játékfejlesztésben?

Inputról kapunk egy vektort a mozgásról, ami egy 2D vektprt ír le.

(Ez jöhet a WASD gombokból, Gamepad-en az analog karokból vagy a D-padről)

De aze a 2D vaktort arra használjuk, hogy 3D ben mozogjunk méghozzá úgy, hogy ha a felfelét nyomom akkor előre haladjon a karakterem.

‣
Lépésszámlálás

Írj komponenst, ami kap 2 helyvektort Vector2 típusú [SerializeField] bemeneti váltókban.

A komponens kiszámolja, hogy “a” pontból “b” pontba legalább hány ugrással tudnánk eljutni, ha maximum egy egység hosszút ugorhatunk.

Emellett a komponens kiszámolja a vektort is, amit egy ugrásban meg kéne tenni, hogy eljussunk a célba. Minden ugrás legyen egyforma hosszú!

Az eredményeket [SerializeField] változókba írja be a program!

Az eredmény a bemeneti változók módosítása után egyből látsszon! (OnValidate)

‣
Megoldás
‣
Lépésszámlálás korlátokkal

Írj függvényt, ami 2 helyvektort kap Vector2 paraméterként!

A függvényt visszaadja, hogy “a” pontból “b” pontba legalább hány ugrással tudnánk eljutni, ha maximum egy egység hosszút ugorhatunk és csakis függőleges, vízszintes vagy 45 fokos átlós irányba.

‣
Megoldás
‣
Egyenes haladás

Írj komponenst, aminek meg lehet adni egy [SerializeField] Vektor3 típusú változót.

A komponens egyenletesen mozog. Másodpercenkét akkora utat tesz meg, mint a megadott vektor hossza és olyan irányba megy amerre a megadott vektor mutat.

‣
Megoldás
using UnityEngine;

public class SimpleMover : MonoBehaviour
{
    [SerializeField] Vector3 inputVector;

    void Update()
    { 
        // Szorozni kell az Time.deltaTime-el, mert így csak egy frame-nyit lépünk előre.
        transform.Translate(inputVector * Time.deltaTime);
    }
}
‣
Lépkedés

Írj komponenst, aminek a kurzorgombok lenyomásakor lépked 1 egységet a megfelelő irányba!

‣
Megoldás
‣
Lépkedés fix sebeséggel

Írj komponenst, aminek a kurzorgombok lenyomásakor lépked 1 egységet a megfelelő irányba!

A lépés sebessége beálltható.

Minden lépés után automatikus a mozgás.

‣
Illusztráció
‣
Megoldás
‣
Folyamatos mozgás gombnyomásra

Írj komponenst, ami a kurzorgombok lenyomva tartására folyamatosan halad a megfelelő irányba.

A komponensnek be kell állítani egy [SerializeField] változóban egy haladási sebességet.

Figyelj a következőkre:

  • A beállított sebeség mértéke: egység / másodper.
  • Keresztben is lehet haladni, de a sebességet ekkor is tartani kell!
‣
Megoldás
‣
Lábad elé nézz!

Írj komponenst, ami figyeli, hogy haladt-e a komponens előző Update óta. Ha igen akkor a GameObject Transformját beforgatja a haladási irányba.

(A GameObject lokális előre iránya arra mutasson, amerre haladtunk.)

‣
Megoldás
‣
Követő

Írj komponenst, aminek ha egy Transorm típusú [SerializeField] változóban megadunk egy másik GameObject-et, akkor követi azt fix sebességgel. (Folyamatosan megy felé.)

A komponensnek be kell állítani a haladási sebességet is. (A beállított sebesség azt adja meg, hogy egy másodperc alatt mekkora utat tegyen meg a GameObject.)

‣
Megoldás
‣
Követés tisztes távolságból

Írj komponenst, aminek ha egy Transorm típusú [SerializeField] változóban megadunk egy másik GameObject-et, akkor követi azt fix sebességgel, azaz folyamatosan megy felé úgy, hogy nem közelíti meg az teljesen. Hogy mekkora távolságot tartunk a célobjektumtó egy másik beállíthatás adja meg.

A komponensnek be kell állítani a haladási sebességet is. (A beállított sebesség azt adja meg, hogy egy másodperc alatt mekkora utat tegyen meg a GameObject.)

‣
Megoldás
‣
Közelebbi követése

Írj komponenst, aminek megadhatunk kettő másik GameObject-et Transorm típusú [SerializeField] változóban. A szkripünk kiválasztja a kettő közül a közelebbit és afelé megy fix beállítható sebességgel.

‣
Megoldás
‣
Menekülés!

Írj “menekülő” szkriptet, aminek megadható egy “üldöző” GameObject, amitől “menekül”!

A “menekülő” akkor kezd el “menekülni”, ha egy beállítható minimum távolságon belül van az “üldöző”-höz képest, és akkor hagyja abba azt, ha kívül kerül ezen a távolságon.

A “menekülés” úgy történik, hogy a menekülő egy fix beállítható gyorsulással növeli a saját sebességét az üldözőtől távolodó irányba. Amikor nincs “menekülő” állapot, akkor fix lassulással a 0 sebességet próbálja elérni a “menekülő”.

Opcionális: Megadható egy max sebesség a menekülőnek.

Opcionális: Megadható egy max sebesség a menekülőnek.

‣
Illusztráció

Bárány és kutya Sprite-ok letölthetők itt:

Animals.zip4.8KB
‣
Megoldás
‣
Forgatás a közelebbi irányába

Írj komponenst, aminek megadhatunk kettő másik GameObject-et Transorm típusú [SerializeField] változóban. A szkripünk kiválasztja a kettő közül a közelebbit és lassan elkezdi afelé fordítja a saját felfelé irányát fix beállítható szögsebességgel. A komponens 2D-ben működik.

‣
Illusztráció
‣
Megoldás
‣
Eltolás egy célpont felé

Írj komponenst, aminek megadhatunk egy másik GameObject-et Transorm típusú [SerializeField] változóban. A szkriptünk eltolja saját magát egy maximális beállítható távolsággal a célpont irányába a kezdeti pozíciójához képest. Ha a célpont közelebb van, mint a maximális eltolás, akkor az eltolás kisebb.

‣
Illusztráció

Minden egyes szembogárra rátettem a szkriptet:

‣
Megoldás
‣
Kockarácson tartó

Írj komponenst, ami mindhárom tengelyen egész számú pozíción tart egy GameObject-et!

‣
Példák

Nem lehet a pozíció (3.4, -1.8, 11.66), Helyette lenne: (3, -2, 12)

(33.33, 0.25, -0.49) → (33, 0, 0)

(0.83, 45.55, 9.99) → (1, 46, 10)

‣
Megoldás
‣
Átlépés a 0 magasságon

Írj komponenst, ami jelzi (kiírja a konzolra), hogyha a GameObject -je átlépte a nulla magasságot bármilyen irányba.

Pl.: Abc GameObject már magasabban van mint 0.

Pl.: Abc GameObject már alacsonyabban van mint 0.

Figyelj arra, hogy ezt az üzenetet egy átlépés esetén csak egyszer írja ki, ne folyamatosan

‣
Megoldás
‣
Átlépés a négyzetrácson

Írj komponenst, ami jelzi, hogyha a GameObject -je átlépett bármilyen tengelyen, bármilyen irányban egy 10-zel osztható egységen.

Pl.: Abc GameObject x koordinátája már nagyobb, mint -60.

Pl.: Abc GameObject z koordinátája már kisebb van mint 120.

Figyelj arra, hogy ezt az üzenetet egy átlépés esetén csak egyszer írja ki, ne folyamatosan!

‣
Megoldás
‣
Saját Towards függvény

Írjátok meg a saját verziótokat a Mathf. Vector2. és Vector3.MoveTowards függvényből.

‣
Definíció
💡
Towards típusú függvények

Unityban a Towards szót tartalmazó függvények mindig hasonlóan működnek.

3 paraméterüke van:

  • current… (Jelenlegi érték)
  • target… (Cél érték)
  • maxDelta… (Maximum változás értéke)

A függvény azzal az értékkel tér vissza, ami az current értékből való elmozdulás a target érték felé legfeljebb maxDeltával.

A towards típusú függvényeket általában arra használjuk, hogy Updatde függvényben közelítsünk valami felé. Ebben a zesetben a maxDelta általában a változás sebessége kell, hogy legyen megszorozva Time.deltaTime-mal

Ha szükséges, nézzetek utána a magadott függvények működésének a Unity dokumentációban!

‣
Példák
‣
Megoldás
‣
Automata forgató

Írj komponenst, ami a középpontja körül forgat egy testet.

A komponens beállításai:

  • A forgás tengelye egy beállítható 3D vektor.
  • Az, hogy a lokális vagy a globális térben értelmezett-e a vektor.
  • A forgás szögsebessége fokban kifejezve.

A tengelyt gizmó jelenítse meg!

‣
Megoldás
‣
Körpályán mozgatás

Írj komponenst, ami egy pont körül körpályán mozgatja a GameObject-jét 2D síkban.

Beállítható a középpont, forgási sebesség.

A kör sugarát az határozza meg, hogy kezdetben milyen távol van a ponttól.

‣
Segítség

A megoldáshoz hasznos lehet a szinusz, a koszinus és a kör kapcsolatának megértése.

‣
Megoldás
‣
Összekötő vonal

Írj komponenst ami egy Gizmo vonalat rajzol, ami egy másik beállítható objektumig ér, de csak ha egy beállítható határérték alatt van a két objektum távolsága.

Ha közel jár (90% vagy több) a távolság ehhez a határértékhez, a vonal színe legyen piros.

‣
Megoldás
‣
Gömbben tartó

Írj komponenst, ami nem tud elhagyni egy beállítható középpontú és sugarú gömböt!

Ha a GameObject a megadott gömbön kívül van, a szkriptednek vissza kell helyeznie azt a gömbön belüli legközelebbi pontra.

A megoldás elég ha Play módban működik.

Figyelj arra, hogy ne lehessen 0-nál kisebb sugarat beállítani!

Gizmóval rajzold ki a gömböt!

‣
Megoldás
‣
Két pont között tartás

Írj komponenst, ami egy objektumot mindig 2 beállítható egyéb A és B objektum közötti vonalon tart.

Hogy a vonalon hol helyezkedik el azt egy 0-1 értéket felvehető arányszám határozza meg, amely érték szintén a komponens beállítása.:

Ha az arányszám <= 0, akkor pont A-nál kell legyen.

Ha az arányszám >= 1 pont B-nél. Ha

Minden köztes értékre valahol az összekötő vonalon legyen az objektum, úgy hogy az arányszám egyenletes változtatásával az objektum is egyenletesen mozog.

Opcionális:

Beállításban rendelj egy egy színt mindkét objektumhoz és rajzolj ki gömb alakú gizmokat az objektumok pozíciójába a megfelelő színnel.

A két pont közti vonalat is rajzold ki. A vonal színe attól függjön, hogy melyik objektumhoz vagyunk közelebb.

‣
Megoldás
‣
Sarkokból Bound

Írj függvényt, ami visszaad egy téglatestet két átellenben lévő sarokpontja alapján! A téglatest oldalai párhuzamosak a 3D tér tengelyeivel.

A függvény két Vektor3 típusú paramétert vár bemenetnek, és visszatér egy Bound típusú téglatesttel.

Teszteld a függvényt gizmók kirajzolásával!

‣
Illusztráció
‣
Megoldás
‣
Kocka sarkai

Írj függvényt, ami egy kocka sarkainak pozícióit számolja ki!

A függvény bemenetei:

  • A kocka középpontja: Vector3
  • A kocka oldalhossza: float
  • A kocka elforgatását Euler szögekkel: Vector3

A függvény kimenete:

  • Egy 8 elemű Vector3 tömb a kocka 8 sarkával

Teszteld a függvényt gizmók kirajzolásával!

‣
Megoldás
‣
Saját lineáris interpoláció függvények

Írjátok meg a saját verziótokat a következő függvényekből:

  • Mathf.LerpUnclamped (Először ezt old meg!)
  • Mathf.Lerp

Ha szükséges, nézzetek utána a magadott függvények működésének a Unity dokumentációban

Bonyolultabb matematikai függvények megalkotásánál segíthet ez a weboldal: Desmos | Graphing Calculator

‣
Megoldás
‣
Saját lineáris interpoláció vektorokon

Írjátok meg a saját verziótokat a következő függvényekből:

  • Vector2.LerpUnclamped
  • Vector2.Lerp
  • Vector3.LerpUnclamped
  • Vector3.Lerp

Ha szükséges, nézzetek utána a magadott függvények működésének a Unity dokumentációban!

Ha elkészítetted már korábban, Mathf.Lerp és Mathf.Lerp függvények saját változatát, akkor felhasználhatod őket a megoldáshoz.

‣
Megoldás
‣
Póz rajzoló

Írj komponenst, ami egy 6 ágú keresztet rajzol a térben pont oda, ahol a komponenshez tartozó GameObject elhelyezkedik!

A keresztnek 3 egymással merőleges tengelye legyen!

A kereszt ágai arra mutassanak, amerre a GameObject lokális jobbra, balra, fel, le, előre és hátra iránya mutat.

A kereszt ágai meghatározott színűek legyenek:

  • X tengely: 🔴 Piros
  • Y tengely: 🟢 Zöld
  • Z tengely: 🔵 Kék

Az ágak hossza megegyezik. A hossz egy [SerializeField] mezővel beállítható.

Bónusz: A pozitív irányokba (jobbra, fel, előre) mutató ágak végére rajzoljatok egy kis gömböt!

‣
Megoldás 1
‣
Megoldás 2
‣
Életcsík

Írj komponenst, ami kirajzol egy életcsíkot gizmóval.

A komponensnek megadható, hogy

Mennyi a maximum élet

Mennyi a jelenlegi élet

Milyen széles az életcsík

Mennyire csúsztassa el az életcsíkot az eredeti komponenshez képest

Az életcsík piros színnel mutatja az elveszített életet és zölddel a meglévőt.

‣
Illusztráció
‣
Megoldás
‣
Méretező interpoláció

Írj komponenst, amin a következő beállítások szerepelnek:

  • Egy másik “t” transform,
  • Egy tetszőleges maximum távolságérték,
  • Egy tetszőleges minimum távolságérték,
  • És egy tetszőleges "scale" szorzóértéket.

A komponens a következő módon változtassa a transform-ja méretét:

Ha a maximum távolságértéknél vagy annál távolabb vagyunk a másik “t” transformhoz, a méretünk az eredeti.

Ha a minimum távolságértéknél vagy közelebb vagyunk a másik “t” transformhoz, a méretünk megváltozik az eredeti m-szeresére.

A kettő között fokozatos a változás.

‣
Megoldás:
‣
Színátmenet

Írj komponenst, ami kirajzol egy csíkot két pont közé úgy, hogy a vonal színe egyik pontból átmenetet képez a másikba!

A komponensnek megadható…

  • a két végpont pozíciója (Vector3 point1, point2),
  • a kezdő és a végpont színe (Color color1, color2) és
  • hogy mennyi különböző szeletre legyen vágva a vonal (int segmentCount).
Game ablakban a nagyítást (Scale) felvettem maximumra
Game ablakban a nagyítást (Scale) felvettem maximumra
⚠️
Figyeljetek arra, hogy egy [SerializeField] Color mező alfa csatornája (opacitás/ átlátszatlanság értéke) alapértelmezetten mindig 0 lesz. Tehát a szín teljesen átlátszó lesz, még akkor is, ha ti a többi csatornát beállítjátok.

Az alfa csatornát is manuálisan kell módosítani, és ezt könnyű elfelejteni.

Hasznos lehet tehát, ha a szín mezőknek adtok egy olyan kezdőértéket kódból, amiben az alfa csatorna értéke nem 0. Pl.:

[SerializeField] Color color1 = Color.red;
[SerializeField] Color color2 = Color.green;

Ekkor nem áll fenn az veszélye, hogy Editor-ban elfelejtitek majd átállítani.

‣
Megoldás
‣
Követőrakéta

Írj követőrakéta komponenst! A komponens-nek van egy [SerializeField] Transform target beállítása. A követőrakéta mindig ezt a célpontot próbálja elérni a 3D térben.

A rakéta mindig csak…

  • előrefelé haladhat egy beállítható fix sebességgel, és
  • legfeljebb fix szögsebességgel fordulhat.
‣
Megoldás
‣
Kör rajzoló

Írj metódust, ami rajzol egy Gizmo kört 2D síkban!

(A Gizmos osztály nem tartalmaz kör rajzoló metódust viszont tartalmaz egyenes rajzolót. 😉)

Az eljárás paraméterben kapja meg a kör középpontját és a sugarát.

‣
Segítség

A megoldáshoz hasznos lehet a szinusz és koszinusz függvény valamint a kör kapcsolatának megértése.

‣
Megoldás
‣
Körszelet rajzoló

Írj metódust, ami rajzol egy körszeletet 2D síkban.

A Gizmos osztály nem tartalmaz kör rajzoló metódust viszont tartalmaz egyenes rajzolót. 😉

A függvény paraméterben kapja meg a középpontját és a kör sugarát ás a nyitó és záró szögét.

‣
Segítség

A megoldáshoz hasznos lehet a szinusz, a koszinus és a kör kapcsolatának megértése.

‣
Megoldás
‣
Dolly Zoom

Alakítsatok ki Dolly Zoom effektet a Unity-ben.

Hogy mi a fene az a Dolly Zoom? Egy filmes kamera effekt, amit Alfred Hitchcock dolgozott ki Irmin Roberts operatőrrel a Szédülés című mára klasszikussá vált filmhez. (Korábban is kísérletezett az effekttel kevesebb sikerrel) Az effekt lényege, hogy úgy változtatja az operatőr a kamera zoom-ot, hogy közben a célpont és a kamera távolsága is módosul. Ezáltal megoldható, hogy a célobjektum mérete ne változzon, mégis drasztikusan átalakuljon a kép. Ezáltal kényelmetlen, idegen hatást kelthet a filmkészítő.

Szédülés - Vertigo (1958)
Szédülés - Vertigo (1958)
Cápa - Jaws (1975)
Cápa - Jaws (1975)
A gyűrű szövetsége - The Fellowship of the Ring (2001)
A gyűrű szövetsége - The Fellowship of the Ring (2001)
Nagymenők - Goodfellas (1990)
Nagymenők - Goodfellas (1990)

Unity-ben egy komponenst kell elkészíteni, amin a következő beállítások szerepelnek:

[SerializeField] new Camera camera;           // A kamera, amivel dolgozunk
[SerializeField] Transform target;            // A cél, amit követünk
[SerializeField] Vector3 offset;              // A célpont pozíciójának eltolása
[SerializeField] float targetScale = 1;       // A célpont mérete
[SerializeField] float targetDistance = 5f;   // A célpont távolsága a kamerától

A célpozíciót a target, azaz célpont objektum pozíciója eltolva az offset eltolásvektorral.

A targetScale, azaz a célpont mérete azt adja meg, hogy a kamera által belátott magasság mekkora a célpozíció mélységében.

A targetDistance a kamera és a célpont távolságát adja meg.

A kamera pozíciója a kamera irányából, a célpozícióból és a céltól való távolságból számolható ki.

Adjunk a komponenshez lekérdező (getter) és beállító (setter) metódusokat a következő adatokhoz:

  • targetDistance
  • targetScale
  • cameraFieldOfView
‣
Illusztráció
‣
Megoldás

Tömbök, Listák

‣
Legközelebbi elem

Írj komponenst aminek egy [SerializeField] tömbben beköthetünk bárhány darab Transform-ot.

A komponens feladata, hogy a legközelebbi felé menjen egyenletes beállítható sebességgel.

Gizmó kösse össze a GameObject-et a legközelebbivel!

‣
Megoldás
‣
Szülő a legmagasabb

Írj komponenst, ami meggátolja, hogy bármely gyerek objektuma magasabban legyen, mint az a GameObject, amin a komponens van.

‣
Megoldás
‣
Forgató szülő

Írj komponenst, ami egyenletes sebességgel forgatja az összes gyerek objektumát, amin van MeshRenderer-rel!

A forgás tengelye legyen a gyerek objektum lokális függőleges (Y) iránya!

A forgatás alap szögsebességét egy beállítás adja meg!

Bónusz feladat: A forgási sebesség legyen fordítottan arányos a szülőtől vett távolsággal is! Minél távolabb van a test, annál lassabban forogjon a test!

‣
Megoldás
‣
Közeli Trasform-ok

Írj komponenst, ami Gizmó vonalat rajzol saját pozíciójából minden olyan Transform pozíciójába, amik nincs messzebb egy beállítható távolságnál!

‣
Illusztráció
‣
Megoldás
‣
Sorakozó

Írj komponenst, aminek meg lehet adni [SerializeField] beállításként Transform-oknak egy sorozatát (tömbjét vagy listáját).

A komponens berendezi a Transform-okat az első és az utolsó közé egyenes vonalon egyenletes távolság

‣
Illusztráció
image
‣
Megoldás
‣
Pályán mozgás

Írj komponenst, ami egy szögletes útvonalon mozgat egy testet fix beállítható sebességgel!

Az útvonal pontjait egy Vector3 lista tartalmazza, ami a komponens beállítása.

A pályát rajzold ki gizmóval!

Ha az útvonalon végigért a test, visszafordul.

‣
Megoldás
‣
Pályán mozgás ciklikusan

Írj komponenst, ami egy zárt szögletes útvonalon mozgat körbe-körbe egy testet fix beállítható sebességgel!

Az útvonal pontjait egy Vector3 lista tartalmazza, ami a komponens beállítása.

Az utolsó és az első pont összekötött.

A pályát rajzold ki gizmóval!

Ha az útvonalon végigért a test, megy tovább körkörösen.

‣
Megoldás
‣
Kör pontjai

Írj metódust, ami visszaadja egy síkbeli kör pontjait egyenletes távolságban!

A függvény paraméterben kapja meg a kör középpontját, sugarát és a visszaadandó pontok számát.

Opcionális: Használd fel a fent megírt függvényt, hogy Gizmo-val vagy Line Renderer-rel kirajzold az alakzatot!

‣
Segítség

A megoldáshoz hasznos lehet a szinusz és koszinusz függvény valamint a kör kapcsolatának megértése.

‣
Megoldás
‣
Spirál pontjai

Írj metódust, ami visszaadja egy spirál pontjait egyenletes távolságban!

A függvény paraméterben kapja meg a kör középpontját, sugarát és a visszaadandó pontok számát.

Opcionális: Használd fel a fent megírt függvényt, hogy Gizmo-val vagy Line Renderer-rel kirajzold az alakzatot!

‣
Illusztráció
‣
Megoldás
‣
2D Pontok átalakítása 3D-be (Hamarosan)
‣
Kézműves TrailRenderer (Hamarosan)
‣
Mozgás két pont közt

Írj komponenst, ami két beállítható pont között mozgatja a GameObject-et oda-vissza egy beállítható fix sebességgel!

‣
Megoldás
‣
Megoldás 2
public class BackAndForth : MonoBehaviour
{
  [SerializeField] Transform a, b;
  [SerializeField] float speed;
  
	void Update()
	{
		transform.position = Vector3.Lerp(a.position, b.position, Mathf.PingPong(Time.time * speed, 1));
	}
}
‣
Szinuszos mozgás két pont közt

Írj komponenst, ami két beállítható pont között mozgatja a GameObject-et oda-vissza szinuszosan egy beállítható frekvenciával! (Másodpercenként hány teljes hullámot tegyen meg?)

Javasolt kipróbálni:

Desmos Desmos | Graphing CalculatorDesmos Desmos | Graphing Calculator

‣
Megoldás
‣
Megoldás 2
‣
Gyerekek forgatása

Valósítsd meg a tojások mozgását egy komponenssel az alábbi videoból (Cuphead) (Videóban 01:05-1:30)

‣
Megoldás
// Hgy oldja meg ezt a feladatot a Unity a háttérben?
// Pithagorasz tétellel!
        
float GetDistance(Vector2 p1, Vector2 p2)
{
	// Ha a két vektort kivonom egymásból, akkor egy olyan vektort kapok,
	// ami egyik pontból a másikba mutat:
	Vector2 v = p1 - p2;
	        
	// Az így papott vektor körberajzolható egy téglalappal,
	// aminek oldalai párhuzamosak az x és y tengelyekre.
	// A vektor (a két pontot összekötő volan) a téglalap átlója.
	
	// a téglalap oldalait "a"-val és "b"-vel, az átlója "c"-vel jelölöm.
	float a = v.x;
	float b = v.y;
	// c = ?         Ezt keresem. Ez a megoldás.
	
	// a, b, c egyenesek derékszögű háromszöget adnak, ahol c az átló.
	// Derékszögű háromszögön alkalmazható a Pitagorasz tétel:
	// a^2 + b^2 = c^2
	
	float cSquare = (a * a) + (b * b); // Kiszámolom c-négyzetet
	float c = Mathf.Sqrt(cSquare); // Gyököt vonok, hogy kiszámoljam c-t
	
	return c; // Ez a két pont távolsága
}
Vector3 MoveTowards(Vector3 current, Vector3 target, float maxDistanceDelta)
{
	Vector3 distanceVec = target - current;        // Jelenlegiből a cél felig tartó vektor
	float distance = distanceVec.magnitude;        // Teljes út hossza
	Vector3 direction = distanceVec / distance;    // Cél felé mutató 1 egység hosszú irányvektor
	                                               // (Kiszámolhattuk volna így is: distanceVec.normalized)
	                                                       
	float movement = Mathf.Min(distance, maxDistanceDelta);   // Ekkora utat teszünk meg
	return current + direction * movement;         // Visszaadom a jelenlegi pozíciót eltolva a mozgással
}
using UnityEngine;
    
class NormalizedDirectionVector : MonoBehaviour
{
    [SerializeField] Vector2 a, b;      // Bemeneti változók    
    
    // Kimeneti változók:
    [SerializeField] int stepCount;
    [SerializeField] Vector2 step;
    
    void OnValidate()
    {
        Vector2 dirVec = b - a;             // a-ból b-be mutató vektor.
        float distance = dirVec.magnitude;  // Távolság
        stepCount = Mathf.CeilToInt(distance / 1f); // Min.ennyi lépés kell
        step = dirVec / stepCount;          // Ekkora egy lépés
    }
}
using UnityEngine;
    
class NormalizedDirectionVector : MonoBehaviour
{
    // Tesztelésre:
    [SerializeField] Vector2 a, b;   // Bemeneti változók    
    [SerializeField] int stepCount;  // Kimeneti változó
    
    void OnValidate()
    {
        stepCount = GetStepCount(a, b, 1);
    }
    
    // Lényegi megoldás:
    int GetStepCount(Vector2 a, Vector2 b, float maxStepLength)
    {
        Vector2 dirVec = b - a;             // a-ból b-be mutató vektor.

        // Az a megoldásötlet, hogy két részre osztom a megtehető utat.
        // Amíg lehet megyek átlósan,
				// a maradékot a tengelyek mentén teszem meg
        
        float x = dirVec.x;
        float y = dirVec.y; 

        float min = Mathf.Min(x, y);    // Rövidebbik oldal
        float max = Mathf.Max(x, y);    // Hosszabbik oldal

        float diagonal = min * Mathf.Sqrt(2);  // Átlósan megtehatő út
        float straight = max - min;            // Tengelyekre merőleges út

        int stepCountDiagonal = (int)(diagonal / maxStepLength);
        int stepCountStraight = (int)(straight / maxStepLength);
        return stepCountDiagonal + stepCountStraight;
    }
}
using UnityEngine;

public class StepMover : MonoBehaviour
{
    void Update()
    {
        // This script steps 1 in the direction from the keyboard.
        
        if (Input.GetKeyDown(KeyCode.RightArrow))
            transform.position += Vector3.right;
        if (Input.GetKeyDown(KeyCode.LeftArrow))
            transform.position += Vector3.left;
        
        if (Input.GetKeyDown(KeyCode.UpArrow))
            transform.position += Vector3.forward;
        if (Input.GetKeyDown(KeyCode.DownArrow))
            transform.position += Vector3.back;
    }
}
using UnityEngine;

class StepMover : MonoBehaviour
{
    [SerializeField] float speed;

    Vector3 target;

    void Start()
    {
        target = transform.position;
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.UpArrow))
            target += Vector3.up;
        if (Input.GetKeyDown(KeyCode.DownArrow))
            target += Vector3.down;
        if (Input.GetKeyDown(KeyCode.RightArrow))
            target += Vector3.right;
        if (Input.GetKeyDown(KeyCode.LeftArrow))
            target += Vector3.left;

        Vector3 selfPos = transform.position;
        transform.position = Vector3.MoveTowards(
            selfPos,
            target,
            speed * Time.deltaTime);
    }
}
using UnityEngine;

public class PlayerMover : MonoBehaviour
{
    [SerializeField] float speed = 1;

    void Update()
    {
        // Input vektor létrehozása 1:
        Vector3 inputVector1 = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
        
        // Input vektor létrehozása 2:
        float x1 = Input.GetKeyDown(KeyCode.LeftArrow) ? -1 : 0;
        float x2 = Input.GetKeyDown(KeyCode.RightArrow) ? 1 : 0;
        
        float z1 = Input.GetKeyDown(KeyCode.DownArrow) ? -1 : 0;
        float z2 = Input.GetKeyDown(KeyCode.UpArrow) ? 1 : 0;
        Vector3 inputVector2 = new Vector3(x1 + x2, 0, z1 + z2);
        
        // Az input vektort normalizáljuk, hogy átlós irányban is nulla hosszú legyen.
        inputVector1 = inputVector1.normalized;
        
        // Szorozni kell a beállított sebességgel.
        // Szorozni kell az Time.deltaTime-el, mert így csak egy frame-nyit lépünk előre.
        transform.Translate(inputVector1 * (Time.deltaTime * speed));
    }
}
using UnityEngine;

public class MoveDirectionTurner : MonoBehaviour
{
    // Osztály szintű változó, hogy mindig elmentsük az előző pozíciót
    Vector3 lastPosition;

    void Start()
    {
        // Elmentem az kezdeti pozíciót
        lastPosition = transform.position;
    }

    void Update()
    {
        Vector3 currentPosition = transform.position;                 // Az aktuális pozíció
        Vector3 movementDirection = currentPosition - lastPosition;   // A mozgás iránya
        
        // Ha a pozíció változott, akkor a haladás irányába nézek
        transform.rotation = Quaternion.LookRotation(movementDirection);
        
        lastPosition = currentPosition;  // Az előző pozíciót elmentem
    }
}
using UnityEngine;

public class Follower : MonoBehaviour
{
    // Követendő transform referenciája
    [SerializeField] Transform target;      // Célpont
    [SerializeField] float speed = 1;       // Sebesség 
    
    void Update()
    {
        Vector3 targetPosition = target.position;   // Követendő pozíció
        Vector3 selfPosition = transform.position;  // Saját pozíció
        
        Vector3 movement = targetPosition - selfPosition; // Mozgás iránya
        movement.Normalize();                             // Irány normalizálása
        
        // Szükséges szorozni a mozgás irányát a sebességével
        // Szükséges szorozni a Time.deltaTime-mal,
        // hogy egy frame alatti utat tegye csak meg
        transform.position += movement * (Time.deltaTime * speed);
    }
}
using UnityEngine;

public class DistancedFollower : MonoBehaviour
{
    // Követendő transform referenciája
    [SerializeField] Transform target;      // Célpont
    [SerializeField] float speed = 1;       // Sebesség
    [SerializeField] float minDistance = 1; // Minimális távolság
    
    void Update()
    {
        Vector3 targetPosition = target.position;   // Követendő pozíció
        Vector3 selfPosition = transform.position;  // Saját pozíció
        
        Vector3 movement = targetPosition - selfPosition; // Mozgás iránya
        float distance = movement.magnitude;              // Célponttávolsága
        
        if(distance <= minDistance)    // Ha már elég közel vagyunk,
	        return;                      // akkor nem megyünk még közelebb
        
        
        movement.Normalize();          // Irány normalizálása
        
        // Szükséges szorozni a mozgás irányát a sebességével
        // Szükséges szorozni a Time.deltaTime-mal,
        // hogy egy frame alatti utat tegye csak meg
        transform.position += movement * (Time.deltaTime * speed);
    }
}
using UnityEngine;

public class Follower : MonoBehaviour
{
	// Követendő transformok referenciái
	[SerializeField] Transform target1, target2;  // Célpontok
	[SerializeField] float speed = 1;             // Sebesség 
    
	void Update()
	{
		Vector3 selfPosition = transform.position;  // Saját pozíció
		// Célpontok távolságai:
		fload distance1 = Vector3.Distance(target1.position, selfPosition);
		fload distance2 = Vector3.Distance(target2.position, selfPosition);
		    
		Transform target;               // Kiválasztjuk a közelebbit
		if (distance1 < distance2)
			target = target1;
		else
			target = target2;				  
    
		Vector3 targetPosition = target.position;   // Követendő pozíció
        
		Vector3 movement = targetPosition - selfPosition; // Mozgás iránya
		movement.Normalize();                             // Irány normalizálása
        
		// Szükséges szorozni a mozgás irányát a sebességével
		// Szükséges szorozni a Time.deltaTime-mal,
		// hogy egy frame alatti utat tegye csak meg
		transform.position += movement * (Time.deltaTime * speed);
	}
}
using UnityEngine;

public class Fleeing : MonoBehaviour
{
	[SerializeField] Transform chaser;   // Az az objektum, amely üldözi ezt az objektumot 
	[SerializeField] float minDistance;  // A minimális távolság, amelyen belül a menekülési viselkedés elkezdődik
	[SerializeField] float acceleration; // A menekülés gyorsulásának (és lassulásának) mértéke
	[SerializeField] float maxSpeed;     // Az objektum által elérhető maximális sebesség

	Vector3 velocity; // Az objektum jelenlegi sebességvektora

	void Update()
    {
		// Számítjuk ki az objektum és az üldöző közötti távolságvektort és hosszát
		Vector3 distanceVector = (transform.position - chaser.position);
		float distance = distanceVector.magnitude;

		bool isFleeing = distance < minDistance; // Éppen menekülünk-e?

		if (isFleeing) // Ha menekülünk, akkor...
		{
			// A távolság alapján számítjuk ki az üldöző irányítására használni kívánt irányvektort
			Vector3 direction = distanceVector / distance; // Normalizálás
			// ...növeljük a sebességet az irányításhoz
			velocity += acceleration * Time.deltaTime * direction;
			//és végül korlátozzuk a sebességet, ha túl nagy lenne
			velocity = Vector3.ClampMagnitude(velocity, maxSpeed);
		}
		else // Ha nem menekülünk, akkor...
		{
			// ...lassítsuk le a sebességet a nulla felé
			velocity = Vector3.MoveTowards(velocity, Vector3.zero, acceleration * Time.deltaTime);
		}

		// Lépünk egyet: Frissítjük az objektum pozícióját a sebességvektor és a időintervallum szorzatával
		transform.position += velocity * Time.deltaTime;
	}
}
using UnityEngine;

public class RotateToClosest : MonoBehaviour
{
	[SerializeField] Transform target1, target2;  // Célpontok
	[SerializeField] float angularSpeed; // Szögsebesség

	void Update()
    {
		// Számítjuk ki az objektum és a cél1, valamint az objektum és a cél2 közötti távolságot
		float distance1 = Vector3.Distance(transform.position, target1.position);
		float distance2 = Vector3.Distance(transform.position, target2.position);

		// Kiválasztjuk a közelebbi célt az objektumhoz
		Vector3 targetPosition = distance1 < distance2 ? target1.position : target2.position;

		// Kiszámítjuk a cél irányát az objektumhoz képest
		Vector3 targetDirection = (targetPosition - transform.position).normalized;

		// Számítjuk ki a célt irányítására használt elfordulási irányítást
		Quaternion targetRotation = Quaternion.LookRotation(Vector3.forward, targetDirection);

		// Elforgatjuk az objektumot a cél felé az elfordulási sebesség és az időintervallum alapján
		transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, angularSpeed * Time.deltaTime);
	}
}
using UnityEngine;

public class OffsetMover : MonoBehaviour
{
	[SerializeField] Transform target; // A célobjektum, amely felé mozgunk
	[SerializeField] float maxOffset;  // A maximális eltolás mértéke

	Vector3 startPostion; // Az objektum kezdeti pozíciója

	void Start()
	{
		// Elmentjük az objektum kezdeti pozícióját
		startPostion = transform.position;
	}

	void Update()
	{
		// Kiszámítjuk az objektum és a célpont közötti távolságvektort:
		Vector3 distanceVector = target.position - transform.position;
		// Korlátozzuk az eltolás méretét
		Vector3 offsetVector = Vector3.ClampMagnitude(distanceVector, maxOffset);

		// Az objektum új pozíciója a kezdeti pozíció és az eltolás összege
		transform.position = startPostion + offsetVector;
	}
}
using UnityEngine;

public class GridLocker : MonoBehaviour
{
    void Update()
    {
        // Saját pozíció
        Vector3 pos = transform.position;
        
        // Kerekített pozíció
        Vector3 rounded = new Vector3(
            Mathf.Round(pos.x),
            Mathf.Round(pos.y),
            Mathf.Round(pos.z));

        // Visszaírjuk a kerekített pozíciót
        transform.position = rounded;
    }
}
using UnityEngine;

public class ZeroHeightChecker : MonoBehaviour
{
    // Ebbe a változóba mentjük el a legutóbbi magasságot
    float lastY;

    void Start()
    {
        // Elmentjük a kezdeti magasságot
        lastY = transform.position.y;
    }

    void Update()
    {
        // Jelenlegi magasság
        float currentY = transform.position.y;
        
        // Ha a jelenlegi és az előző magasság előjele különböző,
        if (Mathf.Sign(currentY) != Mathf.Sign(lastY))
            Debug.Log("Zero height crossed at " + Time.time); // átlépte a 0 magasságot.
            
        lastY = currentY; // Elmentem az utolsó magasságot
    }
}
using UnityEngine;

public class GridCrossingCheck : MonoBehaviour
{
    float gridSize = 10;
    
    Vector3 lastPosition;

    void Start()
    {
        // Elmentem a kezdeti pozíciót
        lastPosition = transform.position;
    }

    void Update()
    {
        // Jelenlegi pozíció
        Vector3 currentPosition = transform.position;

        // Minden tengelyt külön vizsgálok
        TestAxis(currentPosition.x, lastPosition.x, "X");
        TestAxis(currentPosition.y, lastPosition.y, "Y");
        TestAxis(currentPosition.z, lastPosition.z, "Z");
        
        // Elmentem a legutóbbi pozíciót
        lastPosition = currentPosition;
    }
    
    // Segédmetódust hozok létre, ami csak egy tengelyt vizsgál egyszerre
    void TestAxis(float currentPos, float lastPos, string axis)
    {
        int current = Mathf.FloorToInt(currentPos / gridSize);
        int last = Mathf.FloorToInt(lastPos / gridSize);
        
        // Átlépés felfelé irányba
        if (current > last)
            Debug.Log($"{axis} now is higher than {current * gridSize}");
        
        // Átlépés lefelé irányba
        else if (current < last)
            Debug.Log($"{axis} now is smaller than {last * gridSize}");
    }
}
MoveTowards(1, 2, 0.2f)  // Eredmény: 1.2f  (1-ből 2 felé elmozdultunk 0.2-t)
MoveTowards(1, -3, 0.2f) // Eredmény: 0.8f  (1-ből -3 felé elmozdultunk 0.2-t)
MoveTowards(3, 5, -0.3f) // Eredmény: 2.7f  (3-ból 5 felé elmozdultunk -0.3-at)
MoveTowards(1, 2, 1)     // Eredmény: 2     (1-ből 2 felé elmozdultunk 1-et)
MoveTowards(1, 2, 2)     // Eredmény: 2     (1-ből 2 felé elmozdultunk 1-et)
												 // (Ezért csa 1-et, mert nem lehet a targeten túlmenni) 
using UnityEngine;

public class MyOwnTowardsFunctions : MonoBehaviour
{
    // Tesztelésre
    [SerializeField] Transform target;
    [SerializeField] float speed = 1;

    void Update()
    {
        transform.position = MoveTowards(
            transform.position, 
            target.position, 
            Time.deltaTime * speed);
    }

    // Lényegi megoldás
    float MoveTowards(float current, float target, float maxDelta)
    {
        float delta = target - current;
        delta = Mathf.Clamp(delta, -maxDelta, maxDelta);
        return current + delta;
    }
    
    Vector2 MoveTowards(Vector2 current, Vector2 target, float maxDelta)
    {
        return new Vector2(
            MoveTowards(current.x, target.x, maxDelta),
            MoveTowards(current.y, target.y, maxDelta));
    }
    
    Vector3 MoveTowards(Vector3 current, Vector3 target, float maxDelta)
    {
        return new Vector3(
            MoveTowards(current.x, target.x, maxDelta),
            MoveTowards(current.y, target.y, maxDelta),
            MoveTowards(current.z, target.z, maxDelta));
    }  
}
using UnityEngine;

public class Rotator : MonoBehaviour
{
    [SerializeField] Vector3 center;
    [SerializeField] float angularSpeed = 360;

    float currentAngle;
    float radius;

    void Start()
    {
        // Kezdetben kiszámítom a szöget és a kezdő fokot
        Vector2 v = transform.position - center;
        currentAngle = Vector2.Angle(v, Vector2.right);
        radius = v.magnitude;
    } 

    void Update()
    {
        // Növelem a jelenlegi szöget a szögsebességnek megfeleően.
        currentAngle += angularSpeed * Time.deltaTime;
        
        // Szinusz és Coszinusz függvényekből állítom elő a pozíciót 
        float angleInRadians = currentAngle * Mathf.Deg2Rad;
        float x = Mathf.Cos(angleInRadians);
        float y = Mathf.Sin(angleInRadians);
        Vector3 pos = new Vector3(x, y, 0);
        
        pos *= radius;      // Átméretezem a kört sugár szereint
        pos += center;      // Eltolom a pozíciót a középponttól
        
        transform.position = pos;
    }
}
using UnityEngine;

public class CircleMover : MonoBehaviour
{
    [SerializeField] Vector3 center;
    [SerializeField] float angularSpeed = 360;

    float currentAngle;
    float radius;

    void Start()
    {
        // Kezdetben kiszámítom a szöget és a kezdő fokot
        Vector2 v = transform.position - center;
        currentAngle = Vector2.Angle(v, Vector2.right);
        radius = v.magnitude;
    } 

    void Update()
    {
        // Növelem a jelenlegi szöget a szögsebességnek megfeleően.
        currentAngle += angularSpeed * Time.deltaTime;
        
        // Szinusz és Coszinusz függvényekből állítom elő a pozíciót 
        float angleInRadians = currentAngle * Mathf.Deg2Rad;
        float x = Mathf.Cos(angleInRadians);
        float y = Mathf.Sin(angleInRadians);
        Vector3 pos = new Vector3(x, y, 0);
        
        pos *= radius;      // Átméretezem a kört sugár szereint
        pos += center;      // Eltolom a pozíciót a középponttól
        
        transform.position = pos;
    }
}
using UnityEngine;

public class ConnectingLine : MonoBehaviour
{
    [SerializeField] Transform other;
    [SerializeField] float maxLength = 10;

    void OnDrawGizmos()
    {
        if (other == null)
            return;

        Vector3 otherPos = other.position;
        Vector3 selfPos = transform.position;
        
        // Távolság kiszámítása
        float distance = Vector3.Distance(otherPos, selfPos);
        
        // Ha határértéken belül van a másik objektum
        if (distance <= maxLength)
        {
            if (distance > maxLength * 0.9f)   // Ha 90% felett
                Gizmos.color = Color.red;
            else
                Gizmos.color = Color.green;
            
            Gizmos.DrawLine(otherPos, selfPos);
        }
    }
}
using UnityEngine;

public class ConnectingLine : MonoBehaviour
{
    [SerializeField] Transform center;
    [SerializeField] float maxDistance = 10;

    void Update()
    {
        Vector3 centerPosition = center.position;
        Vector3 offset = transform.position - centerPosition;
        
        if(offset.magnitude > maxDistance) // Ha tullóg a határon
        {
            // Visszateszem a határra
            transform.position = centerPosition + offset.normalized * maxDistance;
        }
    }

    void OnDrawGizmos()  // Kirajzolás
    {
        Gizmos.color = Color.white;
        Gizmos.DrawWireSphere(center.position, maxDistance);
    }
}
using UnityEngine;

public class KeepingOnTheLine : MonoBehaviour
{
    [SerializeField] Vector3 a, b;
    [SerializeField] Color colorA, colorB;
    [SerializeField, Range(0,1)] float f;
    
    void Update()
    {
        // Lineáris interpoláció pontok között
        transform.position = Vector3.Lerp(a, b, f);
    }
    
    void OnDrawGizmos()
    {
        Gizmos.color = colorA;
        Gizmos.DrawWireSphere(a, 0.1f);
        Gizmos.color = colorB;
        Gizmos.DrawWireSphere(b, 0.1f);
        
        // Lineáris interpoláció színek között
        Gizmos.color = Color.Lerp(colorA, colorB, f);
        Gizmos.DrawLine(a,b);
    }
}
using UnityEngine;

public class BoundsTester : MonoBehaviour
{
	// Ellenőrzés:
	[SerializeField] Vector3 corner1, corner2; 
	
	void OnDrawGizmosSelected()
	{
		Bounds bounds = FoundBounds(corner1, corner2);
		Gizmos.color = Color.red;
		Gizmos.DrawWireCube(bounds.center, bounds.size);
		Gizmos.DrawSphere(corner1, 0.1f);
		Gizmos.DrawSphere(corner2, 0.1f);
	}
	
	// Függvény:
	Bounds FoundBounds(Vector3 cornerA, Vector3 cornerB)
	{ 
		// Minden komponenst külön-külön minimuma és maximuma
		Vector3 min = Vector3.Min(cornerA, cornerB);
		Vector3 max = Vector3.Max(cornerA, cornerB);
		
		// A középpont és a méret kiszámítása
		Vector3 center = (min + max) / 2;
		Vector3 size = max - min;
		
		// Visszatérés az eredménnyel
		return new Bounds(center, size);
	}
}
using UnityEngine;

public class CornersOfCube: MonoBehaviour
{
  // Ellenőrzés:
	[SerializeField] Vector3 position;
	[SerializeField] float side = 1.0f;
	[SerializeField] Vector3 euler = Vector3.zero;
	
	void OnDrawGizmosSelected()
	{
		Vector3[] corners = FoundCorners(position, side, euler);
		Gizmos.color = Color.red;
		foreach (Vector3 corner in corners)
		{
			Gizmos.DrawSphere(corner, 0.1f);
		}
	
		Gizmos.DrawLine(position, position + normal);
	}
	
  // Függvény:
	Vector3[] FoundCorners(Vector3 center,float side, Vector3 euler)
	{
		// Kiszámolok egy quaterniont az egyik oldal normálvektorából:
		Quaternion rotation = Quaternion.Euler(euler);
		        
		// Közepétől elülső oldalig mutató vektor  (Csak az oldalhossz fele):
		Vector3 forward = rotation * Vector3.forward * side / 2f;
				
		// Közepétől jobb oldalig mutató vektor:
		Vector3 right = rotation * Vector3.right * side / 2f;

		// Közepétől tetejéig mutató vektor:
		Vector3 up = rotation * Vector3.up * side / 2f;

		// Fentiek kiszámítására használhattunk volna kereszt szorzást:
		// Vector3.Cross(Vector3 lhs, Vector3 rhs);
		// Ekkor nem kellett volna Quaternion

		// Sarokpontok:
		Vector3[] corners = new Vector3[8];
		corners [0] = center + forward + right + up;
		corners [1] = center + forward + right - up;
		corners [2] = center + forward - right + up;
		corners [3] = center + forward - right - up;
		corners [4] = center - forward + right + up;
		corners [5] = center - forward + right - up;
		corners [6] = center - forward - right + up;
		corners [7] = center - forward - right - up;

		return corners;
	}
}
using UnityEngine;

class OwnLerp : MonoBehaviour
{
    // Tesztelésre:
    [SerializeField] float a, b;
    [SerializeField] float t;

    [SerializeField] float lerp;
    [SerializeField] float lerpUnclamped;
    
    void OnValidate()
    { 
        lerp = Lerp(a, b, t);
        lerpUnclamped = LerpUnclamped(a, b, t);
    }

    // Lényegi megoldás:
    float LerpUnclamped(float a, float b, float t)
    {
        // LerpUnclamped lineáris függvény:
        // Csak a meredeksége és az eltolása a kérdés.
        
        float dif = b - a;          // A két szám különbsége fogja mutatni,
                                    // hogy egy egység alatt
																		// mennyit változik a függvény értéke.
        float multiplied = t * dif; // Ez lesz a függvény meredeksége
        return a + multiplied;      // Függőlegesen eltoljuk a függvényt a-val.
    }
    
    float Lerp(float a, float b, float t)
    {
        // Ne kezdjük előlről!
        // Felhasználhatjuka a LerpUnclamped függvényünket.
        float l = LerpUnclamped(a, b, t);
        float min = Mathf.Min(a, b);
        float max = Mathf.Max(a, b);
        return Mathf.Clamp(l, min, max);
    }
}
using UnityEngine;

public class MyOwnVectorLerp : MonoBehaviour
{
    // Tesztelésre:
    [SerializeField] Vector3 a, b;
    [SerializeField, Range(0, 1)] float f;

    void Update()
    {
        transform.position = Lerp(a, b, f);
    }

    // Lényegi megoldás:
    
    Vector2 LerpUnclamped(Vector2 a, Vector2 b, float f)
    {
        return a + f * (b - a);
    }
    
    Vector3 Lerp(Vector2 a, Vector2 b, float f)
    {
        return new Vector3(
            Mathf.Lerp(a.x, b.x, f),
            Mathf.Lerp(a.y, b.y, f));
    }
    
    Vector3 LerpUnclamped(Vector3 a, Vector3 b, float f)
    {
        return a + f * (b - a);
    }
    
    Vector3 Lerp(Vector3 a, Vector3 b, float f)
    {
        return new Vector3(
            Mathf.Lerp(a.x, b.x, f),
            Mathf.Lerp(a.y, b.y, f),
            Mathf.Lerp(a.z, b.z, f));
    }
}
using UnityEngine;

public class PoseMarker : MonoBehaviour
{
  [SerializeField] float length = 0.5f;  // Egy ág hossza
    
  void OnDrawGizmos()
  { 
	  Vector3 p = transform.position;              // Középpont
        
		// X tengely
		Gizmos.color = Color.red;                    // Gizmó színe
    Vector3 right = length * transform.right;    // Lokális joobbra irány
    Gizmos.DrawLine(p - right, p + right);       // Vonal rajzolása
    Gizmos.DrawSphere(p + right, length);        // Gömb rajzoása 
        
		// Y tengely
    Gizmos.color = Color.green;
    Vector3 up = length * transform.up;
    Gizmos.DrawLine(p - up, p + up);
    Gizmos.DrawSphere(p + up, length);

		// Z tengely
    Gizmos.color = Color.blue;
    Vector3 forward = length * transform.forward;
    Gizmos.DrawLine(p - forward, p + forward);
    Gizmos.DrawSphere(p + forward, length);

		// Hmmm... Kicsit sok a kódisméttlés. Mit kezdjünk ezzel?
	}
}
using UnityEngine;

public class Tester : MonoBehaviour
{
	[SerializeField] float length;  // Egy tengely hossza
    
  void OnDrawGizmos()
  { 
	  Vector3 p = transform.position;

    DrawAxis(p, Vector3.right, Color.red);
    DrawAxis(p, Vector3.up, Color.green);
    DrawAxis(p, Vector3.forward, Color.blue);
  }
    
  void DrawAxis(Vector3 center, Vector3 axis, Color color)
  {
		Vector3 direction = length * transform.TransformDirection(axis);
		Gizmos.color = color;
		Gizmos.DrawLine(center - direction, center + direction);
		Gizmos.DrawSphere(center + direction, 0.1f * length);
  }
}
using UnityEngine;

public class LifeBar : MonoBehaviour
{
    [SerializeField] float maxHealth = 100f;                            // Maximum élet
    [SerializeField] float currentHealth = 50f;                         // Jelenlegi élet
    [SerializeField] float lifeBarWidth = 1;                            // Életvonal szélessége
    [SerializeField] Vector3 lifeBarOffset = Vector3.up;                // Életvonal eltolása

    void OnDrawGizmos()
    {
        Vector3 basePos = transform.position + lifeBarOffset;           // Az életcsík középpontjának pozíciója
        
        Vector3 left = basePos + Vector3.left * lifeBarWidth / 2;       // Az életcsík bal oldalának pozíciója
        Vector3 right = basePos + Vector3.right * lifeBarWidth / 2;     // Az életcsík jobb oldalának pozíciója
        
        float healthRatio = currentHealth / maxHealth;                  // Az meglévő élet aránya
        healthRatio = Mathf.Clamp01(healthRatio);                       // A fenti érték 0 és 1 közé korlátozása
        Vector3 turningPoint = left + Vector3.right * lifeBarWidth * healthRatio;  
                                                                        // Az életcsík itt vált pirosra
        
        Gizmos.color = Color.green;                                     
        Gizmos.DrawLine(left, turningPoint);                            // Az életcsík zöld része
            
        Gizmos.color = Color.red;                                       
        Gizmos.DrawLine(turningPoint, right);                           // Az életcsík piros része
    }
}
using UnityEngine;

public class Scaler : MonoBehaviour
{
    [SerializeField] Transform t;
    [SerializeField] float minDistance, maxDistance;
    [SerializeField] float scale;

    Vector3 startScale;
    
    void Start()
    {
        // Elmentem az eredeti méretet
        startScale = t.localScale;
    }

    void Update()
    {
        // Távolság
        float distance = Vector3.Distance(t.position, transform.position);
        
        // Mennyire legyen erős a méretezés hatása
        float scalingRate = Mathf.InverseLerp( maxDistance,minDistance, distance);
        
        // Méretezés
        transform.localScale = startScale * Mathf.Lerp(1, scale, scalingRate);;
    }

    void OnDrawGizmos()
    {
        Gizmos.color = Color.green;
        Gizmos.DrawWireSphere(t.position, minDistance);
        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(t.position, maxDistance);
    }
}
using UnityEngine;

public class GradientDrawer : MonoBehaviour
{
    [SerializeField] Vector3 point1, point2;
    [SerializeField] Color color1, color2;
    [SerializeField, Min(2)] int segmentCount = 10;
    
    void OnDrawGizmos()
    {
        float step = 1f / segmentCount;
        for (int i = 0; i < segmentCount; i++)
        {
            float colorRate = (float)i / (segmentCount-1);
            Color color = Color.Lerp(color1, color2, colorRate);
            Vector3 start = Vector3.Lerp(point1, point2, i * step);
            Vector3 end = Vector3.Lerp(point1, point2, (i+1) * step);
            Gizmos.color = color;
            Gizmos.DrawLine(start, end);
        }

    }
}
using UnityEngine;

public class Rocket : MonoBehaviour
{
	[SerializeField] Transform target;
	[SerializeField] float speed = 5;
	[SerializeField] float angularSpeed = 180;
	
	void Update()
	{
		Transform self = transform;
		
		Vector3 targetDirection = target.position - self.position;  // Ebben az irányban van a cél
		Quaternion targetRotation = Quaternion.LookRotation(targetDirection);   // Ahhoz ebbe az irányba akarunk fordulni
		
		// Fordulás:
		float maxAngle = angularSpeed * Time.deltaTime;  // Maximum ekkora szögben fordulhatunk most
		self.rotation = Quaternion.RotateTowards(self.rotation, targetRotation, maxAngle);  // Towards metódus
		
		// Haladás:
		float offset = speed * Time.deltaTime;   // Ennyit lépünk előre
		self.position += self.forward * offset;  // Előre irányba megyünk
	}
}
using UnityEngine;

public class CircleDrawer : MonoBehaviour
{
    // Teszteléshez:
    [SerializeField] Vector3 center;
    [SerializeField] float radius;

    void OnDrawGizmos()
    { 
        DrawCircle(transform.position, radius);
    }

    // A lényegi megoldás:
    void DrawCircle(Vector3 center, float radius)
    {
        float angle = 0;
        Vector3 previous = GetCirclePoint(center, radius, angle);
        
        int steps = 30; // Hány kis egyenesből rajzolom ki a kört
        for (int i = 1; i <= steps; i++)
        {
            angle += 2 * Mathf.PI / steps; // Növelem a szöget
            Vector3 current = GetCirclePoint(center, radius, angle);
            Gizmos.DrawLine(previous , current);
            previous = current;
        }
    }
    
    // Segédmetódus a kör egy pontjának kiszámolására
    Vector3 GetCirclePoint(Vector3 center, float radius, float angle)
    {
        float x = Mathf.Cos(angle);
        float y = Mathf.Sin(angle);
        return center + new Vector3(x, y, 0) * radius;
    }
}
using UnityEngine;

public class CircleSliceDrawer : MonoBehaviour
{
    // Teszteléshez:
    [SerializeField] Vector3 center;
    [SerializeField] float radius = 10;
    [SerializeField] float startAngle = 0, endAngle = 360;

    void OnDrawGizmos()
    { 
        DrawCircleSlice(transform.position, radius);
    }

    // A lényegi megoldás:
    void DrawCircleSlice(Vector3 center, float radius)
    {
        int steps = 60; // Hány kis egyenesből rajzolom ki a kört
        
        Vector3 previousPoint = GetCirclePoint(center, radius, startAngle);
        float allAngle = endAngle - startAngle;
        float step = Mathf.Sign(allAngle) * 360f / steps;
        float angleDone = 0;
        
        // Egyik szár kirajzolása:
        if (Mathf.Abs(allAngle) < 360)
            Gizmos.DrawLine(previousPoint, center);
        
        for (int i = 1; i <= steps; i++)
        {
            angleDone += step; // Növelem a szöget
            
            // Nem lépem túl az határt egyik irányba sem.
            if (Mathf.Abs(angleDone) > Mathf.Abs(allAngle))
                angleDone = allAngle;
            
            float angle = startAngle + angleDone;
            Vector3 cur = GetCirclePoint(center, radius, angle);
            Gizmos.DrawLine(previousPoint, cur);
            previousPoint = cur;
            
            if(angleDone == allAngle)
                break;
        }
        
        // Másik szár kirajzolása:
        if (Mathf.Abs(allAngle) < 360)
            Gizmos.DrawLine(previousPoint, center);
    }
    
    // Segédmetódus a kör egy pontjának kiszámolására
    Vector3 GetCirclePoint(Vector3 center, float radius, float angle)
    {
        float angleInRadians = angle * Mathf.Deg2Rad;
        float x = Mathf.Cos(angleInRadians);
        float y = Mathf.Sin(angleInRadians);
        return center + new Vector3(x, y, 0) * radius;
    }
}
using UnityEngine;

[ExecuteAlways]                         // Az update Play módon kívül is lefut
[RequireComponent(typeof(Camera))]      // Csak kamerával használható
public class DollyZoom : MonoBehaviour
{ 
	[SerializeField] new Camera camera;          // A kamera, amivel dolgozunk
	[SerializeField] Transform target;           // A cél, amit követünk
	[SerializeField] Vector3 offset;             // A célpont pozíciójának eltolása
	[SerializeField] float targetScale = 1;      // A célpont mérete
	[SerializeField] float targetDistance = 5f;  // A célpont távolsága a kamerától
	
	void OnValidate()
	{
		if (camera == null)
		camera = GetComponent<Camera>();
	}
	
	void Update()
	{
		if(target == null)
			return;
		
		// A kamera fieldOfView-ját és a pozícióját beállítjuk:
		camera.fieldOfView =GetFieldOfView();
		Vector3 targetPosition = target.position + offset;
		Vector3 distanceVector = transform.forward * targetDistance;
		transform.position = targetPosition - distanceVector;
	}
	
	// publikus lekérdező metódusok:
	public float GetTargetDistance()
	{
		return targetDistance;
	}
	
	public float GetFieldOfView()
	{
		return
			2 * Mathf.Atan(targetScale * 0.5f /  targetDistance) * Mathf.Rad2Deg;
	}
	
	public float GetScale()
	{
		return targetScale;
	}
	
	// publikus beállító metódusok:
	public void SetTargetDistance(float distance)
	{
		targetDistance = distance;
	} 
	
	public void SetFieldOfView(float fieldOfView)
	{
		targetDistance = 
			0.5f * targetScale / Mathf.Tan(fieldOfView * 0.5f * Mathf.Deg2Rad);
	}
	
	public void SetScale(float scale)
	{
		targetScale = scale;
	}
}
using UnityEngine;

public class ClosestFollower : MonoBehaviour
{
    [SerializeField] Transform[] transforms;
    [SerializeField] float speed = 1;

    void Update()
    {
        Vector3 currentPosition = transform.position;
        Transform closest = Closest(currentPosition, transforms);

        if (closest != null)
        {
            transform.position = Vector3.MoveTowards(
                currentPosition,
                closest.position,
                speed * Time.deltaTime);
        }
    }

    Transform Closest(Vector3 selfPosition, Transform[] transforms)
    {
        if (transforms == null || transforms.Length == 0)
            return null;
        
        if (transforms.Length == 1)
            return transforms[0];

        Transform closest = transforms[0];
        float minDist = 
					Vector3.Distance(selfPosition, transforms[0].position);
        
        for (int index = 1; index < transforms.Length; index++)
        {
            Transform t = transforms[index];
            float dist = Vector3.Distance(selfPosition, t.position);
            if (dist < minDist)
            {
                closest = t;
                minDist = dist;
            }
        }

        return closest;
    }

    void OnDrawGizmos()
    {
        Vector3 currentPosition = transform.position;
        Transform closest = Closest(currentPosition, transforms);
        
        if(closest!= null)
            Gizmos.DrawLine(currentPosition, closest.position);
    }
}
using UnityEngine;

[ExecuteAlways]
public classLockChildrenUnder: MonoBehaviour
{
    voidUpdate()
    {
        float y = transform.position.y;
        foreach (Transform child in GetComponentsInChildren<Transform>())
        {
            Vector3 childPos = child.position;
            if (childPos.y < y)
            {
                childPos.y = y;
                child.position = childPos;
            }
        }
    }
}
using UnityEngine;

public classChildRotator: MonoBehaviour
{
    [SerializeField] floatbaseAngularSpeed= 1f;

    void Update()
    {
        foreach (Transform child in GetComponentsInChildren<Transform>())
        {
            if (child.GetComponent<MeshRenderer>() != null)
            {
                float angularSpeed = baseAngularSpeed;
								
								//Bónusz feladat:
								angularSpeed /= Vector3.Distance(child.position, transform.position);

                child.Rotate(0, angularSpeed * Time.deltaTime, 0);
            }
        }
    }
}
using UnityEngine;

public class CloseObjects : MonoBehaviour
{
    [SerializeField] float maxDistance = 5f;

    void OnDrawGizmos()
    {
        Transform[] all = FindObjectsOfType<Transform>();
        Gizmos.color = Color.red;
        foreach (Transform t in all)
        {
						float distance = transform.position, t.pos;
            if (distance  < maxDistance)
                Gizmos.DrawLine(transform.position, t.position);
        }
    }
}
using System.Collections.Generic;
using UnityEngine;

public class KeepInLine : MonoBehaviour
{ 
    [SerializeField] List<Transform> objects; 
    
    void Update()
    {
        if(objects == null || objects.Count <= 2)
            return;
        
        Vector3 start = objects[0].position;
        Vector3 end = objects[objects.Count - 1].position;
        
        for (int i = 1; i < objects.Count-1; i++)
        {
						float rate = i / (float)(objects.Count - 1);
            objects[i].position = Vector3.Lerp(start, end, rate);
        }
    }
}
using System.Collections.Generic;
using UnityEngine;

public class PathMoverPingPong : MonoBehaviour
{
		// Útvonal
    [SerializeField] List<Vector3> path = new List<Vector3>
    {
        new Vector3(1,1,0),
        new Vector3(1,-1,0),
        new Vector3(-1,-1,0),
        new Vector3(-1,1,0),
    };
	  
		// Sebesség
    [SerializeField] float speed = 1f;

		// Előre halad-e? (A következő pont a lista következő eleme vagy előző)
    [SerializeField] bool movingForward = true; 
    
		// Aktuális index (Hol tartunk épp?)
    int _currentIndex;
 
    void Start()
    {
				// Kezdőiránytól függően bepozicionáljuk a testet.
        if (path != null && path.Count > 0)
        {
            _currentIndex = movingForward ? 0 : path.Count - 1;
            transform.position = path[_currentIndex];
        }
    }

    void Update()
    { 
				// Következő célpont indexe
        int nextIndex =  movingForward ? _currentIndex + 1 : _currentIndex;
        nextIndex = Mathf.Clamp(nextIndex, 0, path.Count - 1);
        Vector3 nextPoint = path[nextIndex];
         
				// Move Towards metósus
        Vector3 position = Vector3.MoveTowards(transform.position, nextPoint, speed * Time.deltaTime);
        transform.position = position;
        
        if (position == nextPoint) // Ha elértem egy ponthoz
        {
            if (movingForward)
                _currentIndex++;
            else
                _currentIndex--;
            
						// Ha a pályavégére értem valamilyenirányba, megfordulok.
            if (nextIndex >= path.Count-1)
                movingForward = false;
            if (nextIndex <= 0)
                movingForward = true;
        }
    }
    
    void OnDrawGizmos()
    {
        for (int i = 0; i < path.Count - 1; i++)
            Gizmos.DrawLine(path[i], path[i + 1]);
    }
}
using System.Collections.Generic;
using UnityEngine;

public class PathMoverLoop : MonoBehaviour
{
    // Útvonal
    [SerializeField]
    List<Vector3> path = new List<Vector3>
    {
        new Vector3(1,1,0),
        new Vector3(1,-1,0),
        new Vector3(-1,-1,0),
        new Vector3(-1,1,0),
    };

    // Sebesség
    [SerializeField] float speed = 1f;

    // Előre halad-e? (A következő pont a lista következő eleme vagy előző)
    [SerializeField] bool movingForward = true;

    // Aktuális index (Hol tartunk épp?)
    int currentIndex;

    void Start()
    {
        // Kezdőiránytól függően bepozicionáljuk a testet.
        currentIndex = 0;
        if (path != null && path.Count > 0)
            transform.position = path[currentIndex];
    }

    void Update()
    {
        // Következő célpont
        int nextIndex = movingForward ? currentIndex + 1 : currentIndex;
        Vector3 nextPoint = path[nextIndex];

        // Move Towards metósus
        Vector3 position = Vector3.MoveTowards(transform.position, nextPoint, speed * Time.deltaTime);
        transform.position = position;

        if (position == nextPoint) // Ha elértem egy ponthoz
        {
            if (movingForward)
            {
                currentIndex++;
                // Túlhaladás lekezelése
                currentIndex %= path.Count;
            }
            else
            {
                currentIndex--;
                // Túlhaladás lekezelése
                if (nextIndex < 0)
                    nextIndex += path.Count;
            }
        }
    }


    void OnDrawGizmos()
    {
        if (path.Count < 2)
            return;

        for (int i = 0; i < path.Count - 1; i++)
            Gizmos.DrawLine(path[i], path[i + 1]);
        Gizmos.DrawLine(path[path.Count - 1], path[0]);
    }
}
using UnityEngine;

public class CircleDrawer : MonoBehaviour
{
    // Teszteléshez:
    [SerializeField] Vector3 center;
    [SerializeField] float radius;

    void OnDrawGizmos()
    { 
        DrawCircle(transform.position, radius);
    }

    // A lényegi megoldás:
    void Vector3[] GetCircle(Vector3 center, float radius, int steps)
    {
				Vector3[] points = new Vector3[steps];
        float angle = 0;
        
        for (int i = 0; i < steps; i++)
        {
            angle += 2 * Mathf.PI / steps; // Növelem a szöget
            points[i] = GetCirclePoint(center, radius, angle);
        }
    }
    
    // Segédmetódus a kör egy pontjának kiszámolására
    Vector3 GetCirclePoint(Vector3 center, float radius, float angle)
    {
        float x = Mathf.Cos(angle);
        float y = Mathf.Sin(angle);
        return center + new Vector3(x, y, 0) * radius;
    }

		// Gizmó rajzoló metódus
		void DrawCircle(Vector3 center, float radius)
		{
      int steps = 30; // Hány kis egyenesből rajzolom ki a kört
			Vector3 points = GetCircle(center, radius, steps)
			for(int i = 0; i < points; i++)
			{
				Vector3 p1 = points[i];
				Vector3 p2 = points[(i+1) % points];
				Gizmos.DrawLine(p1, p2);					
			}
		}
}
public class Spiral : MonoBehaviour
{
	[SerializeField, Min(0)] float length;
	[SerializeField, Min(0)] float radius;
	[SerializeField, Min(0)] float fullAngle;
	[SerializeField, Min(2)] int steps;

	public Vector3[] GetPoints()
	{
		Vector3 center = transform.position;
		Vector3 dir = transform.up;
		Vector3 centerStart = center - dir * length / 2;
		Vector3 lengthVector = dir * length;

		Vector3 p1 = transform.right * radius;
		Vector3 p2 = transform.forward * radius;

		Vector3[] points = new Vector3[steps];

		float fullAngleRad = fullAngle * Mathf.Deg2Rad;

		for (int i = 0; i < steps; i++)
		{
			float t = i / (steps - 1f);
			float angle = t * fullAngleRad;
			float x = Mathf.Cos(angle);
			float y = Mathf.Sin(angle);
			Vector3 point = centerStart + p1 * x + p2 * y + lengthVector * t;
			points[i] = point;
		}

		return points;
	}
}
public class BackAndForth : MonoBehaviour
{
	[SerializeField] Transform a, b;
	[SerializeField] float speed;

	Transform nextTarget;

	void Start()
	{
	  // Az első célont legye a "b"
		nextTarget = b;
	}

	void Update()
	{
	  // Mozgatja a GameObject-et a következő célponthoz a sebesség és az idő alapján
    transform.position = Vector3.MoveTowards(transform.position, nextTarget.position, speed * Time.deltaTime);

    // Ellenőrzi, hogy elértük-e a következő célponthoz
    if (transform.position == nextTarget.position)
	    // Ha elértük, akkor váltunk a következő célpontra
      nextTarget = nextTarget == a ? b : a;
	}
}
public class BackAndForth : MonoBehaviour
{
    [SerializeField] Transform a, b;
    [SerializeField] float frequency = 1f;    // Másodpercenkénti hány teljes hullámot tegyen meg

    void Update()
    {
        float t= Time.time * frequency;            
        t = Mathf.Sin(t * Mathf.PI * 2);        // -1 és 1 közötti értéket ad vissza
        t = t / 2 + 0.5f;                       // 0 és 1 közötti értékre alakítjuk
        transform.position = Vector3.Lerp(a.position, b.position, t);     // Lineáris interpoláció a két pont között t arányban
    }
}
public class BackAndForth : MonoBehaviour
{
    [SerializeField] Transform a, b;
    [SerializeField] float frequency = 1f;    // Másodpercenkénti hány teljes hullámot tegyen meg
    [SerializeField, Range(0,1)] float exponent = 0.5f;    // A szinusz függvény hatványa

    void Update()
    {
        float phase = Time.time * frequency;            // Fázis
        float t = Mathf.Sin(phase * Mathf.PI * 2);      // -1 és 1 közötti értéket ad vissza

        t = Mathf.Pow(Mathf.Abs(t), exponent) * Mathf.Sign(t); // Hatványozás

        t = t / 2 + 0.5f;                               // 0 és 1 közötti értékre alakítjuk
        transform.position = Vector3.Lerp(a.position, b.position, t);     // Lineáris interpoláció a két pont között t arányban
    }
}
using System;
using UnityEngine;

public class ChildRotator : MonoBehaviour
{
    [SerializeField] float rotationSpeed = 360;
    [SerializeField] float minDistance = 2;
    [SerializeField] float maxDistance = 3;
    [SerializeField] float distanceFrequency = 1;

    float baseAngleDeg = 0;
    float distancePhaseRad = 0;

    void Update()
    {
        Vector3 center = transform.position;

        baseAngleDeg += Time.deltaTime * rotationSpeed;
        distancePhaseRad += Time.deltaTime * 2 * Mathf.PI * distanceFrequency;

        float distance01 = (Mathf.Sin(distancePhaseRad) + 1) / 2;
        float distance = Mathf.Lerp(minDistance, maxDistance, distance01);

        for (int i = 0; i < transform.childCount; i++)
        {
            Transform child = transform.GetChild(i);
            float phase01 = (float)i / transform.childCount;
            float angleDeg = baseAngleDeg + (phase01 * 360);

            float angleRad = angleDeg * Mathf.Deg2Rad;
            Vector3 direction = new(Mathf.Cos(angleRad), Mathf.Sin(angleRad));
            child.position = center + (direction * distance);
        }
    }
}