Canvas größe ändern

J

joniwa

Neues Mitglied
0
Hallo zusammen,

ich habe ein Problem bei dem ich einfach nicht weiterkomme.Ich möchte ein Android Spiel Programmieren das auf allen Bildschirmgrößen gleich aussieht, dazu würde ich gerne eine feste Pixelgröße für meinen Canvas festlegen. Allerdings habe ich dazu im Internet nichts gefunden.Hier meine Fragen:

Gibt es eine möglichkeit dem Canvas eine feste Pixelgröße zu geben und diese dann auf Vollbild zu Skalieren ?

Oder gibt es eine bessere Methode um dem Bildschirm eine feste Pixelgröße zu geben damit es auf allen Geräten gleich aussieht?

Wäre für jede Hilfe Dankbar.
 
gehört ind en bereich "Spiele programmierung"

Ansonsten je geht natürlich

ich m,ach es so das ich jedes einzelne bitmaps riochtig skaliere und deren aspect ratio beibehalte

deine Lösund ist auch einfach zu machen wird jedoch unter Umständen sehr verzerrt rüberkommen(entwickle unter vorlage eines Bildschirmes dessen Breite zu seiner Höhe etwa 0.6 ist(z.B. 600x1000 px)

die verezerrung (ein kries ist z.B. eine Ellipse) wäre heir nur minimal

als erstes müssen die bitmaps die richtige größe von vorneherein haben in deinem fall(skalieren geht auch falls du die bitmaps sehr groß haben willst und nur kleine bitmaps erstmal in den speicher laden willst um diese zu vergrößern später sonst läufst du gefahr OOM zu triggern so wie ich manchmal auch...gibt shcon ein thread von mir darüber und auch eine mehr oder weniger zufreidenstellende Lösung den large heap zubenutzen))

dann erstellst du dir im Code eine Bitmap deiner gewünschten Größe mit

PHP:
Bitmap bmp=Bitmap.screateBitmap(width,height,Config.ARGB_8888);


dannerstellst du einen canvas mit

PHP:
Canvas tempCanvas=new Canvas(bmp);

damit wird alles was du mit tempCanvas.draw... machst ins bitmap gemalt


so der Trick ist jetzt eigentlich du bekommst ja einen canvas(du benutzt ja die Surfaceview oder?) die du mit lockcanvas erhälst...

du zeichnest erstmal deine sachen auf das Bitmap.

wenn du fertig bist nimmst du das bitmap in das du gezeichnet hast und skalierst es mit

PHP:
Bitmap scaledBMP = Bitmap.createScaledBitmap(bmp,screenWidth,screenHeight,true);

screenWidth und Height sind selbsterklärend diese bekommst du (sobald die Surfaceview sich aufgebaut hat (in ->public void surfaceCreated()) mit yourSFView.getWidth() oder ...getHeight())


jetzt malst du dieses skalierte bitmap auf den Canvas der zum Screen gehört mit

PHP:
screenCanvas.drawBitmap(scaledBitmap,0,0,paint oder null);


Fertig ist das verzerrte Bild ;)

NAchteil: neben der Verzerrung dauert es etwas bis ein Bildschirm großes bitmap fertig skaliert wurde. das Schlimme ist ja auch dass wenn sich die Bildschirmgröße verdoppelt vervierfacht sich auch die Zeit dazu

Das habe ich hier zum Beispiel schmerzlich erfahren müssen ->https://www.android-hilfe.de/forum/...oid-canvas-color-milchglas-effekt.674998.html siehe letzter Post)


viel erfolg

Der ursprüngliche Beitrag von 22:09 Uhr wurde um 22:12 Uhr ergänzt:

also kurz gesagt wirst du je anch größe des spiels und anzahl der Bitmaps eine mehr oder weniger schlechte FPS Rate haben
 
Zuletzt bearbeitet:
Jaiel schrieb:


also kurz gesagt wirst du je anch größe des spiels und anzahl der Bitmaps eine mehr oder weniger schlechte FPS Rate haben

Das Problem hatte ich auch als ich mich an einem Spiel mit dem Android SDK probiert habe. Sobald es einige größere Bitmaps anzuzeigen gab war die Framerate nicht mehr zufriedenstellend.
Hab mir jetzt mal LibGDX angeschaut.

@Jaiel nutzt du das android SDK oder vlt ein anderes Framework um dem Problem zu entgehen?
 
Ja nur die Standard API zur zeit mir reichenüber 40 frames bei starker Belastung aus

Libgdx ist top

Der ursprüngliche Beitrag von 16:14 Uhr wurde um 16:17 Uhr ergänzt:

Ich hab auch schon aber mit opengl es direkt geliebäugelt

