10/05/2023
Skalering af din 2D-spilskærm i Unity: En omfattende guide
At sikre, at dit 2D-spil ser godt ud på tværs af et bredt udvalg af mobile enheder, kan være en udfordring. Forskellige skærmstørrelser, opløsninger og billedformater kan føre til frustrerende problemer som sorte bjælker (marginer) øverst og nederst eller billeder, der zoomes for meget ind. Dette er et almindeligt problem for spiludviklere, der arbejder med Unitys 2D-system, især når man forsøger at opnå et konsistent visuelt udtryk på tværs af alle platforme. Lad os dykke ned i, hvordan du løser disse skalering- og billedformatsudfordringer.

Forståelse af Unitys Kamerasystem til 2D
I Unity, når du arbejder med 2D-spil, bruger du typisk et ortografisk kamera. Ortografiske kameraer projicerer verden uden perspektiv, hvilket betyder, at objekter forbliver samme størrelse uanset deres afstand fra kameraet. Kameraets vigtigste indstilling for skalering er `orthographicSize`. Denne værdi definerer, hvor meget af den vertikale verden der er synlig. En højere `orthographicSize` betyder, at du ser mere af verden (og objekter ser mindre ud), mens en lavere værdi betyder, at du ser mindre af verden (og objekter ser større ud).
Problemet opstår, fordi mobile enheder har varierende billedformater. Et typisk 16:9-format (bredformat) vil have mere vandret plads end et 4:3-format (ældre skærme). At skalere din spilskærm til at passe perfekt til alle disse formater kræver en intelligent tilgang.
Almindelige Fejl og Løsninger
De scripts, du har prøvet, forsøger begge at tackle problemet med at justere kameraets `orthographicSize` baseret på skærmens bredde og højde. Lad os analysere dem:
Script 1: MatchWidth
Dette script forsøger at matche en bestemt `sceneWidth` (25 enheder i dit tilfælde). Det beregner derefter den ønskede `desiredHalfHeight` baseret på forholdet mellem `sceneWidth` og `Screen.width` ganget med `Screen.height`.
[ExecuteInEditMode] [RequireComponent(typeof(Camera))] public class MatchWidth: MonoBehaviour { public float sceneWidth = 25; Camera _camera; void Start() { _camera = GetComponent(); } void Update() { float unitsPerPixel = sceneWidth / Screen.width; float desiredHalfHeight = 0.5f * unitsPerPixel * Screen.height; camera.orthographicSize = desiredHalfHeight; } } Problemet her: Som du nævnte, resulterer dette ofte i mellemrum øverst og nederst. Dette skyldes, at scriptet prioriterer at matche bredden. Hvis enhedens billedformat er bredere end din definerede `sceneWidth`, vil der være plads i højden. Hvis enhedens billedformat er smallere, vil der være plads i siderne.
Script 2: ChangeScreenSizeBasedonDevice
Dette script forsøger en anden tilgang, hvor det beregner et `orthoWidth` baseret på en defineret `screenHeight` og `screenWidth` og derefter justerer `orthographicSize` baseret på `targetAspect`.
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ChangeScreenSizeBasedonDevice: MonoBehaviour { public float screenHeight = 1920f; public float screenWidth = 1080f; public float targetAspect = 9f / 16f; // Forventet bredformat public float orthographicSize; private Camera mainCamera; void Start() { mainCamera = Camera.main; orthographicSize = mainCamera.orthographicSize; // Beregner den ønskede bredde baseret på mål-billedformatet float orthoWidth = orthographicSize / screenHeight * screenWidth; orthoWidth = orthoWidth / (targetAspect / mainCamera.aspect); Camera.main.orthographicSize = (orthoWidth / Screen.width * Screen.height); } } Problemet her: Dette script kan føre til, at spillet zoomes for meget ind. Dette sker sandsynligvis, fordi beregningen af `orthoWidth` og efterfølgende justering af `orthographicSize` ikke tager højde for, hvordan man bedst opretholder det visuelle indhold uden beskæring.
En Bedre Tilgang: Match Height eller Width Strategien
Den mest almindelige og effektive måde at håndtere dette på i Unity 2D er at vælge enten at matche bredden eller matche højden og derefter tillade, at den anden dimension tilpasser sig. Formålet er at sikre, at alt dit spilindhold er synligt, uden at det bliver beskåret.
For et spil i landskabsformat, som du har, er det ofte bedst at prioritere, at hele bredden er synlig. Dette betyder, at du skal justere `orthographicSize` baseret på den bredeste mulige visning, og derefter acceptere, at der kan være tom plads i toppen og bunden på enheder med et smallere billedformat.
Her er et forbedret script, der implementerer denne strategi:
using UnityEngine; [ExecuteInEditMode] [RequireComponent(typeof(Camera))] public class ResponsiveCamera: MonoBehaviour { [Tooltip("Den ønskede bredde af spilverdenen i enheder.")] public float targetWidth = 10.8f; // Eksempel: Hvis din 3D-model eller sprite er 10.8 enheder bred ved 1920x1080 private Camera cam; void Awake() { cam = GetComponent(); } void Update() { // Beregn den ønskede ortografiske størrelse baseret på bredden // OrthographicSize * 2 = synlig højde // (OrthographicSize * 2) * aspect = synlig bredde // Så: OrthographicSize = synlig bredde / aspect / 2 float desiredOrthoSize = targetWidth / cam.aspect / 2.0f; cam.orthographicSize = desiredOrthoSize; } // Du kan også tilføje en funktion til at tilpasse sig højden, hvis det er nødvendigt, // men for landskab er bredde-match ofte bedre. } Hvordan dette script virker:
- `targetWidth`: Du definerer den bredde, du ønsker, at din spilverden skal have. Dette er ofte baseret på dine designovervejelser eller den bredde, dine vigtigste elementer passer ind i. For eksempel, hvis du har en sprite, der er 10.8 Unity-enheder bred, og du vil have den til at fylde skærmens bredde på en standard 16:9-enhed, sætter du `targetWidth` til 10.8.
- `cam.aspect`: Dette er en indbygget Unity-egenskab, der giver det aktuelle billedformat for kameraet (bredde / højde).
- Beregning af `desiredOrthoSize`: Formlen `targetWidth / cam.aspect / 2.0f` sikrer, at uanset enhedens billedformat, vil den definerede `targetWidth` altid blive vist fuldt ud på skærmen. Hvis billedformatet er bredere end dit mål, vil kameraet automatisk se mere lodret, hvilket resulterer i mellemrum øverst og nederst. Hvis billedformatet er smallere, vil kameraet se mindre lodret, men hele bredden er stadig synlig, hvilket kan føre til beskæring i siderne (hvilket normalt er uønsket i 2D-spil).
Justering af Billedformat i Unitys Project Settings
Udover scripts kan du også bruge Unitys indbyggede værktøjer til at simulere forskellige billedformater og teste din skalering.
Gå til File > Build Settings... og klik på Player Settings.... Under sektionen Resolution and Presentation kan du finde indstillinger for Default Orientation (som du skal sætte til Landscape) og Supported Aspect Ratios. Du kan også bruge Game View vinduet i Unity og vælge forskellige forudindstillede billedformater fra rullemenuen øverst.
| Metode | Fordele | Ulemper | Bedst til |
|---|---|---|---|
| Match Width (som i Script 1) | Sikrer, at bredden altid passer. | Kan give mellemrum øverst/nederst på smalle enheder. | Landskabsspil, hvor horisontal plads er vigtig. |
| Match Height | Sikrer, at højden altid passer. | Kan give mellemrum i siderne på brede enheder. | Portrætsspil, hvor vertikal plads er vigtig. |
| Uniform (Bevarer begge dimensioner) | Ingen beskæring, men kan give mellemrum i begge retninger. | Mindst optimal pladsudnyttelse. | Meget specifikke UI-layout, hvor plads ikke er et problem. |
| Expand (Fyld skærmen, beskær om nødvendigt) | Fuld skærm uden mellemrum. | Beskærer indhold på nogle enheder. | Spil, hvor visuelt indhold er mindre kritisk end at fylde skærmen. |
Håndtering af UI-Elementer
Når du skalerer hovedkameraet, skal du også overveje, hvordan dine UI-elementer opfører sig. Unitys UI-system har en Canvas Scaler komponent, der kan hjælpe med at skalere UI i forhold til skærmstørrelsen. Sørg for, at din Canvas Scaler er konfigureret korrekt, typisk med UI Scale Mode sat til Scale With Screen Size.
Når du bruger denne tilstand, kan du definere en Reference Resolution (f.eks. 1920x1080) og et Match-slider. En `Match` værdi på 0 betyder, at skaleringen primært baseres på bredden, mens 1 betyder, at den primært baseres på højden. For et landskabsspil vil en værdi omkring 0.5 ofte give en god balance, hvor både bredde og højde tages i betragtning.
Din Opdatering og Løsning
I din UPDATE 2 nævner du en løsning, der involverer en `GameManager` og skalering af et specifikt GameObject (en "Cube").
void Start() { float screenWidth = GameManager.Instance.getScreenWidth(); float screenHeight = GameManager.Instance.getScreenHeight(); if (gameObject.name == "Cube") { transform.localScale = new Vector3(screenWidth / 4, screenHeight, -1); transform.position = new Vector3(transform.position.x, 0, transform.position.z); } } Denne tilgang er mere egnet til at skalere individuelle objekter eller UI-elementer for at passe til skærmen, snarere end at justere hele spillets synsfelt via kameraet. Ved at indstille `transform.localScale` baseret på `screenWidth` og `screenHeight` kan du få objekter til at fylde bestemte dele af skærmen.
For eksempel, hvis du vil have en "Cube" til at fylde hele bredden af skærmen og samtidig være centreret vertikalt, ville dette script (når det er knyttet til den pågældende Cube) kunne fungere, forudsat at `screenWidth` og `screenHeight` repræsenterer den aktuelle enheds dimensioner i spillets enheder.
Vigtigt: Denne metode til at skalere individuelle objekter fungerer bedst, når du har et fast kamera og ønsker at placere elementer specifikt. Hvis du derimod ønsker, at hele spilverdenen skal skalere responsivt, er det kameraets `orthographicSize`, der skal justeres.
Hvordan Fjerner Man Mellemrum?
For at fjerne mellemrum øverst og nederst i et landskabsspil, skal du sikre dig, at dit kamera altid matcher bredden af den tilgængelige skærm.
Det vil sige, at hvis du definerer en ønsket bredde for din spilverden (f.eks. 10.8 enheder), skal kameraets `orthographicSize` justeres, så denne bredde altid passer, uanset billedformatet. Når billedformatet bliver smallere end din definerede bredde, vil der uundgåeligt opstå mellemrum i toppen og bunden.
Hvis du bruger det forbedrede `ResponsiveCamera`-script ovenfor, og du har sat `targetWidth` korrekt, så vil bredden altid passe. Mellemrummene i toppen og bunden er det kompromis, du laver for at sikre, at alt indhold er synligt på bredere skærme uden at blive beskåret.
Hvis du derimod ønsker at fylde hele skærmen og acceptere potentiel beskæring, skal du justere din strategi. Du kan enten:
- Bruge et script, der prioriterer at matche højden (for landskab, dette ville føre til beskæring i siderne på brede skærme).
- Bruge Unitys Expand-tilstand i Canvas Scaler, hvis du udelukkende arbejder med UI.
- Sætte dit kamera til at matche højden og derefter skalere dine spilobjekter manuelt for at fylde bredden, hvilket kan være komplekst.
Konklusion
At opnå perfekt skalering på tværs af alle mobile enheder kræver ofte en afvejning. For 2D-landskabsspil er det mest almindelige og brugervenlige at matche bredden og acceptere potentielle mellemrum i toppen og bunden på smallere skærme. Brug et script, der dynamisk justerer kameraets `orthographicSize` baseret på en defineret `targetWidth` og enhedens `aspect ratio`.
Husk at teste grundigt på forskellige enheder eller ved hjælp af Unitys Game View med forskellige billedformater for at sikre, at dit spil ser ud og fungerer som tiltænkt. En veludført skaleringstrategi er afgørende for en god brugeroplevelse.
Ofte Stillede Spørgsmål (FAQ)
Spørgsmål: Hvorfor ser mit spil anderledes ud på forskellige telefoner?
Svar: Dette skyldes forskelle i skærmstørrelser og billedformater. Enheder med et bredere billedformat (f.eks. 18:9) viser mere af verden enten vandret eller lodret end enheder med et smallere billedformat (f.eks. 4:3), hvis ikke korrekt skaleret.
Spørgsmål: Hvad er det bedste `orthographicSize` for mit 2D-spil?
Svar: Der er ikke én universel bedste værdi. Det afhænger af dine spilobjekters størrelse og dit design. Du skal indstille `orthographicSize` (eller bruge et script til at beregne den), så dine vigtigste spilelementer passer komfortabelt ind i den ønskede bredde eller højde.
Spørgsmål: Hvordan kan jeg sikre, at mine UI-elementer også skalerer korrekt?
Svar: Brug Canvas Scaler komponenten på din Canvas. Sæt UI Scale Mode til Scale With Screen Size og juster Reference Resolution og Match-slideren for at opnå den ønskede skalering.
Spørgsmål: Skal jeg bruge `ExecuteInEditMode`?
Svar: `ExecuteInEditMode` gør, at scriptet kører i editoren, hvilket er nyttigt til at se skaleringen live. Men husk at fjerne det til produktion, hvis det ikke er nødvendigt, eller sørg for, at det kun kører i `Start()` eller `Awake()` for at undgå unødvendig belastning.
Spørgsmål: Hvad er forskellen på `camera.aspect` og `Screen.width / Screen.height`?
Svar: `camera.aspect` er billedformatet af selve kameraets viewport, som kan være anderledes end den faktiske skærms billedformat, hvis kameraet ikke fylder hele skærmen. `Screen.width / Screen.height` giver det faktiske billedformat af den aktuelle enheds skærm.
Hvis du vil læse andre artikler, der ligner Tilpas din 2D-spilskærm til alle enheder, kan du besøge kategorien Teknologi.
