Is there an example of how Lemur's InputManager should be used?

    public void CommandButton(Container directiveWindow) {
        
        Button Q = directiveWindow.addChild(new Button("Q", "ButtonGlass"), 0, 0);
        
        Button W = directiveWindow.addChild(new Button("W", "ButtonGlass"), 0, 1);

        Button E = directiveWindow.addChild(new Button("E", "ButtonGlass"), 0, 2);

        Button R = directiveWindow.addChild(new Button("R", "ButtonGlass"), 0, 3);

        Button T = directiveWindow.addChild(new Button("T", "ButtonGlass"), 0, 4);

    }

I have these 5 buttons.
I want the click() method of Button Q to be triggered when I press Q on the keyboard.

This is the normal inputManager, what should I do if I’m in Lemur?

You should use InputMapper instead.
InputManager = JME’s primitive input management.
InputMapper = Lemur’s more advanced input management.

This Lemur Gem uses InputMapper to control a cammera:

…you can see from there how to map keys to functions and stuff.

Edit: but note that InputMapper also has some convenience methods that use reflection:
inputMapper.addDelegate(yourFunctionId, theButton, “click”);
…might work.

http://jmonkeyengine-contributions.github.io/Lemur/javadoc/Lemur/com/simsilica/lemur/input/InputMapper.html#addDelegate-com.simsilica.lemur.input.FunctionId-java.lang.Object-java.lang.String-

2 Likes

Thank you very much for your tip. This is what I need. I totally missed it

1 Like
/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package GUI;

import CameraAndMouse.CamAndMouseCur;
import CameraAndMouse.SelectUnit;
import SelectUnit.UnitGlobalData;
import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import static com.jme3.app.SimpleApplication.INPUT_MAPPING_EXIT;
import com.jme3.app.StatsAppState;
import com.jme3.app.StatsView;
import com.jme3.app.state.BaseAppState;
import com.jme3.app.state.ScreenshotAppState;
import com.jme3.asset.AssetManager;
import com.jme3.asset.DesktopAssetManager;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.export.binary.BinaryExporter;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Ray;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.shape.Quad;
import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Image;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture2D;
import com.jme3.util.BufferUtils;
import com.simsilica.lemur.Axis;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Checkbox;
import com.simsilica.lemur.Command;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.FillMode;
import com.simsilica.lemur.GridPanel;
import com.simsilica.lemur.GuiGlobals;
import com.simsilica.lemur.Insets3f;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.LayerComparator;
import com.simsilica.lemur.Panel;
import com.simsilica.lemur.PasswordField;
import com.simsilica.lemur.TextField;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.event.CursorButtonEvent;
import com.simsilica.lemur.event.CursorEventControl;
import com.simsilica.lemur.event.CursorMotionEvent;
import com.simsilica.lemur.event.DefaultCursorListener;
import com.simsilica.lemur.event.MouseEventControl;
import static com.simsilica.lemur.focus.FocusNavigationFunctions.F_ACTIVATE;
import com.simsilica.lemur.input.AnalogFunctionListener;
import com.simsilica.lemur.input.FunctionId;
import com.simsilica.lemur.input.InputMapper;
import com.simsilica.lemur.input.InputState;
import com.simsilica.lemur.input.StateFunctionListener;
import com.simsilica.lemur.style.Attributes;
import com.simsilica.lemur.style.BaseStyles;
import com.simsilica.lemur.style.Styles;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.FloatBuffer;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import mygame.Main;
import static scenario.scenarioState.mapGrid3D;

/**
 * 游戏UI部分
 *
 * @author Icyboxs
 */
public class UI extends BaseAppState implements AnalogFunctionListener, StateFunctionListener{

    private static Logger log = Logger.getLogger(UI.class.toString());
    private InputManager inputManager;
    private InputMapper inputMapper;
    private AssetManager assetManager;
    private SimpleApplication simpleApp;
    private BitmapFont font;
    private Camera cam;
    private Node iMap = new Node("miniMap");
    private Node info = new Node("infowindow");
    private Node directive = new Node("directive");
    private Node checkboxUI= new Node("checkboxUI");
    private BitmapText bt;

    private ViewPort vp;

    private Quaternion camQuaternion = new Quaternion();
    private CollisionResults results = new CollisionResults();

    private CollisionResults iresults = new CollisionResults();

    float[] vertices = new float[4 * 3];
    short[] indices = {0, 1, 2, 3, 0};
    private Mesh mesh = new Mesh();
    private Camera cam4;

