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.
--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.
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?)
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.
-Basics of Android Surface View
Recommended Posts