2011-11-28 17 views
5

Diciamo che ho questo sprite:Creare un caso, un grafico sinusoidale come sprite paesaggio

Sample sprite

e ho creato un paesaggio casuale durante il runtime:

Dynamic runtime landscape

E poi, Voglio affiancare l'area sotto la linea con lo sprite:

enter image description here

Questo è il terreno di gioco, pertanto dovrebbe essere anche un oggetto fisico (In Box2D).

Here, ha fornito un esempio di come rendere questo un corpo fisico. Quindi, come faccio a fare la parte grafica nel codice?

EDIT: Guardando negli esempi AndEngine, archiviare RepeatingSpriteBackgroundExample.java, non è esattamente quello che mi serve, ma dovrei aderire a questa idea e cambiare il RepeatingSpriteBackground class per le mie esigenze? Non credo che sarebbe il metodo migliore comunque ...

Grazie in anticipo.

risposta

6

In realtà non conosco Box2D o AndEngine, ma ho pensato che fosse un problema interessante e ho creato un SurfaceView personalizzato in grado di disegnare un "terreno" casuale come quello nella tua immagine. (Speriamo che sia utile a voi o qualcun altro, almeno ho imparato alcune cose nuove: p)

singolo terreno di colore: screenshot Sfondo affiancato fuoristrada: screenshot La bitmap piastrelle:
resource bitmap

il mio codice è il seguente:

public class PathView extends SurfaceView implements SurfaceHolder.Callback{ 
private class DrawingRunnable implements Runnable{ 
    private final static int minPointsOnScreen = 3; 
    SurfaceHolder surfaceHolder; 
    Random rand = new Random(); 

    private Path path; 
    private Paint pathPaint; 
    Bitmap background; 
    private Paint tilePaint;   

    volatile boolean running = false; 

    int width; 
    int height; 
    int maxHeight; 

    protected DrawingRunnable(SurfaceHolder sh){ 
     surfaceHolder = sh; 

     pathPaint = new Paint(); 
     pathPaint.setColor(0xFF000000); 
     pathPaint.setStrokeWidth(4); 

     tilePaint = new Paint(); 
    } 

    protected void createPath(){ 
     path = new Path(); 
     path.setFillType(Path.FillType.WINDING); 

     path.setLastPoint(0, height); 
     int lastX = 0, lastY = height - rand.nextInt(maxHeight); 
     path.lineTo(lastX,lastY); 

     int newX=lastX, newY=lastY; 

     do{ 
      lastX = newX; lastY = newY; 
      newX += rand.nextInt(width/minPointsOnScreen); 
      newY = height - rand.nextInt(maxHeight); 
      path.cubicTo(
        interpolateLinear(lastX, newX, 0.333f), 
        lastY, 
        interpolateLinear(lastX, newX, 0.666f), 
        newY, 
        newX, newY); 
     }while(newX <= width); 

     path.lineTo(width, height); 
    } 

    private int interpolateLinear(int start, int end, float part){ 
     return (int) (start*(1-part) + end*part); 
    } 

    @Override 
    public void run(){ 
     while(running){ 
      Canvas c = null; 
      try{ 
       c = surfaceHolder.lockCanvas(null); 
       synchronized (surfaceHolder) { 
        doDraw(c); 
       } 
      } finally{ if(c!=null) surfaceHolder.unlockCanvasAndPost(c); } 
      SystemClock.sleep(40); 
     } 
    } 

    private void doDraw(Canvas c){ 
     c.drawColor(0xFFFFFFFF); 
     //c.drawPath(path, pathPaint); //Use this to draw a single-colour. (First screenshot) 
     c.clipPath(path); 
     for(int y = 0; y+background.getHeight() < height+background.getHeight(); y+=background.getHeight()){ 
      for(int x = 0; x+background.getWidth() < width+background.getWidth(); x+=background.getWidth()){ 
       c.drawBitmap(background, x, y, tilePaint); 
      } 
     } 
    } 
} 

private ExecutorService exec; 
private SurfaceHolder holder; 
private DrawingRunnable drawer; 

public PathView(Context c){ super(c); init(c); } 
public PathView(Context c, AttributeSet as){ super(c, as); init(c); } 
public PathView(Context c, AttributeSet as, int defStyle){ super(c, as, defStyle); init(c); } 

private void init(Context c){ 
    exec = Executors.newSingleThreadExecutor(); 
    holder = getHolder(); 
    holder.addCallback(this); 
} 

public void surfaceCreated(SurfaceHolder sh){ 
    if(drawer == null){ 
     drawer = new DrawingRunnable(holder); 
     drawer.width = getWidth(); 
     drawer.height = getHeight(); 
     drawer.maxHeight = drawer.height/2; 
     drawer.createPath(); 
     drawer.background = BitmapFactory.decodeResource(getResources(), R.drawable.tile); 
    } 
    drawer.running = true; 
    exec.execute(drawer); 
} 
public void surfaceDestroyed(SurfaceHolder sh){ 
    drawer.running = false; 
} 
public void surfaceChanged(SurfaceHolder sh, int format, int width, int height){} 
} 

Se questo è di alcun aiuto a voi probabilmente dovrete giocare con i parametri per ottenere forme che si adatta le tue esigenze e molto probabilmente aggiungono un parametro per la distanza minima tra punti ecc. È anche una buona idea ottimizzare un po 'il disegno dello sfondo, come disegnare dal basso verso l'alto fino al massimo del terreno, per minimizzare il disegno aree invisibili. Dovrei anche essere possibile ridurre la quantità di chiamate a getHeight() e getWidth().

Cheers!

+0

Grazie, ma non è esattamente quello di cui avevo bisogno. Innanzitutto, AndEngine utilizza la propria versione di SurfaceView (anche se immagino di poter creare una sottoclasse anche in questo caso). Ma ho bisogno di scoprire come affiancare il paesaggio con una trama quadrata, gli algoritmi per creare percorsi sono la parte più facile :( – Jong

+0

Ho cambiato il doDraw() un po 'per farlo nel caso in cui sia di qualche aiuto per voi: – Jave

+0

Funziona alla grande, ma non posso usare queste classi native Android durante lo sviluppo con AndEngine - Devo usare le classi AndEngine. Comunque, vedrò se riesco a combinarli entrambi ... (SurfaceView e AndEngine's SurfaceView) – Jong

Problemi correlati