Arendaja jaoks on kaamera mängu arendamise üks alustalasid. Alates oma mänguvaate näitamisest malerakenduses kuni kaamera liikumise juhtimise juhtimiseni 3D AAA mängus kinematograafiliste efektide saamiseks, kasutatakse kaameraid põhimõtteliselt igas videomängus, mis kunagi tehtud on, isegi enne, kui neid tegelikult kaamerateks nimetatakse.
Selles artiklis selgitan, kuidas 2D-mängude jaoks kaamerasüsteemi kujundada, ja selgitan ka mõningaid punkte selle kohta, kuidas seda kõige populaarsemates mängumootorites rakendada, Ühtsus .
Kaamerasüsteem, mille koos kujundame, on modulaarne ja laiendatav. Sellel on põhituum, mis koosneb mitmest komponendist, mis tagab põhifunktsionaalsuse, ja seejärel erinevatest komponentidest / efektidest, mida saab valikuliselt kasutada, sõltuvalt konkreetsest olukorrast.
Siin ehitatav kaamerasüsteem on suunatud 2D-platvormimängudele, kuid seda saab hõlpsasti laiendada ka muud tüüpi 2D-mängudele, 2,5D-mängudele või isegi 3D-mängudele.
Jagan kaamera funktsionaalsuse kahte põhirühma: kaamera jälgimine ja kaamera efektid.
Suurem osa kaamera liikumisest, mida siin teeme, põhineb jälgimisel. See on objekti, antud juhul kaamera, võime jälgida teisi objekte, kui nad mängustseenis liiguvad. Rakendatavad jälgimistüübid lahendavad mõned levinumad stsenaariumid, mis 2d platvormimängudes ette tulevad, kuid neid saab laiendada uut tüüpi jälgimisega muude konkreetsete stsenaariumide korral.
Rakendame mõningaid lahedaid efekte, nagu kaamera värisemine, kaamera suum, kaamera tuhmumine ja värvikiht.
Looge Unity's uus 2D-projekt ja importige standardvarad, eriti RobotBoy-märk. Järgmisena looge jahvatuskast ja lisage tähemärk. Peaksite olema võimeline oma tegelasega oma praeguses stseenis kõndima ja hüppama. Veenduge, et kaamera on seatud ortograafilisele režiimile (vaikimisi on see seatud Perspektiivile).
Järgmine skript lisab meie peamisele kaamerale põhilise jälgimiskäitumise. Skript peab olema komponentidena lisatud teie stseeni põhikaamerale ja see paljastab välja jälgitava sihtobjekti määramiseks. Seejärel tagab skript, et kaamera x- ja y-koordinaadid on jälgitava objektiga samad. Kogu see töötlemine toimub värskendusetapi ajal.
[SerializeField] protected Transform trackingTarget; // ... void Update() { transform.position = new Vector3(trackingTarget.position.x, trackingTarget.position.y, transform.position.z); }
Peategelase jälgimise võimaldamiseks lohistage RobotBoy märk oma stseenihierarhiast väljale „Jälgimise sihtmärk“ üle, mis on meie järgmise käitumisega avatud.
Kõik hea, kuid näeme piirangut otse nahkhiirelt: tegelane on alati meie stseeni keskmes. Näeme palju tegelase taga, mis on tavaliselt asjad, mis meid ei huvita, ja näeme liiga vähe sellest, mis meie tegelasel ees ootab, mis võib olla mängule kahjulik.
Selle lahendamiseks lisame skripti mõned uued väljad, mis võimaldavad kaamera asetada sihtmärgist kaugemale.
[SerializeField] float xOffset; [SerializeField] float yOffset; // ... void Update() { transform.position = new Vector3(trackingTarget.position.x + xOffset, trackingTarget.position.y + yOffset, transform.position.z); }
Allpool näete kahe uue välja võimalikku konfiguratsiooni:
Kaamera liikumine on üsna jäik ja tekitab ka pidevas keskkonna tajutavas liikumises osale mängijatest peapööritust. Selle parandamiseks lisame kaamera jälgimisel viivituse, kasutades lineaarset interpoleerimist, ja uue välja, et kontrollida, kui kiiresti kaamera paigale saabub pärast märgi positsiooni muutmist.
[SerializeField] protected float followSpeed; // ... protected override void Update() { float xTarget = trackingTarget.position.x + xOffset; float yTarget = trackingTarget.position.y + yOffset; float xNew = Mathf.Lerp(transform.position.x, xTarget, Time.deltaTime * followSpeed); float yNew = Mathf.Lerp(transform.position.y, yTarget, Time.deltaTime * followSpeed); transform.position = new Vector3(xNew, yNew, transform.position.z); }
Kuna teie aju ei ole meeldiv jälgida kogu aeg kaamerat koos tegelasega üles ja alla, tutvustame telgede lukustamist. See tähendab, et saame jälgida ainult ühe teljega. Seejärel eraldame oma jälgimiskoodi teljest sõltumatuks jälgimiseks ja võtame arvesse uusi lukustuslippe.
[SerializeField] protected bool isXLocked = false; [SerializeField] protected bool isYLocked = false; // ... float xNew = transform.position.x; if (!isXLocked) { xNew = Mathf.Lerp(transform.position.x, xTarget, Time.deltaTime * followSpeed); } float yNew = transform.position.y; if (!isYLocked) { yNew = Mathf.Lerp(transform.position.y, yTarget, Time.deltaTime * followSpeed); }
Nüüd, kui kaamera jälgib mängijat ainult horisontaalselt, piirdume ühe ekraani kõrgusega. Kui tegelane ronib mööda redelit või hüppab sellest kõrgemale, peame järgima. See, kuidas me seda teeme, on sõiduraja süsteemi kasutamine.
Kujutage ette järgmist stsenaariumi:
Tegelane on esialgu alumisel rajal. Kuigi tegelane jääb selle raja piiridesse, liigub kaamera ainult horisontaalselt sellel rajal, mida saame määrata.
Niipea kui tegelane siseneb teisele rajale, liigub kaamera sellele rajale ja jätkab sealt horisontaalset liikumist kuni järgmise rajavahetuseni.
Raja kujundamisel tuleb olla ettevaatlik, et vältida kiiret rajavahetust selliste tegevuste ajal nagu hüppamine, mis võib tekitada mängijas segadust. Rada tuleks muuta ainult siis, kui mängija tegelane kavatseb sellel mõnda aega püsida.
Radade tasemed võivad muutuda kogu mängu tasemel lähtuvalt disaineri konkreetsetest vajadustest või neid võib üldse katkestada ja nende asemele võib asuda mõni muu kaamera jälgimissüsteem. Seetõttu vajame rajavööndite täpsustamiseks mõningaid piirajaid.
Võimalik teostus on lisada rajale lihtsate objektidena sõidurajad. Süsteemi juurutamiseks kasutame ülaltoodud jälgimisskriptis nende Y-positsiooni koordinaate, mis on ühendatud Y-nihkega. Seetõttu pole nende positsioon X- ja Z-koordinaatidel oluline.
Lisage kaamerale LaneSystem klass koos jälgimisklassiga ja määrake rajaobjektid ettenähtud massiivi. Määrake mängija märk ka väljale Viide. Kuna viide asub sõiduraja ja teise raja vahel, kasutatakse kaamera positsioneerimiseks kahest alumist.
Ja LaneSystemi klass hoolitseb kaamera liikumise eest sõiduradade vahel, lähtudes võrdlusasendist. Järjekordi kiirust kasutatakse siin uuesti positsiooni interpoleerimiseks, et vältida sõidurea vahetamise liiga järsku:
[SerializeField] Transform reference; [SerializeField] List lanes; [SerializeField] float followSpeed = 5f; // ... void Update() { float targetYCoord = transform.position.y; if (lanes.Count > 1) { int i = 0; for (i = 0; i lanes[i].position.y) && (reference.position.y <= lanes[i + 1].position.y)) { targetYCoord = lanes[i].position.y; break; } } if (i == lanes.Count - 1) targetYCoord = lanes[lanes.Count - 1].position.y; } else { targetYCoord = lanes[0].position.y; } float yCoord = Mathf.Lerp(transform.position.y, targetYCoord, Time.deltaTime * followSpeed); transform.position = new Vector3(transform.position.x, yCoord, transform.position.z); }
See teostus ei ole WYSIWYG ja see on jäetud selliseks, nagu lugejale mõeldud harjutus.
Kaamera liikumine radadel on suurepärane, kuid mõnikord vajame kaamera lukustamist millegi külge, huvipunkti (HP) mängustseenis.
Seda on võimalik saavutada, kui konfigureerida selline HP stseenis ja kinnitada neile päästik-kokkupõrge. Alati, kui märk siseneb sellele päästikule, liigutame kaamerat ja püsime HP-l. Kui tegelane liigub ja lahkub siis POI päästikuolijast, jõuame tagasi teise jälgimistüübi juurde, tavaliselt tavapärase jälgimiskäitumise juurde.
Kaamera jälgimise lülitamise lukusõlmele ja tagasi saab teha kas lihtsa lüliti või virnasüsteemi abil, millele jälgimisrežiimid lükatakse ja hüpatakse.
Lukustussõlme konfigureerimiseks looge lihtsalt objekt (see võib olla tühi või nagu allpool oleval ekraanipildil, sprite) ja kinnitage sellele suur Circle Collider 2D komponent, nii et see tähistab ala, kus mängija viibib, kui kaamera fokuseerige sõlm. Võite valida mis tahes tüüpi kokkupõrke, valin siin näiteks Circle. Looge ka silt, mida saate hõlpsalt kontrollida, näiteks „CameraNode”, ja määrake see sellele objektile.
Lisage oma kaamera jälgimisskriptile järgmine atribuut:
public Transform TrackingTarget { get { return trackingTarget; } set { trackingTarget = value; } }
Seejärel kinnitage mängijale järgmine skript, mis võimaldab tal ajutiselt kaamera sihtmärgi teie valitud lukusõlmele lülitada. Skript mäletab ka oma eelmist sihtmärki, et saaks selle juurde tagasi pöörduda, kui mängija on päästikualast väljas. Võite seda jätkata, kui vajate, selle kogu korstnasse teisendada, kuid meie eesmärk, kuna me ei kattu mitme lukusõlmega, teeb seda. Pange tähele ka seda, et saate kaamera lukustuse käivitamiseks muuta Circle Collider 2D asukohta või uuesti lisada mis tahes muud tüüpi põrkeraudu. See on vaid näide.
public class LockBehavior : MonoBehaviour { #region Public Fields [SerializeField] Camera camera; [SerializeField] string tag; #endregion #region Private private Transform previousTarget; private TrackingBehavior trackingBehavior; private bool isLocked = false; #endregion // Use this for initialization void Start() { trackingBehavior = camera.GetComponent(); } void OnTriggerEnter2D(Collider2D other) { if (other.tag == tag && !isLocked) { isLocked = true; PushTarget(other.transform); } } void OnTriggerExit2D(Collider2D other) { if (other.tag == tag && isLocked) { isLocked = false; PopTarget(); } } private void PushTarget(Transform newTarget) { previousTarget = trackingBehavior.TrackingTarget; trackingBehavior.TrackingTarget = newTarget; } private void PopTarget() { trackingBehavior.TrackingTarget = previousTarget; } }
Kaamera suumi saab teostada kas kasutaja sisendil või animatsioonina, kui tahame keskenduda millelegi HP-le või kitsamale alale tasemel.
2D kaamera suumi saab Unity 3D-s saavutada kaamera ortograafilise suurusega manipuleerimisega. Järgmise skripti lisamine kaamera komponendina ja SetZoom-meetodi kasutamine suumiteguri muutmiseks annab soovitud efekti. 1.0 tähendab suumi puudumist, 0.5 tähendab kaks korda suumimist, 2 tähendab kaks korda suumimist jne.
[SerializeField] float zoomFactor = 1.0f; [SerializeField] float zoomSpeed = 5.0f; private float originalSize = 0f; private Camera thisCamera; // Use this for initialization void Start() { thisCamera = GetComponent(); originalSize = thisCamera.orthographicSize; } // Update is called once per frame void Update() { float targetSize = originalSize * zoomFactor; if (targetSize != thisCamera.orthographicSize) { thisCamera.orthographicSize = Mathf.Lerp(thisCamera.orthographicSize, targetSize, Time.deltaTime * zoomSpeed); } } void SetZoom(float zoomFactor) { this.zoomFactor = zoomFactor; }
Alati, kui peame oma mängus näitama maavärinat, plahvatust või muud efekti, on kaamera värisemise efekt kasuks.
Rakenduse näide selle kohta on saadaval GitHubis: gist.github.com/ftvs/5822103 . Rakendamine on üsna lihtne. Erinevalt teistest seni käsitletud mõjudest tugineb see väikesele juhuslikkusele.
Kui meie tase algab või lõpeb, on hääbumise või väljalülitamise efekt tore. Saame selle rakendada, lisades kogu ekraanile ulatuvasse paneeli mitte-interaktiivse kasutajaliidese tekstuuri. Esialgu oleme läbipaistvad, saame selle täita mis tahes värvi ja läbipaistmatusega või animeerida seda soovitud efekti saavutamiseks.
Siin on näide sellest konfiguratsioonist. Pange tähele, et kasutajaliidese paneeli objekt on määratud peamise kaameraobjekti alamale “Kaamera ülekate”. Kaamera ülekate paljastab skripti nimega ülekate, mis sisaldab järgmist:
[SerializeField] Image overlay; // ... public void SetOverlayColor(Color color) { overlay.color = color; }
Pimendava efekti saavutamiseks muutke ülekatte skripti, lisades interpolatsiooni SetOverlayColoriga määratud sihtvärvile nagu järgmises skriptis, ja määrake meie paneeli algvärviks Must (või Valge) ja sihtvärv oma ülekatte lõpliku värvini. FadeSpeed saate muuta vastavalt oma vajadustele, minu arvates on algajatele hea 0,8. FadeSpeed väärtus töötab aja muutjana. 1.0 tähendab, et see juhtub mitme kaadri jooksul, kuid ühe sekundi jooksul. 0.8 tähendab, et selle täitmiseks kulub tegelikult 1 / 0,8 = 1,25 sekundit.
public class Overlay : MonoBehaviour { #region Fields [SerializeField] Image overlay; [SerializeField] float fadeSpeed = 5f; [SerializeField] Color targetColor; #endregion void Update() { if (overlay.color != targetColor) { overlay.color = Color.Lerp(overlay.color, targetColor, Time.deltaTime * fadeSpeed); } } #region Public public void SetOverlayColor(Color color) { targetColor = color; } #endregion }
Selles artiklis olen püüdnud demonstreerida põhikomponente, mis on vajalikud teie mängu jaoks moodulse 2D-kaamerasüsteemi paigutamiseks, ja ka seda, milline on selle kujundamiseks vajalik mõttekomplekt. Loomulikult on kõigil mängudel oma erivajadused, kuid siin kirjeldatud põhise jälgimise ja lihtsate efektidega saate pika tee ja saate ka oma efektide rakendamise kava. Seejärel saate minna veelgi kaugemale ja pakkida kõik korduvkasutatavasse Unity 3D paketti, mille saate ka teistesse projektidesse üle kanda.
Kaamerasüsteemid on mängijatele õige atmosfääri edastamisel väga olulised. Hea võrdlus, mida mulle meeldib kasutada, on see, kui mõelda klassikalise teatri ja filmide erinevusele. Kaamerad ja filmid ise tõid stseenile nii palju võimalusi, et see kujunes lõpuks omapäi kunstiks, nii et kui te ei kavatse rakendada mõnda muud mängu “Pong”, peaksid edasijõudnud kaamerad olema teie valitud tööriist mis tahes mänguprojekt võtate nüüdsest ette.
Seotud: Ühtsus MVC-ga: kuidas oma mänguarendust tasemele viia