2015-06-07 24 views
7

Das beliebte Spiel Words with Friends zieht Brief Fliesen auf dem Spielbrett als eine einzige Einheit -Wie erstellt man Relief um ein Bitmap?

Sie können alle Buchstaben Fliesen im folgende Screenshot und auch einen Präge-Effekt am Rande ein gelbe linearen Gradienten angewandt sehen :

app screenshot

In my word game würde Ich mag ähnliche Effekte haben:

So erstelle ich ein Spielbrett Größe mBitmap, dann alle Steine ​​hinein ziehen und schließlich die Bitmap zeichnen in my custom view -

Setup:

setLayerType(View.LAYER_TYPE_SOFTWARE, null); 

// create yellow linear gradient 
mGradStart = new Point(3 * mWidth/4, mHeight/3); 
mGradEnd = new Point(mWidth/4, 2 * mHeight/3); 
LinearGradient gradient = new LinearGradient(
     mGradStart.x, 
     mGradStart.y, 
     mGradEnd.x, 
     mGradEnd.y, 
     new int[]{ 0xCCFFCC00, 0xCCFFCC99, 0xCCFFCC00 }, 
     null, 
     TileMode.CLAMP); 

// create the big bitmap holding all tiles 
mBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888); 
mCanvas = new Canvas(mBitmap); 

mPaintGrad = new Paint(); 
mPaintGrad.setShader(gradient); 

mPaintEmboss = new Paint(); 
mPaintEmboss.setShader(gradient); 

EmbossMaskFilter filter = new EmbossMaskFilter(
    new float[] { 0f, 1f, 0.5f }, 0.8f, 3f, 3f); 
mPaintEmboss.setMaskFilter(filter); 

Zeichnung:

@Override 
protected void onDraw(Canvas canvas) { 
    mGameBoard.draw(canvas); 

    // draw all tiles as rectangles into big bitmap 
    // (this code will move to onTouchEvent later) 
    mBitmap.eraseColor(Color.TRANSPARENT); 
    for (SmallTile tile: mTiles) { 
     mCanvas.drawRect(
       tile.left, 
       tile.top, 
       tile.left + tile.width, 
       tile.top + tile.height, 
       mPaintGrad); 
     tile.draw(mCanvas); 
    } 
    canvas.drawBitmap(mBitmap, 0, 0, mPaintEmboss); // emboss NOT displayed 
    canvas.drawText("TEXT WORKS OK", 400, 400, mPaintEmboss); // ebmoss OK 
    canvas.drawRect(300, 600, 800, 1200, mPaintEmboss); // emboss OK 
} 

Die EmbossMaskFilter Effekt funktioniert OK mit drawText() und drawRect() Anrufen, aber es funktioniert nicht für die drawBitmap():

app screenshot

Meine Frage: ist es möglich, einige Kombinationen von PorterDuff.Mode zu verwenden, um eine ziehen (und extractAlpha?) Prägen Sie sich um meine große Bitmap?

UPDATE:

von auf HolographicOutlineHelper.java suchen, ich konnte einen äußeren Schatten hinzufügen:

app screenshot

mit dem folgenden Code in MyView.java -

Setup:

Zeichnung:

private void prepareBitmaps() { 
    mBitmap.eraseColor(Color.TRANSPARENT); 
    for (SmallTile tile: mTiles) { 
     mCanvas.drawRect(
       tile.left, 
       tile.top, 
       tile.left + tile.width, 
       tile.top + tile.height, 
       mPaintGrad); 
     tile.draw(mCanvas); 
    } 

    mAlphaBitmap = mBitmap.extractAlpha(mPaintBlur, mOffset); 
} 

@Override 
protected void onDraw(Canvas canvas) { 
    mGameBoard.draw(canvas); 
    canvas.drawBitmap(mAlphaBitmap, mOffset[0], mOffset[1], mPaintBlur); 
    canvas.drawBitmap(mBitmap, 0, 0, mPaintGrad); 
} 