    private float CamLeftMax = mapGrid3D.getXLength() - (mapGrid3D.getXLength() * 0.1f);
    private float CamRightMin = mapGrid3D.getXLength() * 0.1f;
    private float CamUpMax = mapGrid3D.getZWidth() - (mapGrid3D.getZWidth() * 0.1f);
    private float CamBackwardMin = -(mapGrid3D.getZWidth() * 0.01f);
    
     public static final FunctionId FidQ = new FunctionId("KEY", "Q");

    @Override
    protected void initialize(Application aplctn) {
        simpleApp = (SimpleApplication) aplctn;
        assetManager = aplctn.getAssetManager();
        inputManager = aplctn.getInputManager();
        
        inputManager.deleteMapping(INPUT_MAPPING_EXIT);
        cam = simpleApp.getCamera();

        GuiGlobals.initialize(simpleApp);
        if( inputMapper == null ){
        inputMapper = GuiGlobals.getInstance().getInputMapper();
        }
        inputMapper.map( FidQ,KeyInput.KEY_Q);
        
        StatsAppState statsState = simpleApp.getStateManager().getState(StatsAppState.class);
        BitmapText fps = statsState.getFpsText();
        StatsView stats = statsState.getStatsView();
        fps.setLocalTranslation(0, cam.getHeight(), 0);
        fps.setColor(ColorRGBA.Blue);
        stats.setLocalTranslation(0, cam.getHeight() - 165, 0);
        //simpleApp.getRootNode().attachChild(MapUIBox);
        // Setup fourth view
        float farPlane = 4096.0f;

        cam4 = cam.clone();

        //调整这里增加便宜了可以调整Texture2D texture的边距
        cam4.setViewPort(0, (cam.getWidth() / 4f) / cam.getWidth(), 0, (cam.getWidth() / 4f) / cam.getWidth());

        cam4.setLocation(new Vector3f(1024, 300, 1024));
        camQuaternion = camQuaternion.fromAngleAxis(90 * FastMath.DEG_TO_RAD, Vector3f.UNIT_X);
        cam4.setRotation(cam4.getRotation().set(camQuaternion));
        cam4.setFrustumFar(farPlane);
        float frustumScale = 8;
        cam4.setFrustumLeft(cam4.getFrustumLeft() * frustumScale);
        cam4.setFrustumRight(cam4.getFrustumRight() * frustumScale);
        cam4.setFrustumTop(cam4.getFrustumTop() * frustumScale);
        cam4.setFrustumBottom(cam4.getFrustumBottom() * frustumScale);
        cam4.resize(cam.getHeight(), cam.getHeight(), true);
        System.out.println(cam4.getWidth() + "," + cam4.getHeight() + "--cam4");
        //vp = simpleApp.getRenderManager().createMainView("Top Right", cam4);
        vp = simpleApp.getRenderManager().createPreView("MiniMapCam", cam4);

        vp.setBackgroundColor(ColorRGBA.Blue);
        vp.setClearFlags(true, true, true);
        vp.attachScene(simpleApp.getRootNode().getChild("MapNode"));
        vp.attachScene(Main.MapUIBox);
        //simpleApp.getRootNode().attachChild(Main.MapUIBox);
//        simpleApp.getViewPort().detachScene(simpleApp.getRootNode());
//        simpleApp.getViewPort().attachScene(simpleApp.getRootNode().getChild("MapNode"));
//
//        for (int i = 0; i < simpleApp.getRootNode().getChildren().size(); i++) {
//            System.out.println(simpleApp.getRootNode().getChild(i));
//            simpleApp.getViewPort().attachScene(simpleApp.getRootNode().getChild(i));
//        }
//        simpleApp.getViewPort().detachScene(MapUIBox);
//        simpleApp.getViewPort().detachScene(simpleApp.getRootNode().getChild("quadBox"));

        //Object Url = assetManager.loadAsset("Textures/UI/myCoolStyle.groovy");
        //   Texture t1= assetManager.loadTexture("Textures/UI/Steampunk_UI_Buttons_1.png");
        // BaseStyles.loadStyleResources("groovy/glass-styles.groovy");
        BaseStyles.loadStyleResources("/Textures/UI/myCoolStyle.groovy");

        GuiGlobals.getInstance().getStyles().setDefaultStyle("myglass");

//       BaseStyles.loadGlassStyle();
//       GuiGlobals.getInstance().getStyles().setDefaultStyle("glass");
        font = assetManager.loadFont("Textures/font/FontCJK/fontCJK.fnt");
        
        GuiGlobals.getInstance().getStyles().setDefault(font);
        
        
        

        inputMapper.addAnalogListener(this, FidQ);
        //inputMapper.addStateListener(this, FidQ);
    }

