You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:在Slick2D的BasicGameState中实现用户名输入的高效方案

我之前在Slick2D开发游戏时也碰到过这个文本输入的坑,给你两个实用的解决方案:

方案1:修复内置TextField在BasicGameState中的问题

很多时候内置TextField不工作,只是因为我们漏了关键的初始化或生命周期调用步骤。试试按照下面的流程来:

  1. 在BasicGameState的init方法中正确初始化TextField,记得传入GameContainer的Input实例;
  2. 在update方法中调用TextField的update方法,让它处理输入逻辑;
  3. 在render方法中调用TextField的render方法,渲染文本框;
  4. 确保给TextField设置焦点,否则它不会响应输入。

示例代码:

import org.newdawn.slick.*;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;

public class UsernameInputState extends BasicGameState {
    private TextField usernameField;
    private int stateId;

    public UsernameInputState(int stateId) {
        this.stateId = stateId;
    }

    @Override
    public void init(GameContainer container, StateBasedGame game) throws SlickException {
        // 初始化TextField:参数依次是字体、输入实例、x坐标、y坐标、宽度、高度
        usernameField = new TextField(container.getGraphics().getFont(), container.getInput(), 150, 200, 250, 35);
        usernameField.setBorderColor(Color.LIGHT_GRAY);
        usernameField.setTextColor(Color.WHITE);
        usernameField.setFocus(true); // 默认获取输入焦点
        usernameField.setMaxLength(15); // 限制用户名最大长度
    }

    @Override
    public void update(GameContainer container, StateBasedGame game, int delta) throws SlickException {
        usernameField.update(delta); // 必须调用,让TextField处理输入状态更新
    }

    @Override
    public void render(GameContainer container, StateBasedGame game, Graphics g) throws SlickException {
        g.drawString("请输入用户名:", 100, 210);
        usernameField.render(container, g); // 渲染文本框
    }

    @Override
    public int getID() {
        return stateId;
    }
}

如果还是有问题,可以检查是否在StateBasedGame中正确切换到了这个状态,或者有没有其他Input监听器抢占了输入事件。

方案2:自定义高效文本输入组件

如果内置TextField实在不满足需求,我们可以自己封装一个,利用Slick2D的Input.getInputString()方法来批量处理输入字符,不用逐个检测按键,效率很高:

首先创建自定义文本框类:

import org.newdawn.slick.*;

public class CustomTextField {
    private String inputText = "";
    private final int x, y, width, height;
    private final Font font;
    private boolean isFocused = false;
    private Color textColor = Color.WHITE;
    private Color borderColor = Color.GRAY;

    public CustomTextField(Font font, int x, int y, int width, int height) {
        this.font = font;
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }

    public void update(Input input) {
        if (!isFocused) return;

        // 处理退格键
        if (input.isKeyPressed(Input.KEY_BACK) && !inputText.isEmpty()) {
            inputText = inputText.substring(0, inputText.length() - 1);
        }

        // 处理回车键(可选:提交输入)
        if (input.isKeyPressed(Input.KEY_ENTER)) {
            isFocused = false;
            // 这里可以添加提交逻辑,比如把用户名传给游戏主逻辑
            System.out.println("用户名:" + inputText);
        }

        // 处理所有可打印字符(自动处理大小写、符号,不用逐个检测按键)
        String newInput = input.getInputString();
        if (!newInput.isEmpty()) {
            // 检查文本长度是否超出文本框宽度
            if (font.getWidth(inputText + newInput) <= width - 10) {
                inputText += newInput;
            }
        }
    }

    public void render(Graphics g) {
        // 绘制边框
        g.setColor(borderColor);
        g.drawRect(x, y, width, height);

        // 绘制输入文本
        g.setColor(textColor);
        g.setFont(font);
        // 垂直居中文本
        int textY = y + (height - font.getLineHeight()) / 2;
        g.drawString(inputText, x + 5, textY);

        // 绘制闪烁光标(聚焦时显示)
        if (isFocused) {
            long currentTime = System.currentTimeMillis() % 1000;
            if (currentTime < 500) {
                int cursorX = x + 5 + font.getWidth(inputText);
                g.drawLine(cursorX, y + 5, cursorX, y + height - 5);
            }
        }
    }

    // 辅助方法:设置/获取焦点
    public void setFocused(boolean focused) {
        this.isFocused = focused;
    }

    public boolean isFocused() {
        return isFocused;
    }

    // 获取输入的文本
    public String getInputText() {
        return inputText;
    }
}

然后在你的BasicGameState中使用这个自定义组件:

import org.newdawn.slick.*;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;

public class CustomInputState extends BasicGameState {
    private CustomTextField usernameInput;
    private int stateId;

    public CustomInputState(int stateId) {
        this.stateId = stateId;
    }

    @Override
    public void init(GameContainer container, StateBasedGame game) throws SlickException {
        usernameInput = new CustomTextField(container.getGraphics().getFont(), 150, 200, 250, 35);
        usernameInput.setFocused(true); // 默认聚焦
    }

    @Override
    public void update(GameContainer container, StateBasedGame game, int delta) throws SlickException {
        usernameInput.update(container.getInput());
    }

    @Override
    public void render(GameContainer container, StateBasedGame game, Graphics g) throws SlickException {
        g.drawString("请输入用户名:", 100, 210);
        usernameInput.render(g);
    }

    // 可选:点击文本框获取焦点
    @Override
    public void mousePressed(int button, int x, int y) {
        boolean isInField = x >= usernameInput.x && x <= usernameInput.x + usernameInput.width
                && y >= usernameInput.y && y <= usernameInput.y + usernameInput.height;
        usernameInput.setFocused(isInField);
    }

    @Override
    public int getID() {
        return stateId;
    }
}

这个自定义组件的优势是完全可控,而且getInputString()会自动处理所有可打印字符,包括Shift键切换大小写、符号输入等,比逐个检测按键高效太多。

内容的提问来源于stack exchange,提问作者Huzaif Ahmed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:09:43