Die glsurfaceview ist im Prinzip eine surfaceview die Änderungen sind marginal
 
Vielen Dank Jaiel für diese sehr ausführliche Anleitung :).Hat mir wirklich viel weiter
geholfen.Allerdings reichen mir die FPS für mein Spiel nicht aus weshalb ich alle Bitmaps erst auf die richtige Größe verzerre und dann auf den Canvas Zeichne.
So müssen die Bitmaps nur einmal Skaliert werden und die FPS leiden nicht so stark darunter.
 
Zuletzt bearbeitet:
joniwa schrieb:
Vielen Dank Feuerstern für diese sehr ausführliche Anleitung :)

meinst du vllt mich und meine ausladende Ausführung? :D

Der ursprüngliche Beitrag von 08:01 Uhr wurde um 08:08 Uhr ergänzt:

joniwa schrieb:
.Allerdings reichen mir die FPS für mein Spiel nicht aus weshalb ich alle Bitmaps erst auf die richtige Größe verzerre und dann auf den Canvas Zeichne.
So müssen die Bitmaps nur einmal Skaliert werden und die FPS leiden nicht darunter.


so siehts aus ist der beste und praktikabelste weg alles erstmal zu laden

Also ich krieg zwar keine 10 FPS mit dieser EMthode aber schon so um die 20-25 wenn es gut läuft....teste aber auch immer mit note 4 der hat ein paar pixel mehr(1440x2560) als die meißten anderen gängigen Handy dadurch ist der zeichenaufwand größer weil mehr pixeldaten verändert werden müssen

(ich muss etwas hinzufügen zu meiner anderen erklärungen nciht nur das skalieren raubt zeit auch das ezichnen ist genauso zeitraubend wenn nicht fällt es sogar mehr ins gewicht)

man könnte es sogar noch effizienter machen in dem man nur die stellen mit dem canvas lockt die auch wirklich zu zeichnen und auch nur diese stellen bearbeitet

das geht etwas schneller da android dann alle pixel de ausserhalb des stückes sind das du neu zeichnen willst nicht beachter und sofort in die wichtigen stellen springt und dort verändert

dann könnte man je anch belastung auf jeden fall 30+ fps schaffen
 
Oh das ist mir jetzt aber Peinlich das ich den falschen Namen geschrieben habe :unsure:

Nochmal danke für die Anleitung.Auch wenn ich für mein Spiel nicht immer die ganze Bitmap neu Zeichnen kann weiß ich ja jetzt auch wie ich eine Bitmap Skalieren kann und mein Spiel sieht endlich auf allen Displaygrößen gleich aus.

Ich stelle die Frage jetzt auf beantwortet :)
 
Jaiel warum geht du von einem bildverhaeltnis von 1:1.6 aus?
Ich nutze ein bitmap von 480/320px da doch auch mein handy ein
verhAeltnis von 1240/720 hat. Das kleine bild wird dann je nach handy auf
die bildschirmgroesse skaliert, ich schau mir gleich zuhause nochmal an
wann es skaliert wird (habe die methode v dem buch^^) meine fps lasse ich mir
dummerweise noch nicht anzeigen, was ich aber auch gleich aender und mal
genauer nachschaue... ihr macht mir grad angst ;)

ich hatte am anfang bei mir das problem das zwischen zwei aneinander
liegenden bildern immer eine schwarze linie war. Hatte dann mit den
paint filtern rungespielt( beim scalier vorgang) dann gingen sie weg.
Meine original bilder habe ich fuer die aufloesung von 480/320 px gezeichnet.


okay ich fang mal mit der Orientierung an, ein ausschnitt aus der Game Klasse:
Code:
@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                             WindowManager.LayoutParams.FLAG_FULLSCREEN);

        // Handle posts from UI Thread
        handler = new Handler();


        // CHECK ORIENTATION - SET X Y SIZE
        boolean isLandscape = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
        int frameBufferWidth = isLandscape ? 480 : 320;
        int frameBufferHeight = isLandscape ? 320 : 480;

        // Declaration of frameBuffer
        Bitmap frameBuffer = Bitmap.createBitmap(frameBufferWidth, frameBufferHeight, Config.RGB_565);

        // Declare display metrics
        DisplayMetrics display = new DisplayMetrics();

        // Get/Set display size
        getWindowManager().getDefaultDisplay().getMetrics(display);


        int w = display.widthPixels;
        int h = display.heightPixels;

        // Set scale Size
        float scaleX = (float) frameBufferWidth / w;
        float scaleY = (float) frameBufferHeight / h;

        // IMPLEMENTATION OF INTERFACES
        renderView = new AndroidFastRenderView(this, frameBuffer);          // FrameBuffer Renderview
        graphics = new AndroidGraphics(getAssets(), frameBuffer);           // Graphics
        fileIO = new AndroidFileIO(this);                                   // FileIO
        audio = new AndroidAudio(this);                                     // Audio
        input = new AndroidInput(this, renderView, scaleX, scaleY);         // Input

        // Set start Screen (needs Override)
        screen = getStartScreen();

        //set view
        setContentView(renderView);

        //wakelock
        PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
        wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "GLGame");
    }