    @Override
    protected void cleanup(Application app) {

    }

    @Override
    protected void onEnable() {
        //vp.attachScene(simpleApp.getRootNode().getChild("MiniCam"));
        mesh.setMode(Mesh.Mode.LineStrip);
        Geometry gridGeometry = new Geometry("camT", mesh);

        Material Material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        Material.setColor("Color", ColorRGBA.White);
        Material.getAdditionalRenderState().setWireframe(true);
        gridGeometry.setMaterial(Material);
        Main.MapUIBox.attachChild(gridGeometry);

//        Container checkbox = new Container("myglass");
//        checkboxUI.attachChild(checkbox);
//        simpleApp.getGuiNode().attachChild(checkboxUI);
//        checkbox.setPreferredSize(new Vector3f(cam.getWidth(), cam.getHeight(), 0));
//        checkbox.setLocalTranslation(cam.getWidth() / 1.25f, cam.getHeight() / 4, 0);
//        checkbox.setBackground(new QuadBackgroundComponent(ColorRGBA.Red));
        
        Container checkbox = new Container();
        checkboxUI.attachChild(checkbox);
        simpleApp.getGuiNode().attachChild(checkboxUI);
        checkbox.setPreferredSize(new Vector3f(cam.getWidth(), cam.getHeight(), 0));
        checkbox.setLocalTranslation(0, cam.getHeight(), 0);
        checkbox.setBackground(new QuadBackgroundComponent(ColorRGBA.fromRGBA255(0, 0, 0, 0)));
////信息栏
//        
//
//        Container infoWindow = new Container("containerStyle");
//        simpleApp.getGuiNode().attachChild(info);
//        info.attachChild(infoWindow);
//        infoWindow.setPreferredSize(new Vector3f(cam.getWidth() / 2, cam.getHeight() / 4, 0));
//        infoWindow.setLocalTranslation(cam.getWidth() / 4f, cam.getHeight() / 4, 0);
//        infoWindow.setBackground(new QuadBackgroundComponent(ColorRGBA.White));
        //小地图
        initialisationMiniMap();
        Texture texture = assetManager.loadTexture("/Textures/UI/button.png");
        ButtonStyle buttonStyle = new ButtonStyle(GuiGlobals.getInstance().getStyles(), texture);
//
//命令栏
        Container directiveWindow = new Container("myglass");
 
        directive.attachChild(directiveWindow);
        simpleApp.getGuiNode().attachChild(directive);
        directive.getLocalTranslation().setZ(1);
        directiveWindow.setPreferredSize(new Vector3f(cam.getWidth() / 5f, cam.getHeight() / 4, 0));
        directiveWindow.setLocalTranslation(cam.getWidth() / 1.25f, cam.getHeight() / 4, 0);
        directiveWindow.setBackground(new QuadBackgroundComponent(ColorRGBA.Red));
        CommandButton(directiveWindow);
    }

    @Override
    protected void onDisable() {

    }

    private void checkCollisionWithRay(Ray ray, CollisionResults results) {
        Main.MapUIBox.getChild("quadBox").collideWith(ray, results);
    }

    /**
     * 绘制小地图上的梯形
     *
     * @param results
     * @param vertices
     * @param indexX
     * @param indexY
     * @param indexZ
     */
    private void setMiniMapTrapezoidalMesh(CollisionResults results, float[] vertices, int indexX, int indexY, int indexZ) {
        CollisionResult closest = results.getClosestCollision();
        if (closest != null) {
            Vector3f contactPoint = closest.getContactPoint();
            // System.err.println(contactPoint + "," + indexX + "," + indexY + "," + indexZ);
            if (contactPoint != null) {
                float x = contactPoint.x;
                float z = contactPoint.z;
                if (x > 2048) {
                    x = 2048;
                } else if (x < 0) {
                    x = 0;
                }
                if (z > 2048) {
                    z = 2048;
                } else if (z < 0) {
                    z = 0;
                }
                vertices[indexX] = x;
                vertices[indexY] = 1;
                vertices[indexZ] = z;
            }

        } else {
            if (indexZ == 2) {
                vertices[indexZ] = vertices[5];
            }
            if (indexZ == 5) {
                vertices[indexZ] = vertices[2];
            }
            if (indexZ == 8) {
                vertices[indexZ] = vertices[11];
            }
            if (indexZ == 11) {
                vertices[indexZ] = vertices[8];
            }
            if (indexX == 0) {
                vertices[indexX] = vertices[9];
            }
            if (indexX == 3) {
                vertices[indexX] = vertices[6];
            }
            if (indexX == 6) {
                vertices[indexX] = vertices[3];
            }
            if (indexX == 9) {
                vertices[indexX] = vertices[0];
            }

        }
        iresults.clear();
    }