aber leider ist die App langsam jetzt handelt - und ich weiß noch nicht, wie ein Prägeeffekt um die Bitmap hinzuzufügen.

Antwort

5

Ich bin nicht sicher, ich habe exacly, was Sie brauchen, aber wenn Sie nur EmbossMaskFilter um einige png Brief mit Alphakanal anwenden möchten, können Sie ziemlich viel tun, um diesen Trick mit

EmbossMaskFilter filter = new EmbossMaskFilter(new float[]{1, 1, 1}, 0.5f, 0.6f, 2f); 

Paint paintEmboss = new Paint(); 
paintEmboss.setMaskFilter(embossMaskFilter); 

Bitmap helperBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 
Canvas helperCanvas = new Canvas(helperBitmap); 

Bitmap alpha = src.extractAlpha(); 
helperCanvas.drawBitmap(alpha, 0, 0, paintEmboss); 
alpha.recycle(); 

... 
canvas.drawBitmap(helperBitmap, 0, 0, anyPaint); 

werden Sie nie möchte diesen ganzen Code in 1 onDraw, weil es viele Objekte im Speicher erstellt. Und src.extractAlpha(); erstellt jedes Mal neue Bitmap. (Btw ich bekomme immer aus Speicherfehler von Ihrem Projekt git. Hinzugefügt mAlphaBitmap.recycle(); und es könnte zumindest booten. Aber es ist immer noch wie die Hölle)

Also, ich spielte mit Ihrem Git-Repository und bekam einige Ergebnisse. Hier Demo Bild ist und git repo of first commit:

enter image description here

aber dann merkte ich, dass Sie nicht brauchen EmbossMaskFilter um Buchstaben, müssen Sie sie um Rechtecke. Und es kann genauso gemacht werden. Hier ist, wie ich dies getan:

  1. Erstellen neue Helfer statische Bitmap und Leinwand für Präge-Hintergrund, wie mAlphaBitmap
  2. Auf jeder prepareBitmaps() Farbe Rects auf Helfer Bitmap. Einfarbig ohne Alpha.
  3. Extract aus alpha-Bitmap erstellt ähnlichen alpha Bitmap auf helper mit Farbe mit Prägungsfilter Bitmap alpha = helperCanvas.extractAlpha();
  4. Draw extrahierte helperCanvas.drawBitmap(alpha, 0, 0, paintEmboss);
  5. In OnDraw Druck helperBitmap mit etwas vor alpha Hauptbitmap.

Hier Screenshot ohne alpha (weil es viel einfacher ist es, die Formen auf diese Weise zu sehen) enter image description here

Hier git Demo von dieser Version: https://github.com/varren/AndroidEmbossMaskFilterForPng/blob/1d692d576e78bd434252a8a6c6ad2ee9f4c6dbd8/app/src/main/java/de/afarber/mytiles2/MyView.java

Und hier ist wesentlicher Bestandteil Code geändert ich in Ihrem Projekt:

private static final EmbossMaskFilter filter = 
       new EmbossMaskFilter(new float[]{1, 1, 1}, 0.5f, 0.6f, 2f); 
private static Canvas helperCanvas; 
private static Paint paintEmboss; 

public Canvas getHelperCanvas(int width, int height){ 
    if (mAlphaBitmap == null) { 
     mAlphaBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 
     helperCanvas = new Canvas(mAlphaBitmap); 
     paintEmboss = new Paint(); 
     paintEmboss.setColor(Color.BLACK); 
    } 
    return helperCanvas; 
} 