es wird wie jaiel schon sagte auf ein bild gemalt und dieses dann skaliert.
das eigentliche skalieren geht in der SurfaceView vor sich:
Code:
public class AndroidFastRenderView extends SurfaceView implements Runnable {

    AndroidGame game;
    Bitmap framebuffer;
    Thread renderThread = null;
    SurfaceHolder holder;
    Paint paint;

    volatile boolean running = false;


    public AndroidFastRenderView(AndroidGame game, Bitmap framebuffer) {
        super(game);
        this.game = game;
        this.framebuffer = framebuffer;
        this.holder = getHolder();
        paint = new Paint();
    }

    public void resume() {
        running = true;
        renderThread = new Thread(this);
        renderThread.start();
    }

    public void run() {
        Rect dstRect = new Rect();
        long startTime = System.nanoTime();
        int fpsCount = 0;
        float lastTime = 0;
        float totalTime = 0;
        float firstTime = 0;
        float deltaTime2=0;
        float fps = 0;
        String FPS = "";

        while (running) {
            firstTime = System.nanoTime();
            if (!holder.getSurface().isValid())
                continue;
            float deltaTime = (System.nanoTime() - startTime) / 1000000000.0f;
            startTime = System.nanoTime();

            game.getCurrentScreen().update(deltaTime);
            game.getCurrentScreen().present(deltaTime);

            Canvas canvas = holder.lockCanvas();
            canvas.getClipBounds(dstRect);
            canvas.drawBitmap(framebuffer, null, dstRect, null);

            fpsCount++;
            lastTime = System.nanoTime();
            deltaTime2 = lastTime - firstTime;
            totalTime = totalTime + deltaTime2;

            if(fpsCount >= 20) {
                fps = ((1000000000) / (totalTime / fpsCount));
                fps = (int) fps;
                FPS = "FPS: " + fps;

                totalTime = 0;
                fpsCount = 0;
            }

            paint.setTypeface(Typeface.DEFAULT_BOLD);
            paint.setTextSize(canvas.getHeight()/25);
            paint.setTextAlign(Paint.Align.LEFT);
            paint.setColor(Color.WHITE);
            canvas.drawText(FPS, canvas.getWidth() / 3, canvas.getHeight()/5,paint);
            holder.unlockCanvasAndPost(canvas);
        }
    }

berechne ich die Fps richtig? dann sinds damit bei meinem 2d Tilegame bisher
59+ Fps. Ich werde am Wochenende mal einen Thread aufmachen und mein bisheriges Ergebnis posten,
ich denke ich habe viele Stellen die man besser lösen könnte ( das durchgehen der zu zeichnenden Tiles etc)
also müsste noch mehr drin sein.

Bildausschnitte von Tilesheets werden dann so gezeichnet:
Code:
    @Override
    public void drawPixmap(Pixmap pixmap, int x, int y, int srcX, int srcY, int srcWidth, int srcHeight) {
        srcRect.left = srcX;
        srcRect.top = srcY;
        srcRect.right = srcX + srcWidth;
        srcRect.bottom = srcY + srcHeight;
        dstRect.left = x;
        dstRect.top = y;
        dstRect.right = x + srcWidth;
        dstRect.bottom = y + srcHeight;
        //System.out.println(srcRect.left + " "+ srcRect.top+" "+srcRect.right+ " "+srcRect.bottom);
        canvas.drawBitmap(((AndroidPixmap) pixmap).bitmap, srcRect, dstRect, null);
    }
    @Override
    public void drawPixmapT(Pixmap pixmap, int x, int y, int srcX, int srcY, int srcWidth, int srcHeight, int transparancy) {
        srcRect.left = srcX;
        srcRect.top = srcY;
        srcRect.right = srcX + srcWidth;
        srcRect.bottom = srcY + srcHeight;
        dstRect.left = x;
        dstRect.top = y;
        dstRect.right = x + srcWidth;
        dstRect.bottom = y + srcHeight;

        paint.setAlpha(transparancy);
        canvas.drawBitmap(((AndroidPixmap) pixmap).bitmap, srcRect, dstRect, null);
        paint.setAlpha(100);
    }