    @Override
    public void update(float tpf) {

        // 获取屏幕上的点的世界坐标
        Vector3f click3d0 = cam.getWorldCoordinates(new Vector2f(0, 0), 0f);
        Vector3f click3d1 = cam.getWorldCoordinates(new Vector2f(cam.getWidth(), 0), 0f);
        Vector3f click3d2 = cam.getWorldCoordinates(new Vector2f(cam.getWidth(), cam.getHeight()), 0f);
        Vector3f click3d3 = cam.getWorldCoordinates(new Vector2f(0, cam.getHeight()), 0f);

//        Vector3f CamMid = cam.getWorldCoordinates(new Vector2f(cam.getWidth()/2, cam.getHeight()/2), 0f);
        // 计算方向
        Vector3f dir0 = click3d0.subtract(cam.getLocation());
        Vector3f dir1 = click3d1.subtract(cam.getLocation());
        Vector3f dir2 = click3d2.subtract(cam.getLocation());
        Vector3f dir3 = click3d3.subtract(cam.getLocation());
//        Vector3f dir4 = click3d3.subtract(cam.getLocation());

        dir0.normalizeLocal();
        dir1.normalizeLocal();
        dir2.normalizeLocal();
        dir3.normalizeLocal();
//        dir4.normalizeLocal();

        // 创建射线并进行碰撞检测
        checkCollisionWithRay(new Ray(click3d0, dir0), iresults);
        setMiniMapTrapezoidalMesh(iresults, vertices, 0, 1, 2);
        checkCollisionWithRay(new Ray(click3d1, dir1), iresults);
        setMiniMapTrapezoidalMesh(iresults, vertices, 3, 4, 5);
        checkCollisionWithRay(new Ray(click3d2, dir2), iresults);
        setMiniMapTrapezoidalMesh(iresults, vertices, 6, 7, 8);
        checkCollisionWithRay(new Ray(click3d3, dir3), iresults);
        setMiniMapTrapezoidalMesh(iresults, vertices, 9, 10, 11);

        mesh.setBuffer(VertexBuffer.Type.Position, 3, vertices);
        mesh.setBuffer(VertexBuffer.Type.Index, 3, BufferUtils.createShortBuffer(indices));
        mesh.updateBound();

    }

    public void initialisationMiniMap() {
        Container window = new Container("containerStyle");
        FrameBuffer framebuffer = new FrameBuffer(cam4.getWidth(), cam4.getHeight(), 1);
        Texture2D texture = new Texture2D(cam4.getHeight() / 4, cam4.getHeight() / 4, 1, Image.Format.RGBA8);
        framebuffer.addColorTarget(FrameBuffer.FrameBufferTarget.newTarget(texture));
        vp.setOutputFrameBuffer(framebuffer);

        iMap.attachChild(window);
        iMap.getLocalTranslation().setZ(1);
        //iMap.attachChild(minimap);
        simpleApp.getGuiNode().attachChild(iMap);

        // window.addChild(minimap);
        window.setLocalTranslation(0, cam.getHeight() / 4, 0);
        window.setPreferredSize(new Vector3f(cam.getHeight() / 4, cam.getHeight() / 4, 0));
        window.addChild(new Container("myglass"));
        window.setBackground(new QuadBackgroundComponent(ColorRGBA.White));
        //创建一个 Panel 作为背景
        Container BackgroundPanel = new Container("containerStyle");
        BackgroundPanel.setPreferredSize(window.getPreferredSize()); // 设置大小
        BackgroundPanel.setBackground(new QuadBackgroundComponent(ColorRGBA.Black));
        System.out.println(window.getPreferredSize());
        System.out.println(iMap.getChildren());
        // 设置容器的边界留白
        Insets3f insets = new Insets3f(cam.getHeight() / 4 * 0.05f, cam.getHeight() / 4 * 0.05f, cam.getHeight() / 4 * 0.05f, cam.getHeight() / 4 * 0.05f);
        BackgroundPanel.setInsets(insets);
        //创建一个 Panel 作为小地图纹理填充
        Container MiniMapPanel = new Container("containerStyle");
        MiniMapPanel.setPreferredSize(BackgroundPanel.getPreferredSize());
        MiniMapPanel.setBackground(new QuadBackgroundComponent(texture));

        BackgroundPanel.addChild(MiniMapPanel);
        // 将边框添加到容器中
        window.addChild(BackgroundPanel);

        CursorEventControl.addListenersToSpatial(BackgroundPanel, new DefaultCursorListener() {
            boolean pressed = false;

            @Override
            protected void click(CursorButtonEvent event, Spatial target, Spatial capture) {

            }

            @Override
            public void cursorButtonEvent(CursorButtonEvent event, Spatial target, Spatial capture) {

                System.err.println("cursorButtonEvent," + event);
                if (event.getButtonIndex() == 0) {
                    pressed = event.isPressed();

                } else {
                    event.setConsumed();
                }

            }

            @Override
            public void cursorEntered(CursorMotionEvent event, Spatial target, Spatial capture) {

            }

            @Override
            public void cursorExited(CursorMotionEvent event, Spatial target, Spatial capture) {

            }

            @Override
            public void cursorMoved(CursorMotionEvent event, Spatial target, Spatial capture) {
                if (pressed) {
                    float widthScale = (float) 2048 / BackgroundPanel.getPreferredSize().x;
                    float heightScale = (float) 2048 / BackgroundPanel.getPreferredSize().y;

                    // 获取相机当前位置
                    Vector3f camLocation = cam.getLocation();

                    // 根据比例更新相机位置
                    float newX = 2048 - event.getX() * widthScale;
                    float newZ = event.getY() * heightScale - 200;
                    if (newX >= CamLeftMax) {
                        newX = CamLeftMax;
                    }
                    if (newX <= CamRightMin) {
                        newX = CamRightMin;
                    }
                    if (newZ >= CamUpMax) {
                        newZ = CamUpMax;
                    }
                    if (newZ <= CamBackwardMin) {
                        newZ = CamBackwardMin;
                    }
                    // 设置相机的新位置
                    cam.setLocation(new Vector3f(newX, camLocation.y, newZ));
                    // System.err.println(widthScale+","+heightScale);
                }
            }
        });
    }

