[JAVA] Display text character by character in Android Surface View

Self-introduction

Hello, this is Hokkaido of students. Basically, I have a little development experience on Android, and the languages I think I can use are Java and C #. Thank you. When I tried to make something like an RPG on Android, I got a little stuck with the method of displaying text character by character on SurfaceView, so I will write it so that I do not forget it. I think there are many mistakes, but please forgive me.

What is Surface View?

--Ideal for animations, games that require drawing performance, complex graphics, and drawing content that is constantly updated. --It is possible to draw on threads other than the main thread, but be careful about exclusive processing between threads. --Access to the Surface is done via the Surface Holder interface.

code

Create a class dedicated to graphics and put drawing instructions in it.

Graphics.java



    //constructor
    public Graphics(int w, int h, SurfaceHolder holder) {
        this.holder = holder;
        this.holder.setFormat(PixelFormat.RGBA_8888);
        this.holder.setFixedSize(w, h);
        paint = new Paint();
        paint.setAntiAlias(true);
    }

    public Canvas getCanvas() {
        return canvas;
    }

    //Lock
    public void lock() {
        canvas = holder.lockCanvas();
        if (canvas == null) return;
        canvas.translate(originX, originY);
    }

    //unlock
    public void unlock() {
        if (canvas == null) return;
        holder.unlockCanvasAndPost(canvas);
    }

    //Specifying the drawing origin
    public void setOrigin(int x, int y) {
        originX = x;
        originY = y;
    }

    //Get the X coordinate of the drawing origin
    public int getOriginX() {
        return originX;
    }

    //Get the Y coordinate of the drawing origin
    public int getOriginY() {
        return originY;
    }

    //Color specification
    public void setColor(int color) {
        paint.setColor(color);
    }

    //Specify font size
    public void setTextSize(int fontSize) {
        paint.setTextSize(fontSize);
    }

    //Get font metrics
    public Paint.FontMetrics getFontMetrics() {
        return paint.getFontMetrics();
    }

    //Get character width
    public int measureText(String string) {
        return (int)paint.measureText(string);
    }

    //Drawing a filled rectangle
    public void fillRect(int x, int y, int w, int h) {
        if (canvas == null) return;
        paint.setStyle(Paint.Style.FILL);
        canvas.drawRect(new Rect(x, y, x+w, y+h), paint);
    }

    //Bitmap drawing
    public void drawBitmap(Bitmap bitmap, int x, int y) {
        if (canvas == null) return;
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();
        Rect src = new Rect(0, 0, w, h);
        Rect dst = new Rect(x, y, x+w, y+h);
        canvas.drawBitmap(bitmap, src, dst, null);
    }

    //Bitmap drawing
    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst) {
        if (canvas == null) return;
        canvas.drawBitmap(bitmap, src, dst, null);
    }

    //Drawing a string
    public void drawText(String string, int x, int y) {
        if (canvas == null) return;
        canvas.drawText(string, x, y, paint);
    }

Then, create a class that inherits SurfaceView and set it in Activity. (It will be a little longer)

IndexActivity.java



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new RPGView(this, storyNum));
    }

RPGView.java




    
    public RPGView(Activity activity, int story) {
        super(activity);
        holder = getHolder();
        holder.addCallback(this);

        //Graphics generation
        g = new Graphics(dw, H, holder);
        g.setOrigin((dw - W) / 2, 0);
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        thread = null;
    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        thread = new Thread(this);
        thread.start();
    }

    @Override
    public void run() {
        while (thread != null) {

            //Program main loop Drawing process here

            //sleep
            key = KEY_NONE;
            sleep(200);
        }
    }

After that, I will write the drawing process in the main loop of the thread. (What are you doing?)

Text one character at a time ...

The View is updated every time in the SurfaceView thread, so I added the string one character at a time and it worked.

RPGView.java



     //Drawing the dialogue screen
    private void talk(String message, Bitmap bitmap, String who) {
        int color = Color.rgb(0, 0, 0);
        if (bitmap != null) {
            g.lock();
            g.setColor(color);
            g.fillRect(0, 0, W, H);

            g.getCanvas().translate(0, 0);
            g.fillRect(0, 0, realX, realY);
            g.getCanvas().translate((dspW - W) / 2, 0);

            g.drawBitmap(bitmap, 0, 0);
            g.setColor(Color.rgb(255, 255, 255));
            g.fillRect((W - 504) / 2, H - 122, 504, 104);
            g.setColor(color);
            g.fillRect((W - 500) / 2, H - 120, 500, 100);

            //Line breaks for TODO characters! !! !! !!
            g.setColor(Color.rgb(255, 255, 255));
            g.setTextSize(25);
            if (message.length() > 18) {
                String message1 = message.substring(0, 18);
                String message2 = message.substring(18);
                g.drawText(message1, (W - 500) / 2 + 25, 370 - (int) g.getFontMetrics().top);
                g.drawText(message2, (W - 500) / 2 + 10, 410 - (int) g.getFontMetrics().top);
            } else {
                g.drawText(message,
                        (W - 500) / 2 + 25, 370 - (int) g.getFontMetrics().top);
            }

            g.unlock();
        }
    }

If you call this method from the loop and pass the text with one more character ...

RPGView.java



    String text = "AIUEO";
    if (moji_count == text.length() || moji_count == 9999) {
          talk(text, background, null);
          moji_count = 9999;
    } else {
          talk(text.substring(0, moji_count), background, null);
          moji_count++;
    }     

I was able to do it character by character. You can display it at just the right speed by putting it to sleep for a short time.

reference

-Basics of Android Surface View

Recommended Posts

Display text character by character in Android Surface View
Display character strings character by character [Note]
Source to display character array with numberPicker in Android studio (Java)
Android view
Display View on other apps on Android (Summary of support methods by API version)
Display text as ASCII art in Java (jfiglet)
(Android) Try to display static text using DataBinding
[Japanese localization] i18n rails Easy Japanese localization view display only
[Rails] How to display an image in the view