    @Override
    public void drawPixmap(Pixmap pixmap, int x, int y) {
        canvas.drawBitmap(((AndroidPixmap)pixmap).bitmap, x, y, null);
    }

Wenn ich es richtig verstanden habe schneide ich in jedem Durchlauf
die Bilder aus den anfangs geladenen Tilesheets und Zeichne sie auf den Buffer.
das fertige Bild wird dann skaliert auf den screen geworfen.

für Tablets ist die Auflösung natürlich nicht gedacht, da wird alles gross und verschwommen.
mit paint filtern könnte man bei der vergrösserung sicher einen klaren pixelart style Effekt erzeugen^^
 
Zuletzt bearbeitet:
Ich gehe von einem aspect ratio von 0.5625 bis 0.666 aus

1440x2560 - 0.5625 b/h
1080×1920 - 0.5625
648×1080 - 0.6
320x480 - 0.667


Neuere Geräte tendieren mehr zu 0.5625 älter mehr gegen 0.6666 und darüber hinaus
 
Und in meinem fall sind es aber 0.5 richtig? Sg s 3

wie saehe mein bild auf andren handys aus? Dachte alle haben
das bildverhaeltnis... :S fehlt dann evtl etwas? Bzw bei mir wird
doch sowieso auf die display metrics geprueft und skaliert
 
Zuletzt bearbeitet:
ne dein Samsung hat auch 0.5625 hat genau die hälfte der pixel eines note 4 in beide richtungen (720x1280)

da ich viele sachen aufgrund der breite eines handys skaliere sind zahlen nahe 0.5... vorteilhaft über 0.7 wirds problematisch.
 
  • Danke
Reaktionen: Railwanderer
Erklaer bitte mal genau wie berechnet sich die aspect ratio? Bei mir sind 1240 auf 720 px das doch
Genau die haelfte drauf also 0.5 bzw 1.5 .... ich steh auf dem schlauch :(
 
Aah meinte ich doch habs falsch im kopf gehabt ;) wieso jetzt 2? Oder
0.5625? :p
 
was meintest du mit 1.5?
 
Okay okay ich hab den denkfehler gefunden...
also mein canvas hat eine abmessung von 480/320
und ist damit 1.5 mal so breit wie hoch ( landscape )
Mein sg s3 hat 1280/720 aber das ist doch nicht 1.5625? Mal so
breit wie hoch? Das verhaeltnis waere hier 1.77777... wieso
Bekomme ich dann beim skalieren ein ordentliches bild? :S also kreise sind rund.
und wie kommst du auf 0.5625?
 
Breite durch Höhe
 
Ich sollte mich schaemen^^ ... mathe leistung xD
 
ach quatsch...

Höhe durch Breite kann man genauso gut beachten das ist eig. egal ich finde nur die zahlen sind "runder" bei meiner Betrachtungsweise
+
aber mit den Werten amche ich ncihts ich sklaier alles in Abhängigkeit von der Breite wenn es um kreise oder buttons geht...weil die breite kleiner ist als die höhe und teste es dann auf einem emulator der eine B/H von 0.66 hat(320x480) wenn sich da keine buttons überlappen ind er höhe dann bei alles unter 0.66 auch nciht


BTW.: ich glaube wir blähen den Thread hier etwas auf :drool::flapper:
 
Ich habe jetzt doch noch ein Problem beim Skalieren gefunden.

Da beim Skalieren natürlich keine Komma Zahlen verwenden kann.
Wenn ich jetzt z.B. 10 Bitmaps untereinander Zeichne die eigentlich über den ganzen Bildschirm gehen würde dann dann kommt bei manchen Bildschirmgrößen am unteren Rand ein leerer Streifen.
Als Standard Bildschirmgröße verwende ich 800*480.Getestet habe ich es auf 1280*800.
Um die Bitmap zu Skalieren Rechne ich 800/480*Bitmapgröße dadurch komme ich auf 66.66666.Diese Zahl kann ja nicht korrekt in einem Int gespeichert werden und die Bitmap wird nicht genau Skaliert.Dadurch bekomme ich diesen Streifen am Rand wo die Bitmaps nicht bis zum Rand gehen.

Gibt es eine Möglichkeit das ich die Bitmaps so Skaliere das sie wirklich bis zum Rand gehen und es auf allen Bildschirmgrößen gleich aussieht?
 

Ähnliche Themen

D
Antworten
14
Aufrufe
1.733
chrs267
chrs267
C
  • Chicken Wing
Antworten
4
Aufrufe
873
Chicken Wing
C
Vapeilas91
  • Vapeilas91
Antworten
3
Aufrufe
709
swa00
swa00
Zurück
Oben Unten