    public void CommandButton(Container directiveWindow) {
        
        Button Q = directiveWindow.addChild(new Button("Q", "ButtonGlass"), 0, 0);

        Button W = directiveWindow.addChild(new Button("W", "ButtonGlass"), 0, 1);

        Button E = directiveWindow.addChild(new Button("E", "ButtonGlass"), 0, 2);

        Button R = directiveWindow.addChild(new Button("R", "ButtonGlass"), 0, 3);

        Button T = directiveWindow.addChild(new Button("T", "ButtonGlass"), 0, 4);

    }

    @Override
    public void valueActive(FunctionId func, double value, double tpf) {
        System.err.println(func);
        if (func == FidQ) {
            System.err.println("Pressed Q on the keyboard.");
        }
    }

    @Override
    public void valueChanged(FunctionId func, InputState value, double tpf) {
        if (func == FidQ) {
            System.err.println("Pressed Q on the keyboard.");
        }
    }

}

I’m so sorry to bother you again.
I didn’t succeed to use inputMapper, I don’t know why he didn’t work, I tried to write it like the demo but it didn’t work.
I tried to initialise inputMapper using these

public static final FunctionId FidQ = new FunctionId("KEY", "Q");
        GuiGlobals.initialize(simpleApp);
        if( inputMapper == null ){
        inputMapper = GuiGlobals.getInstance().getInputMapper();
        }
        inputMapper.map( FidQ,KeyInput.KEY_Q);
        inputMapper.addAnalogListener(this, FidQ);
        inputMapper.addStateListener(this, FidQ);
    @Override
    public void valueActive(FunctionId func, double value, double tpf) {
        System.err.println(func);
        if (func == FidQ) {
            System.err.println("Pressed Q on the keyboard.");
        }
    }

    @Override
    public void valueChanged(FunctionId func, InputState value, double tpf) {
        if (func == FidQ) {
            System.err.println("Pressed Q on the keyboard.");
        }
    }

But when I press Q, nothing seems to happen.

Not sure why it’s not working.

Try creating a simple one class test case that illustrates the problem without any of the other stuff.

Have your tried running the demo code from the Lemur Gem?

Well, it was my carelessness that caused the mistake.
I found out through this link that the mapped keys can be triggered if they are not grouped

This made me suddenly understand why then I did a search on Lemur’s content and then did a comparison and I realised that I was missing activateGroup, then the thought process became clear if I didn’t activate the grouping it certainly wouldn’t have worked! :sweat: :sweat_drops:

Hopefully, this content will keep others from making the same stupid mistakes I did :sweat:

2 Likes