Создайте случайный синусоидальный график, подобный ландшафтному спрайту - PullRequest
5 голосов
/ 28 ноября 2011

Допустим, у меня есть этот спрайт:

Sample sprite

И я создал случайный пейзаж во время выполнения:

Dynamic runtime landscape

А затем я хочу поместить область под линией со спрайтом:

enter image description here

Это игровая площадка, , поэтому он также должен быть физическим объектом (In Box2D) .

Здесь , он привел пример того, как сделать это физическое тело. Итак, как мне сделать графическую часть в коде?

РЕДАКТИРОВАТЬ: Глядя на примеры AndEngine, файл RepeatingSpriteBackgroundExample.java , это не совсем то, что мне нужно, но я должен придерживаться этой идеи и изменить класс RepeatingSpriteBackground для моих нужд? Я не думаю, что это был бы лучший метод, однако ...

Заранее спасибо.

1 Ответ

6 голосов
/ 01 декабря 2011

Я на самом деле не знаю о Box2D или AndEngine, но я подумал, что это интересная проблема, и создал пользовательский SurfaceView, который может рисовать случайную "местность", подобную той, что на вашей картинке. (Надеюсь, это будет полезно вам или кому-то еще, по крайней мере, я узнал кое-что новое: p)

Одноцветная местность: screenshot Плиточный фон-рельеф: screenshot Черепичное растровое изображение:
resource bitmap

Мой код выглядит следующим образом:

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){}
}

Если это вам поможет, вам, вероятно, придется поиграться с параметрами, чтобы получить фигуры, соответствующие вашим потребностям, и, скорее всего, добавить параметр для минимального расстояния между точками и т. Д. Также неплохо немного оптимизировать отрисовку фона, например, отрисовку снизу до максимальной высоты местности, чтобы минимизировать отрисовку в невидимых областях. Я также должен иметь возможность уменьшить количество вызовов getHeight () и getWidth ().

Ура!

...