Search code examples
javaeclipseapplet

Drawable and Clickable text for Visual Novel


This is not a duplicate. All other solutions I tried were outdated.

So first look at this Image

enter image description here

I made that in eclipse today in Java. It looks like a Visual Novel.

The point is I want to draw some text on the screen but don't know how to. At first I only want to know:

  1. How to draw text on screen and change it
  2. Make something, such as an image or some text, clickable to move to the next scene

Here is my current code:

package textboxes;

import java.applet.Applet;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.net.URL;


public class test extends Applet implements Runnable, KeyListener {

private Image Image, Background;
private Image actor1, actor2;
private Image textbox;
private Graphics graphics;
private URL base;
private static testbg bg;

@Override
public void init(){
    setSize(960, 540);
    setBackground(Color.LIGHT_GRAY);
    setFocusable(true);
    Frame frame = (Frame)this.getParent().getParent();
    frame.setTitle("School Scene");
    try{
        base = getDocumentBase();
    }catch(Exception e){};

    //getImages from disk
    Background = getImage(base, "res/background.jpg"); 
    actor1 = getImage(base, "res/actor1.jpg");
    actor2 = getImage(base, "res/actor2.jpg");
    textbox = getImage(base, "res/textbox.jpg");
}

public test(){

}

@Override
public void start(){
    bg = new testbg();
Thread thread = new Thread(this);
thread.start();
}
@Override
public void keyPressed(KeyEvent arg0) {
    // TODO Auto-generated method stub

}

@Override
public void keyReleased(KeyEvent arg0) {
    // TODO Auto-generated method stub

}

@Override
public void keyTyped(KeyEvent arg0) {
    // TODO Auto-generated method stub

}

@Override
public void run() {
    bg.update();
    repaint();
    try{
        Thread.sleep(17);
    }catch(InterruptedException e){
        e.printStackTrace();
    }

}

@Override
public void update(Graphics g){
    if(Image == null){
        Image = createImage(this.getWidth(), this.getHeight());
        graphics = Image.getGraphics();
    }

    graphics.setColor(getBackground());
    graphics.fillRect(0, 0, getWidth(), getHeight());
    graphics.setColor(getForeground());
    paint(graphics);

    g.drawImage(Image, 0, 0, this);
}

@Override
public void paint(Graphics g){
    super.paint(g);

g.drawImage(Background, bg.getBgX(), bg.getBgY(), this);
g.drawImage(actor2, 40, 20, this);
g.drawImage(textbox, 80, 350, this);
}

public static testbg getBg() {
    return bg;
}

}

This piece of code above is what I call test.java

if you are wondering about the Background part

the following piece of code is what I call testbg.java

package textboxes;

public class testbg {

private int bgX, bgY;

public testbg(){
    bgX = 0;
    bgY = 0;
}

public void update(){

}

public int getBgX(){
    return bgX;
}

public int getBgY(){
    return bgY;
}

public void setBgX(int bgX) {
    this.bgX = bgX;
}

public void setBgY(int bgY) {
    this.bgY = bgY;
}

}

Thanks for reading this much till the end...Now so can I know how to do it ??


Solution

  • As for the text, I have two solutions, but for what you want (and for what I know of CG games), I guess the first is the best.

    This first solution is one that I found a long time ago for a problem of mine in StackOverflow (I don't remember where, sorry), in which includes de use of the several classes together to draw directly in the panel.

    private final String message;
    private final java.awt.geom.Rectangle2D.Float aboutMessageBounds;
    private final AttributedString aboutMessageAttributedString;
    private final AttributedCharacterIterator paragraph;
    
    
    // The LineBreakMeasurer used to line-break the paragraph.
    private java.awt.font.LineBreakMeasurer lineMeasurer;
    // index of the first character in the paragraph.
    private final int paragraphStart;
    // index of the first character after the end of the paragraph.
    private final int paragraphEnd;
    
    @Override
    public void init(){
    
        (...)
    
        java.util.Hashtable<TextAttribute, Object> textAtributMap = 
                    new java.util.Hashtable<TextAttribute, Object>();
    
        textAtributMap.put(TextAttribute.FAMILY, "Serif");
        textAtributMap.put(TextAttribute.SIZE, new Float(26.0));
        textAtributMap.put(TextAttribute.JUSTIFICATION, TextAttribute.JUSTIFICATION_FULL );
        textAtributMap.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_DEMIBOLD );
        textAtributMap.put(TextAttribute.LIGATURES, TextAttribute.LIGATURES_ON );
    
        message = "This is a sample of a message.";
    
        aboutMessageAttributedString = new AttributedString( aboutMessage, textAtributMap );
        paragraph = aboutMessageAttributedString.getIterator();
        paragraphStart = paragraph.getBeginIndex();
        paragraphEnd = paragraph.getEndIndex();
    
        (...)
    
    }
    
    @Override
    protected void paintComponent( Graphics g ) {
        super.paintComponent( g ); //To change body of generated methods, choose Tools | Templates.
    
        Graphics2D g2 = (Graphics2D)g.create();
            try {
    
                g2.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON );
    
                // Create a new LineBreakMeasurer from the paragraph.
                // It will be cached and re-used.
                if (lineMeasurer == null) {
                    FontRenderContext frc = g2.getFontRenderContext();
                    lineMeasurer = new java.awt.font.LineBreakMeasurer(paragraph, frc);
                }
    
                //You can scale it like I did. this part is not part of the code that I found.
                g2.scale( ratio.scaleDx, ratio.scaleDy );
    
                // Set break width to width of Component.
                //these were the measures I used for a something in a game;
                float breakWidth = 734.0f;
                float drawPosY = 90.0f;
                float posX0 = 30.0f;
                // Set position to the index of the first character in the paragraph.
                lineMeasurer.setPosition(paragraphStart);
    
                // Get lines until the entire paragraph has been displayed.
                while (lineMeasurer.getPosition() < paragraphEnd) {
                    int next = lineMeasurer.nextOffset(breakWidth);
    
                    int limit = next;
                    if (limit <= message.length()) {
                        for (int i = lineMeasurer.getPosition(); i < next; ++i) {
                            char c = aboutMessage.charAt(i);
                            if (c == '\n') {
                                limit = i + 1;
                                break;
                            }
                        }
                    }
    
                    java.awt.font.TextLayout layout = lineMeasurer.nextLayout( breakWidth, limit, false );
                    // Retrieve next layout. A cleverer program would also cache
                    // these layouts until the component is re-sized.
    
    
                    // Compute pen x position. If the paragraph is right-to-left we
                    // will align the TextLayouts to the right edge of the panel.
                    // Note: this won't occur for the English text in this sample.
                    // Note: drawPosX is always where the LEFT of the text is placed.
                    float drawPosX = layout.isLeftToRight()
                            ? posX0 : breakWidth - layout.getAdvance();
                    // Move y-coordinate by the ascent of the layout.
                    drawPosY += layout.getAscent();
    
                    // Draw the TextLayout at (drawPosX, drawPosY).
                    layout.draw(g2, drawPosX, drawPosY);
    
                    // Move y-coordinate in preparation for next layout.
                    drawPosY += layout.getDescent() + layout.getLeading();
                }
    
            } 
            finally {
                g2.dispose();
            }
    }
    

    As for the second solution, you could use a JEditorPane or a JTextPane. See the Oracle tutorial for this mater:

    https://docs.oracle.com/javase/tutorial/uiswing/components/editorpane.html

    I hop I have helped.

    Have a nice day. :)