private void prepareBitmaps() { 
    mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); 
    helperCanvas = getHelperCanvas(mBitmap.getWidth(),mBitmap.getHeight()); 
    helperCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); 
    paintEmboss.setMaskFilter(null); 
    paintEmboss.setAlpha(255); 

    for (SmallTile tile: mTiles) { 
     if (!tile.visible) continue; 
     helperCanvas.drawRect(tile.left,tile.top,tile.left + tile.width, 
       tile.top + tile.height,paintEmboss); 
     mCanvas.drawRect(tile.left, tile.top,tile.left + tile.width, 
       tile.top + tile.height, mPaintGrad); 
     tile.draw(mCanvas); 
    } 

    paintEmboss.setMaskFilter(filter); 
    Bitmap alpha = mAlphaBitmap.extractAlpha(); 
    helperCanvas.drawBitmap(alpha, 0, 0, paintEmboss); 
} 

protected void onDraw(Canvas canvas) { 
    // ... 
    paintEmboss.setAlpha(255); //todo change alpha here 
    if(mAlphaBitmap!= null)canvas.drawBitmap(mAlphaBitmap, 0,0, paintEmboss); 
    if(mBitmap!= null)canvas.drawBitmap(mBitmap, 0, 0, mPaintGrad); 
    // ... 
} 

Und die letzten 3-d Schritt i gemacht ist alles von OnDraw zu prepareBitmaps() zu bewegen und preformance ist jetzt in Ordnung, aber wir haben Text-Deformation auf der Größe ändern. also hier ist source code für diesen Schritt.

Und hier ist ein bisschen gut funktioniert final solution. Das Verschieben aller Farben mit Filtern löste Probleme mit der Präformanz, aber ich denke, es gibt noch bessere Möglichkeiten, dies zu implementieren.Wie ich erlier sagte, ich weiß nicht, ist es das, was Sie brauchen, aber dieser Code ziemlich schafft viel Emboss um Bitmap

PS: irgendwie cool Effekt beim Aufteilen und das Hinzufügen von Zellen zusammen

PS2: new EmbossMaskFilter(new float[] { 0f, 1f, 0.5f }, 0.8f, 3f, 3f); dies nicht aussehen das gleiche auf verschiedenen Geräten mit verschiedenen Bildschirmauflösung

+0

Danke ... Sie können Emboss gleich aussehen lassen, indem Sie mit 'mScale = getResources() multiplizieren. GetDisplayMetrics(). Dichte;' –

+1

Ja, wollte nur betonen, dass es ein Problem in Demo-Code und Emboss-Effekt könnte schwierig sein wegen der Bildschirmauflösung zu sehen. – varren

2

Hier ist ein Vorschlag mit einem benutzerdefinierten Layout.

Sie benötigen Ihr eigenes Layout für das Scrabble Board. Da es Grid ist, sollte dies ziemlich einfach zu programmieren sein.

Die Grundidee besteht darin, eine Reihe von PNG-Shadow-Images zu erstellen, eines für jede Art von Kombination benachbarter Zellen. Zeichnen Sie in Ihrem Layout onDraw() zuerst die Schatten und dann die Kachel in onLayout().

In onDraw(), durchlaufen Sie Ihr Array von Fliesen Platzhalter. Wenn Sie eine Kachel haben, überprüfen Sie für jede Kante die benachbarten Zellen. Wählen Sie das richtige Schattenbild aus und zeichnen Sie es, je nachdem, was angrenzend ist.

Sie können die Anzahl der Schattenbilder wesentlich reduzieren, indem Sie ein Schattenbild mit genau der Breite einer Kachel erstellen und dann den Eckbereich spezialisieren: einen für 270 Grad, einen für eine gerade Ausrichtung und einen für 90 Grad.

Ich weiß nicht, ob die Verwendung von Porter-Duff helfen kann, da Sie immer noch alle diese "Kanten" -Fälle ermitteln müssen (kein Wortspiel beabsichtigt).

+0

Ja, so macht Word mit Freunden es (indem Sie auf ihre zahlreichen grafischen Assets) ... aber ich möchte eine programmatische Möglichkeit finden, eine Prägung um alle Buchstabenkacheln zu zeichnen . –