[SOLVED] How to use Custom Camera?

pspeed
Wouldn’t be hard to link them then right? If Your code is posted in 3 or 4 topics already. Of course I dag through every camera-related topic here and never found an exhaustive answer from You but, well… My vision isn’t perfect.

As for second part of Your answer - is scaring people away from this forums Your job? Because if You don’t want to help it’s fine - I just don’t see the reason to slap semi-answers here and there that may-or-may-not point someone in right direction but never solve anything completely. Try such behaviour on StackExchange, I dare You.

bloodwalker
Looks like we think in similar way. Before You answered I managed to do the grabbing thingy this way:

private CameraNode cameranode;
private Boolean drag=false;    
private void initKeys() {
    inputManager.addMapping("Drag", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
    inputManager.addMapping("Left", new MouseAxisTrigger(MouseInput.AXIS_X, true));
    inputManager.addMapping("Right", new MouseAxisTrigger(MouseInput.AXIS_X, false));
    inputManager.addMapping("Up", new MouseAxisTrigger(MouseInput.AXIS_Y, true));
    inputManager.addMapping("Down", new MouseAxisTrigger(MouseInput.AXIS_Y, false));

    inputManager.addListener(analogListener,"Left", "Right", "Up", "Down");
    inputManager.addListener(actionListener,"Drag");
}
private ActionListener actionListener = new ActionListener() {
    public void onAction(String name, boolean keyPressed, float tpf) {
        if (name.equals("Drag") && keyPressed) {
            drag = true;
        }
        if (name.equals("Drag") && !keyPressed) {
            drag = false;
        }
    }
};
private AnalogListener analogListener = new AnalogListener() {
    public void onAnalog(String name, float value, float tpf) {
        speed = 25;
        if (drag) {
            if (name.equals("Right")) {
                Vector3f v = cameranode.getLocalTranslation();
                cameranode.setLocalTranslation(v.x + value * speed, v.y, v.z);
            }
            if (name.equals("Left")) {
                Vector3f v = cameranode.getLocalTranslation();
                cameranode.setLocalTranslation(v.x - value * speed, v.y, v.z);
            }
            if (name.equals("Up")) {
                Vector3f v = cameranode.getLocalTranslation();
                cameranode.setLocalTranslation(v.x, v.y + value * speed, v.z);
            }
            if (name.equals("Down")) {
                Vector3f v = cameranode.getLocalTranslation();
                cameranode.setLocalTranslation(v.x, v.y - value * speed, v.z);
            }
        }
    }
};

And it works lovely. Scaling the speed so it actually looks like “grabing screen” was a pain but I believe 25 is as close as I can get.

Anyway great thanks man. You were a lot of help. Hope more people were like You :slight_smile:

Which leaves me with one last scenario to learn (funny thing, it’s the one I started from) which is FPS-style camera that only moves in flat way (up-down-left-right) and never rotates. Which means learning how to modify existing cameras in proper way, instead of creating new one. Sadly all wiki tutorials are made with “default settings FTW” philosophy in mind?

Anyone any ideas?

Sorry, my guess was that you had enough Java chops to figure out how to open the two classes I mentioned. They are not complicated to combine… though it does require that you understand how app states work. Which is a good thing to learn because it’s the recommended way… pretty sure there are even tutorials on the tutorials page under documentation in the tutorials section.

JME is one of the best documented open source game engines. We had a dedicated documentation person work a very long time to create the tutorials no one reads. So perhaps you’ll forgive me if I get a little bristly when someone insults the engine and demands code in the same breath.

JME is not a beginners engine. It expects that you already know Java pretty well. There are plenty of engines geared more towards beginners.

Since people don’t always notice that we have a forum search…

By the way, nothing in your posted code rotates… so either we are missing important code in what you have or you still have a second camera somewhere doing rotation.

From bottom to top:

  • Nothing in my code rotates because I don’t want anything to rotate. I wrote few times already: rotation is the very thing that I want OUT of the picture.

  • I’ve seen this topic already and didn’t see what I was looking for there. But I’ll have a closer look in a moment, maybe I missed something.

  • I jumped here from Kivy (not exactly game engine but it have enough features to be used as one) and it really have better documentation. I mean “example based” one. Every existing function have self-contained example to check if it works or not. And it really helps like a lot. And no, I never meant to insult engine - quite the contrary, I said it’s awesome, just the documentations is lacking (guess we come from different environments thus our definition of good documentation differ).

  • Also “demands code” isn’t a very good choice of words. I don’t demand anything, I came here for help and if someone is nice enough to provide this help I’m glad and thankfull. If not - why write at all? Also like every programmer I’m using mostly StackExchange for solving problems and there providing code with the answer is the law. And it’s the best thing ever invented to be honest, because it helps both people who ask (answers wait there forever in case someone else needs them) and people who answer (You don’t need to answer same question many times in case someone doesn’t understand different part of the code than the guy before him - and that’s because the answer IS the whole code).

  • And yes, You are right, I have absolutely no idea how app states work. Not to mention what they are. I just ran through the basic tutorials and try to apply that to some real conditions. Camera-Stuff seem to be first wall I wasn’t able to break with my head, that’s why I ended up here.

  • So if You want to help, please lower Yourself to my level and provide examples so I can reverse engineer them (that’s best way of learning for me - “break car into pieces and try to rebuild it”, which requires having the car at some point obviously). And if You don’t want to help it’s also fine. Just don’t jump on me just because I don’t know stuff. If I knew I wouldn’t need help right?

So are we fine? Did we clear the air a little? Cause I really don’t need any low-flying tomahawks…
Btw. I really loved the idea You posted in that other topic:

[quote=“pspeed, post:25, topic:33131, full:true”]
A tongue-in-cheek solution:
Step 1: Open FlyBycam.java
Step 2: Ctrl-A
Step 3: Ctrl-C
Step 4: Open a new file MyFlyCam.java
Step 5: Ctrl-V
Step 6: Change class name to MyFlyCam.java and constructor
Step 7: Change mappings as needed.[/quote]
… and It would be absolutely awesome if You posted Steps 8 to X (where X is the point at which You run the app and this app uses duplicated-and-modified FlyByCamera instead of default FlyByCamera). Because obviously just creating such class in my Package and turning default camera off isn’t the whole story.

I use Stack Overflow since I get a lot of answers there :stuck_out_tongue: I never heard of StackExchange till now

as for learning JME, I think you should get one of the suggested books that have better explanations than the tutorials here.

http://jmonkeyengine.org/230076/book-released-jmonkeyengine-3-0-beginners-guide/

JME is a bit demanding from the user, meaning that you need to defend yourself with Java before using the engine. I tried twice using it years ago but I lacked experience. Now I am a full user. JME has excellent documentation but it does not assume you are a total beginner. Get one of the books I listed and they will help you a lot more (I have them both)

Thanks I’ll check those books out :smile:
As for StackExchange it’s the superset of Stack Overflow. Stack Overflow can be defined as “forum section” aimed at strict programming. Other StackExchange subsets fill the topics like graphics, advanced math, server stuff etc.
Catch: http://stackexchange.com/sites# :smile:

P.S. Defending with Java is not a problem… It’s 3D environment and it’s concepts that are like whole new planet to me. But I’ll catch up quickly with people like You around ^^’

Ok, I’m back from vacation which means back to my little learning project… I have:

import com.jme3.app.SimpleApplication;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.*;
import com.jme3.light.AmbientLight;
import com.jme3.light.PointLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.CameraControl;
    
public class Test3Wlasny extends SimpleApplication {

    public static void main(String[] args) {
        Test3Wlasny app = new Test3Wlasny();
        app.start();
    }

    //CAMERA PART//
    private CameraNode cameranode;

    private Boolean drag=false;

    private void initKeys() {
        inputManager.addMapping("Drag", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
        inputManager.addMapping("Left", new MouseAxisTrigger(MouseInput.AXIS_X, true));
        inputManager.addMapping("Right", new MouseAxisTrigger(MouseInput.AXIS_X, false));
        inputManager.addMapping("Up", new MouseAxisTrigger(MouseInput.AXIS_Y, true));
        inputManager.addMapping("Down", new MouseAxisTrigger(MouseInput.AXIS_Y, false));

        inputManager.addListener(analogListener,"Left", "Right", "Up", "Down");
        inputManager.addListener(actionListener,"Drag");
    }
    private ActionListener actionListener = new ActionListener() {
        public void onAction(String name, boolean keyPressed, float tpf) {
            if (name.equals("Drag") && keyPressed) {
                drag = true;
            }
            if (name.equals("Drag") && !keyPressed) {
                drag = false;
            }
        }
    };
    private AnalogListener analogListener = new AnalogListener() {
        public void onAnalog(String name, float value, float tpf) {
            speed = 25;
            if (drag) {
                if (name.equals("Right")) {
                    Vector3f v = cameranode.getLocalTranslation();
                    cameranode.setLocalTranslation(v.x + value * speed, v.y, v.z);
                }
                if (name.equals("Left")) {
                    Vector3f v = cameranode.getLocalTranslation();
                    cameranode.setLocalTranslation(v.x - value * speed, v.y, v.z);
                }
                if (name.equals("Up")) {
                    Vector3f v = cameranode.getLocalTranslation();
                    cameranode.setLocalTranslation(v.x, v.y + value * speed, v.z);
                }
                if (name.equals("Down")) {
                    Vector3f v = cameranode.getLocalTranslation();
                    cameranode.setLocalTranslation(v.x, v.y - value * speed, v.z);
                }
            }
        }
    };
    //END OF CAMERA PART//

    public void simpleInitApp() {

        flyCam.setEnabled(false);
        initKeys();

        cameranode = new CameraNode("Main Camera", getCamera());
        cameranode.setControlDir(CameraControl.ControlDirection.SpatialToCamera);
        rootNode.attachChild(cameranode);
        cameranode.setLocalTranslation(0, -2, -20);

        Node Box1 = new Node("Box1");
        rootNode.attachChild(Box1);
        Box1.setLocalTranslation(-4, 0, -2);
        Node Box2 = new Node("Box2");
        rootNode.attachChild(Box2);
        Box2.setLocalTranslation(2, 0, -2);
        Node Box3 = new Node("Box3");
        rootNode.attachChild(Box3);
        Box3.setLocalTranslation(-2, -1, -2);
        Node Box4 = new Node("Box4");
        rootNode.attachChild(Box4);
        Box4.setLocalTranslation(4, -1, -2);

        Spatial Kostka1 = assetManager.loadModel("Models/U1.obj");
        Box1.attachChild(Kostka1);
        Spatial Kostka2 = assetManager.loadModel("Models/U1.obj");
        Box2.attachChild(Kostka2);
        Spatial Kostka3 = assetManager.loadModel("Models/Kostka1.obj");
        Box3.attachChild(Kostka3);
        Spatial Kostka4 = assetManager.loadModel("Models/Kostka1.obj");
        Box4.attachChild(Kostka4);
     
        PointLight lamp_light = new PointLight();
        lamp_light.setColor(ColorRGBA.White.mult(1.5f));
        lamp_light.setRadius(80f);
        rootNode.addLight(lamp_light);

        AmbientLight al = new AmbientLight();
        al.setColor(ColorRGBA.White.mult(0.5f));
        rootNode.addLight(al);
    }   
}

What I have here is just a simple scene with several objects added (my assets from blender, global light and point light). What I need to do now is split this stuff into several classes. As far as I can kick my Boxes out and they still work, the CameraNode solution gives me a little sweat. How can I put whole camera node stuff in other class so I can just put something like “MyCameraNodeClass Camera = new MyCameraNodeClass” in my init function?

What I tried so far:

  • Moving my CAMERA PART to a new class, create constructor inside it and put initKeys inside it.
    [Here I got trouble with inputManager not being recognized, as my new class extends “CameraNode”.]

  • Create static connection between my main app class and new camera node class to be able to use “inputManager”.
    [I solved the problem above but instead I got a crash after application starts (no debug issues) with red lines pointing me near those lines:

    cameranode = new CameraNodeTest1(“Main Camera”, getCamera());
    cameranode.setControlDir(CameraControl.ControlDirection.SpatialToCamera);
    cameranode.setLocalTranslation(0, -2, -20);
    rootNode.attachChild(cameranode);

So how do I do it properly? I mean kicking whole camera node code to a class outside the main one…

create an AppState

then attach the AppState into your main app.

Care to elaborate? I hope oneliners aren’t “a thing” here, because I really hate Hollywood’ish style…

[EDIT] Did it with appstate using this:
[AppStates Demo][1]
[1]: http://wiki.jmonkeyengine.org/doku.php/jme3:advanced:appstatesdemo
tutorial. And it works. But it’s as far from what I want to achieve as possible.

What I want is having whole camera node stuff in separate class. So I can (for example) load this camera inside several appstates if I want to. And most importantly I want my code clean of camera related stuff.

I’m not sure what you mean here. There is only one camera connected to the screen, right? And that’s what an app state easily gives you. All of your code except the app state will be clean of camera related stuff.

So if I have for example 10 appstates (let’s call them “game levels” for the sake of explanation) and I want the very same camera control on each and every one of them I need to write camera code 10 times (I pollute every appstate with my camera code)?

I want to write camera code once (I use the cameranode way from bloodwalker as You can see in my code) and then just create instance of my cameranode every time I need it and kill that node also every time I want to.

Why would you include that in all of the different app states?

Attach your game level state. Attach your camera control thingy state. Attach all the states you want… that’s what they are for.

Oh for lords sake, could You please think like an academic for a moment? Ever heard of learning stuff for the heck of it? I don’t experiment with stuff because I want to make an actuall game (or maybe I will, dunno at this point). I do this just to stretch the possibilities…

If it helps You try to vizualize a single screen (created as single appstate) divided into gazillion small views, each with it’s own camera instance. Each with “drag’n’drop” camera control and mouse moving freely above all of them.

P.S. I’m still waiting for “just a little example” for the Topic-Title-Questions from You. By which I mean creating my own camera (not cameranode) class and how to “apply” it to actual app. I’ll accept even appstate solution just as long as I can tinker with actual camera settings in separate class.

I give you the link to the doc that is longer than one line.
AppState are not only to define scene (level). It’s the way to modularize your app, by stacking application’s aspect.

// pseudo code
app.attach(new AppState_Level01(...))
app.attach(new AppState_CameraDriver(...))
app.attach(new AppState_Tools01(...))

And you can move in AppState_CameraDriver the code of your test app, juste rename SimpleApplication method name by equivalent in AppState lifecycle. (I’m not on my working desktop).

I did that already David, thanks. And it works (which I wrote just after Your first post as an EDIT option).

But I still need to know the alternative (which is outsourcing camera node code as simple java class, not an appstate).

And also I still need to know the alternative to whole camera node (the thing I wrote in previous post).

I guess we have some misunderstand. Can you share your AppState with camera stuff ?
The Appstate for camera stuff is reusable across your 10 levels, and only take care of this.
I also use an alternative approach but before share it, I would like to understand why appstate doesn’t match your request. (the other approach introduce more freedom and responsability to dev).

EDIT: before I discover CameraNode, I drive camera directly, you can see a CameraFollower behavior I made some time ago at (no garanties it’s the best approach):

https://github.com/davidB/vdrones/blob/exp_jmonkey/src/main/java/vdrones/AppStateCamera.java

If you have several viewport + camera (one camera per viewport like describe in doc), you can a single a AppState that choose the right camera/cameraNode to update into your Action/AnalogListener.

But why not do it as an app state? You’d end up manually doing a bunch of stuff the app state already does.

Sorry, next time I will guess which of a million different things you might be trying to do that you didn’t say.

Good luck with your development. I’m officially never responding to you again.