1. Nimm jetzt an unserem Uhans - 3. ADVENT - Gewinnspiel teil - Alle Informationen findest Du hier!

Spieleentwicklung - feste Auflösung oder Skalierung

Dieses Thema im Forum "Android Spiele Entwicklung" wurde erstellt von funcoder, 10.08.2010.

  1. funcoder, 10.08.2010 #1
    funcoder

    funcoder Threadstarter Erfahrener Benutzer

    Beiträge:
    218
    Erhaltene Danke:
    38
    Registriert seit:
    15.08.2009
    Hallo Zusammen,

    ich arbeite gerade an einem Strategiespiel mit Vogelperspektive auf eine Landschaft mit einzelnen Fahrzeuge. Die Fahrzeuge haben eine Ausmaße von 40x40 Pixel. Durch die Auflösung lassen sich Fahrzeuge auf meinem Hero (480x320 Pixel) ohne Probleme über den Touchscreen auswählen. Aber, wenn jemand das jetzt auf seinem Desire/Milestone mit annähernd doppelter Auflösung ausführt hat er ja schließlich auch nur noch die halbe Größe aufgrund der doppelt so hohen Pixeldichte und er wird sich schwer tun ein Fahrzeug noch vernünftig mit den Finger auswählen zu können. Rendern tu ich das ganze via Canvas.

    Deshalb die Frage:
    Ist es irgendwie Möglich das ich eine "Maximal Auflösung" festlegen tu, und bei Auflösungen darüber wird das gesamte zu rendernde Bild hochskaliert auf die doppelte Auflösung?

    Oder müssen es unbedingt Vektorgrafiken sein? Bzw. müssen alle Grafiken in verschiedenen Größen vorliegen?

    Ich wäre auch offen für eine andere Grafikschnittstelle oder ein andere 2D Rendering Framework, sollte dieses dafür eine Lösung bieten!

    Wie habt ihr sowas gelöst?

    Danke im Voraus

    mfg
    c0der
     
    Zuletzt bearbeitet: 10.08.2010
  2. wilco, 10.08.2010 #2
    wilco

    wilco Android-Hilfe.de Mitglied

    Beiträge:
    106
    Erhaltene Danke:
    32
    Registriert seit:
    10.08.2010
    Da gibt's jede Menge Möglichkeiten:

    1. Im Manifest Deiner App kannst Du angeben welche Auflösungen Deine App unterstützt:
    <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:anyDensity="true" android:resizeable="true"/>
    Wenn Du largeScreens und anyDensity auf "false" setzt gaukelt Android Deiner App auch auf Geräten mit höherer Auflösung vor sie würde auf einer mittleren Auflösung laufen. Das Gerät vergrößert dann einfach die von Deiner App erstellte Grafik so, daß sie auf den größeren Bildschirm passt.

    2. Definiere alle Layouts in Prozentanteilen der Bildschirmgröße. D.h. anstatt zu sagen ein Tile in Deiner Landschaft ist 40x40, sag einfach ein Tile ist 10% Bildschirmbreite mal 10% Bildschirmhöhe. Dabei musst Du natürlich aufpassen dass die Dimensionen nicht verzerrt werden. Soll ein Tile quadratisch sein, musst Du entweder Höhe oder Breite dann entsprechend anpassen.

    Für Option 2 musst Du natürlich auch Deine Grafiken entsprechend skalieren. Da gibt es auch zwei Möglichkeiten:
    2a. über die Funktion Bitmap.createScaledBitmap
    2b. Lass das Android erledigen. Beim Laden Deiner App werden alle Grafiken automatisch skaliert, je nachdem auf welchem Gerät sie geladen wird.
     
    funcoder bedankt sich.
  3. funcoder, 11.08.2010 #3
    funcoder

    funcoder Threadstarter Erfahrener Benutzer

    Beiträge:
    218
    Erhaltene Danke:
    38
    Registriert seit:
    15.08.2009
    Super! Vielen Dank wilco!Eine kleine Frage habe ich noch, wenn ich Tipp 1 anwenden tu, und die Grafiken automatisch hochskaliert werden, wie sieht es da mit den ansprechenden Koordinaten in Canvas aus.Also wenn ich beispielsweise auf Koordinate 10x10 eine 40x40 Pixel große Tile rendern lasse umfasst die Grafik den Bereich von 10x10 bis 50x50. Wenn jetzt dies auf einem hochauflösendem Display ausgeführt wird wo dies alles hochskaliert wird, kann ich dann immernoch in meinem App den Bereich (10x10 bis 50x50) abfragen ob dieser berührt worden ist oder ändert sich durch das hochskalieren zusätzlich auch die Koordinaten, da ja eigentlich die Grafik dann über einen "praktisch" größeren Bereich gerendert wird?Danke!
     
  4. MichaelS, 12.08.2010 #4
    MichaelS

    MichaelS Fortgeschrittenes Mitglied

    Beiträge:
    370
    Erhaltene Danke:
    51
    Registriert seit:
    14.08.2009
    Converting from dips to pixels

    In some cases, you will need to express dimensions in dip and then convert them to pixels. Imagine an application in which a scroll gesture is recognized after the user's finger has moved by at least 16 pixels. On a baseline screen, the user will have to move his finger by 16 pixels / 160 dpi = 1/10th of an inch (or 2.5 mm) before the gesture is recognized. On a device with a high (240) density display, the user will move his finger by only 16 pixels / 240 dpi = 1/15th of an inch (or 1.7 mm.) The distance is much shorter and the application thus appears more sensitive to the user. To fix this issue, the gesture threshold must be expressed in the code in dip and then converted to actual pixels.
    // The gesture threshold expressed in dip
    private static final float GESTURE_THRESHOLD_DIP = 16.0f;

    // Convert the dips to pixels
    final float scale = getContext().getResources().getDisplayMetrics().de nsity;
    mGestureThreshold = (int) (GESTURE_THRESHOLD_DIP * scale + 0.5f);

    // Use mGestureThreshold as a distance in pixels
     
  5. wilco, 12.08.2010 #5
    wilco

    wilco Android-Hilfe.de Mitglied

    Beiträge:
    106
    Erhaltene Danke:
    32
    Registriert seit:
    10.08.2010
    Mit Methode 1 wird Deiner App vom System vorgegaukelt sie laufe auf der regulären, mittleren Auflösung. D.h. auch wenn das Handy-Display tatsächlich 800 Pixel Höhe hat, erhält Deine App als Antwort auf die Frage "Wie hoch ist der Bildschirm" - canvas.getHeight() - den kleineren Wert. Du kannst mit dieser Methode mit absoluten Layout-Werten arbeiten. Android kümmert sich um die Skalierung. Das gilt für die Übermittlung von Koordinaten bei onTouch() genauso. Deine App denkt immer sie würde auf 320x480 laufen.

    Das Ganze hat den Nachteil daß Deine App auf Geräten mit höherer Auflösung pixelig aussieht, und z.B. bei den meisten Tablets ein dicker schwarzer Rand um Deinen App-Screen drumrum ist. Auf Geräten mit kleinerer Auflösung (Wildfire, Tattoo) läuft die App dann gar nicht.

    Die bessere Methode ist wirklich entweder alles in Density Independent Pixel auszudrücken, oder in Deinem Programm statt mit absoluten Werten mit Prozentzahlen zu arbeiten.

    Nimm z.B. ein Sudoku Spiel mit einem 9x9 Spielfeld. Wenn Du das anpassen willst, hole Dir die Höhe und Breite des Screens. Dein Feld soll quadratisch sein, also machst Du das folgende:

    //Hol Dir die Display-Dimensionen
    SpielfeldBreite = getWidth();
    SpielfeldHöhe = getHeight();

    //Mach das Feld quadratisch
    if (SpielfeldBreite>SpielfeldHöhe) SpielfeldBreite=SpielfeldHöhe;
    else if (SpielfeldBreite<SpielfeldHöhe) SpeilfeldHöhe=SpeilfeldBreite;

    //Stell sicher daß die Einzelfelder alle gleich groß werden können. Du hast bei Sudoku 9 Zeile x 9 Spalten, also muss die Feldbreite und Höhe jeweils ohne Rest durch 9 teilbar sein.
    SpielfeldBreite=SpielfeldBreite-(SpielfeldBreite%9);
    SpielfeldHöhe=SpielfeldHöhe-(SpielfeldHöhe%9);

    //Ermittel die Dimensionen eines einzelnen Felds
    EinzelnesFeldBreite = SpielfeldBreite/9;
    EinzelnesFeldHöhe = SpielfeldHöhe/9;

    Statt einer hardcodierten Bildschirmauflösung von 320x480, verwendest Du dann die so ermittelten Werte.

    Deine Grafiken die Du im resource Folder hast kannst Du mit Bitmap.createScaledBitmap() auf die neuen Größen anpassen.
     
  6. funcoder, 14.08.2010 #6
    funcoder

    funcoder Threadstarter Erfahrener Benutzer

    Beiträge:
    218
    Erhaltene Danke:
    38
    Registriert seit:
    15.08.2009
    Super, Danke!
    Ich werde es mal ausprobieren und sollten sich noch fragen ergeben würde ich mich nochmal melden.;)
     
  7. funcoder, 29.08.2010 #7
    funcoder

    funcoder Threadstarter Erfahrener Benutzer

    Beiträge:
    218
    Erhaltene Danke:
    38
    Registriert seit:
    15.08.2009
    Kurios, es hat jetzt alles bis vor kurzem funktioniert. Also, für smallscreens soll die android interne autoscaling feature nicht verwendet werden. Nur für large-Screens. Daher habe ich folgenden Eintrag in der manifest.xml eingetragen:

    <supports-screens
    android:smallScreens="true"
    android:normalScreens="true"
    android:largeScreens="false"
    android:anyDensity="false"/>

    Das ganze hat definitiv schon mal funktioniert, ich habe jediglich weitere activites hinzugefügt. Ich habe schon alles mögliche in der manifest file ausprobiert aber es nicht mehr zum laufen gebracht.

    Die ganze manifest File sieht so aus:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="eu.coderproject.android.stwg"
    android:versionCode="1"
    android:versionName="1.0.0">

    <supports-screens
    android:smallScreens="true"
    android:normalScreens="true"
    android:largeScreens="false"
    android:anyDensity="false"/>

    <application android:icon="@drawable/icon" android:label="@string/app_name">

    <activity android:name=".MainMenu"
    android:screenOrientation="landscape"
    android:label="MainMenu"
    android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
    <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    </activity>

    <activity android:name=".Game"
    android:screenOrientation="landscape"
    android:label="@string/app_name"
    android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
    </activity>

    <activity android:name=".SettingsMenu"
    android:screenOrientation="landscape"
    android:label="@string/app_name"
    android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
    </activity>

    <activity android:name=".LevelMenu"
    android:screenOrientation="landscape"
    android:label="@string/app_name"
    android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
    </activity>

    </application>

    </manifest>


    Bin ziemlich ratlos und wäre daher auch für jeden Tipp dankbar!

    DANKE
     
  8. wilco, 31.08.2010 #8
    wilco

    wilco Android-Hilfe.de Mitglied

    Beiträge:
    106
    Erhaltene Danke:
    32
    Registriert seit:
    10.08.2010
    Soweit ich weis werden die Grafiken vom System immer automatisch skaliert. Was Du mal versuchen kannst ist eine weitere Kopie Deiner Grafiken im Ordner drawable-ldpi abzulegen.

    Sobald Du dann auf einem Gerät mit kleiner Auflösung fährst werden die Grafiken aus diesem Ordner gelesen. Da sollte dann eigentlich nicht skaliert werden.

    Wenn Du eine Möglichkeit gefunden hast die automatische Skalierung generell abzustellen sag Bescheid. Danach suche ich auch schon länger...
     
  9. funcoder, 05.09.2010 #9
    funcoder

    funcoder Threadstarter Erfahrener Benutzer

    Beiträge:
    218
    Erhaltene Danke:
    38
    Registriert seit:
    15.08.2009
    Wuhu endlich geschafft.
    Also wer nur ein drawable Verzeichnis haben möchte und die Skalierung für einzelne Screensolutions (ldpi, mdpi, ldpi) aktivieren bzw. deaktivieren möchte macht am besten folgendes:

    1. die Pixeldichte auslesen:
    DisplayMetrics metrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(metrics);
    int dpi = metrics.densityDpi;

    2. BitmapFactory zum Skalieren instanzieren
    BitmapFactory.Options scalingFeature = new BitmapFactory.Options();

    // Wenn kleines Display, dann internes skalieren deaktivieren
    if(dpi == 120){

    scalingFeature.inScaled = false;
    }else{
    scalingFeature.inScaled = true;
    }

    3. Entsprechend die Grafiken aus dem drawable Folder decodieren

    Bitmap grafik = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.grafik,scalingFeature);

    FERTIG! :D


    Also die Skalierung generell abzuschalten funktioniert wohl am einfachsten so, indem du in der manifest file bei supports-screens anyDensity und anyResizable auf true schaltest und sämtliche grafiken in den drawable-nodpi ablegst.

    Hoffe hier vielleicht jemanden der noch auf der suche nach dem gleichen war geholfen zu haben.
     

Diese Seite empfehlen