Friday, March 21, 2014

Rc Car Game: 1

For the past several months I've been working on an RC car racing game, similar in style to Re-Volt (a classic for those who haven't played it). Here is a video of what I have so far.


As you can see it's currently pretty rough and all. I had to write my own custom vehicle class because the native jBullet vehicle didn't like wheel collisions. With RC-cars they are all basically monster trucks and the wheels need to collide with and roll over obstacles. The method I wound up using attaches a physics object to the chassis via a custom slider joint (a spring that can also rotate). Each wheel calculates it's own, local physics as opposed to the more common method where the vehicle looks at 4 separate rays and does the physics all at once. The wheels don't actually spin though, they just slide across the ground. This means overall lower performance, though I can run up to about 14 cars on my i-7 before the lag becomes unbearable. I've tested it on a friends Macbook and she could run around 10 cars, so for the time being I'm relatively happy.

The cars are all stored in a simple Xml document which links to their model, texture, and lists their wheels and the stats for all of the above. I plan on moving a number of the stats to wheel and engine objects which will be their own separate Xml files in the future. I hope that in the final game the player will be able to choose chassis - body type - wheels - engine - transmission and be able to customize the suspension just like you can with a real RC car.

This isn't going to be a simulator though! I like arcade-y fun. There will be weapons, power-ups, and ridiculous AI. I also currently support local co-op via keyboard sharing, and I plan on adding network multi-player. Joystick support will be incoming soon as well.

This will be a paid game when it releases though I have been toying with the idea of making these super early development builds free to play at some point. I plan on releasing the game Minecraft style, with cheaper alpha - beta builds and slowly increment the price until release.

Let me know what you all think and if you'd like to see some more footage or any articles of how it's done! I'd gladly share some code if anyone is interested.

Friday, July 26, 2013

Nifty GUI in jMonkeyEngine 101

Today I started working with Nifty GUI. Indeed this GUI system is nifty, but it took me nearly 6 hours to get to work correctly! It turns out it was working for a little bit, and I had a very simple error in the screen.xml file, but it wasn't exactly obvious for awhile.

Why am I starting with the GUI? The GUI isn't the greatest starting point when you have nearly 0 idea of how to make a game, but to me it makes sense. With the GUI I have a logical point to implement any features I want, and they can easily be contained in their own areas. When I want to work on a level, all I need to do is add a button to the Main Menu and boom, there I am at the level I was working on. Of course the GUI relies on all of the basics of programming that I haven't actually talked about yet;objects, classes, fields, methods. Find out how to use those with Java's Documentation.

It's ok if you don't know what each piece of code means at this point, I'll do my best to fill you in.

So first, a little bit about Nifty GUI. Nifty runs via what are called "Screens". Your start menu would be 1 screen, your HUD would be another, your pause menu would be a third, etc.

Inside these screens are "Layers". A layer acts just like a layer in an image editor, it lets you edit things completely separate from other layers. These are good for over-laying your buttons and images.

These layers can be divided into sections called "Panels". Panels cannot over-lap. Panels CAN contain more panels, which are divided into smaller panels.

These 3 concepts are the easy part and are explained moderately well here.

Now onto the actual code behind the NiftyGUI. I will show you how I achieved the simple Gui below.




First you will need a Main class for your project, if you start a new project this should be located at "BasicGame/Source Packages/mygame/Main.Java" and looks like this:



package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;

public class Main extends SimpleApplication {

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

    @Override
    public void simpleInitApp() {
        Box b = new Box(Vector3f.ZERO, 1, 1, 1);
        Geometry geom = new Geometry("Box", b);

        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Blue);
        geom.setMaterial(mat);

        rootNode.attachChild(geom);
        
    }

    @Override
    public void simpleUpdate(float tpf) {

    }

    @Override
    public void simpleRender(RenderManager rm) {

    }
}


Now we need to add a couple lines to this file to make it ready for Nifty.

First we need to import Nifty's packages, com.jme3.niftygui.NiftyJmeDisplay and import de.lessvoid.nifty.Nifty.

Next we need a new NiftyJMEDisplay object, we'll name it niftyDisplay. We also need a new Nifty object, named nifty (keep it simple).

last we add the Nifty to our GUIViewport,

package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.niftygui.NiftyJmeDisplay;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import de.lessvoid.nifty.Nifty;

public class Main extends SimpleApplication {
    
    public static void main(String[] args) {
        Main app = new Main();
        app.start();
    }

    @Override
    public void simpleInitApp() {
        Box b = new Box(Vector3f.ZERO, 1, 1, 1);
        Geometry geom = new Geometry("Box", b);

        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Blue);
        geom.setMaterial(mat);

        rootNode.attachChild(geom);
        
        NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager, inputManager, audioRenderer, guiViewPort);
        Nifty nifty = niftyDisplay.getNifty();
        guiViewPort.addProcessor(niftyDisplay);

        //nifty.setDebugOptionPanelColors(true); //un-comment this line to use DebugPanelColors and make sure Nifty is running correctly.
        
        flyCam.setDragToRotate(true); //detaches camera from mouse unless you click/drag.
    }

    @Override
    public void simpleUpdate(float tpf) {
        //TODO: add update code
    }

    @Override
    public void simpleRender(RenderManager rm) {
        //TODO: add render code
    }
}


If you were to run Main now, you'd probably be upset because nothing has changed. Don't worry, we're about 1/3 of the way finished.

The next part to Nifty is a controller class. To keep our project nice and clean looking let's put this controller class in a new package called mygame.GUI. You typically have a couple controllers for the GUI so in the future we'll put them here.

Right click mygame package, new, other, java,  java package rename to GUI click ok.

Right click your new GUI package, new, javaclass, rename it to MainMenuController and click ok.

Go ahead and copy/paste the following code while I tell you what everything is doing.




package mygame.GUI;

import com.jme3.app.Application;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.screen.Screen;
import de.lessvoid.nifty.screen.ScreenController;

public class MainMenuController extends AbstractAppState implements ScreenController {

  private Application app;
  private AppStateManager stateManager;
  private Nifty nifty;
  private Screen screen;
    
  public MainMenuController() {
  
  }
  
  public void bind(Nifty nifty, Screen screen) {
        this.nifty = nifty;
        this.screen = screen;
  }
  
    public void onStartScreen() {
  }

    public void onEndScreen() {
  }
    
  @Override
  public void initialize(AppStateManager stateManager, Application app) {
    this.app = app;
    this.stateManager = stateManager;
  }
}



First we need to extend our MainMenuController via AbstractAppState. This allows us to use our mainmenugui to change the active appstate (we'll be doing this later for switching game modes).
You also need to implement the ScreenController to allow Nifty to do it's thing.

Next we need some private fields so we can access App, AppStateManager,Nifty and a Screen.

Nifty requires OnStartScreen() and OnEndScreen() to function.

Now that the screen controller is created, we need a niftygui layout. You can do these through Java to implement dynamic GUIs, but I haven't gotten that far yet (remember, I'm learning to?) so let's hit up the XML format instead!

Go to ProjectAssets/Interface, right click and go to new, other, XML, xmlDocument, rename it to "MainMenuLayout", make it well-formed and click ok. Go ahead and replace all the contents inside your new document with what is below.



<?xml version="1.0" encoding="UTF-8"?>

<nifty xmlns="http://nifty-gui.sourceforge.net/nifty.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xsi:schemaLocation="http://nifty-gui.sourceforge.net/nifty.xsd http://nifty-gui.sourceforge.net/nifty.xsd">
    
    <useStyles filename="nifty-default-styles.xml" />
    <useControls filename="nifty-default-controls.xml" />
    

</nifty>


You'll notice the schema location, make sure you include that with your file so the xml editor automatically helps you out while you're on your way!

As stated above, Nifty relies on individual screens to contain content. To create a new screen enter the lines below.


<?xml version="1.0" encoding="UTF-8"?>

<nifty xmlns="http://nifty-gui.sourceforge.net/nifty.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xsi:schemaLocation="http://nifty-gui.sourceforge.net/nifty.xsd http://nifty-gui.sourceforge.net/nifty.xsd">
    
    <useStyles filename="nifty-default-styles.xml" />
    <useControls filename="nifty-default-controls.xml" />
    
    <screen id="start" controller="mygame.GUI.MainMenuController">

    </screen>
</nifty>


Make sure you're pointer is pointing to the correct package with your MainMenuController in it, it's Case Sensitive.

Each screen contains several layers which can be used to over-lay panels, we only need 1 layer for now.


    <screen id="start" controller="mygame.GUI.MainMenuController">
        <layer id="foreground" childLayout="center">
            
        </layer>
    </screen>

Notice the childLayout field? This is how the panels will be aligned inside this layer, you can use "vertical" (panels will start flush against the top of the screen) or "horizontal" (panels will start flush against the left side of the screen) or "center" (panels are centered) I personally like centered for now, it might change depending on the over-all look of our main menu later.

Next we need to create some panels. Remember, panels cannot over-lap one another, but they CAN contain additional panels, so lets make 1 large panel to center everything which will have 3 smaller panels inside of it to be used as buttons.


    <screen id="start" controller="mygame.GUI.MainMenuController">
        <layer id="foreground" childLayout="center">
            <panel id="panel_background" width = "50%" height="80%"  childLayout="vertical">
                <panel id="panel_top" backgroundColor="#ff0000ff" width="*" height="33%" childLayout="center">
                    
                </panel>
                <panel id="panel_middle" backgroundColor="#1240abff" width="*" height="33%" childLayout="center">
                    
                </panel>
                <panel id="panel_bottom" backgroundColor="#ffff00ff" width="*" height="*" childLayout="center">
                    
                </panel>
            </panel>
        </layer>
    </screen>

All elements except the screen can contain color information in the form of backgroundColor. This is a hex code with 2 additional characters (00-FF) that represent opacity, FF = 100%.

Elements where you define a size in percentage can use "*" to indicate the remaining amount, in this case it is used to represent 100% width and the remaining 33% height.

Now we are almost finished, we have our screen layout defined inside an xml document, we have our screen controller, we're just missing 1 line of code to attach these to our Main class.





package mygame;
import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.niftygui.NiftyJmeDisplay;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import de.lessvoid.nifty.Nifty;
import mygame.GUI.MainMenuController;
public class Main extends SimpleApplication {
    
    private MainMenuController myMainMenuController;
    public static void main(String[] args) {
        Main app = new Main();
        app.start();
    }
    @Override
    public void simpleInitApp() {
        Box b = new Box(Vector3f.ZERO, 1, 1, 1);
        Geometry geom = new Geometry("Box", b);
        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Blue);
        geom.setMaterial(mat);
        rootNode.attachChild(geom);
        
        myMainMenuController = new MainMenuController();
        stateManager.attach(myMainMenuController);
        
        NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager, inputManager, audioRenderer, guiViewPort);
        Nifty nifty = niftyDisplay.getNifty();
        guiViewPort.addProcessor(niftyDisplay);
        nifty.fromXml("Interface/MainMenuLayout.xml", "start", myMainMenuController);
        //nifty.setDebugOptionPanelColors(true);
        
        flyCam.setDragToRotate(true);
    }
    @Override
    public void simpleUpdate(float tpf) {
    }
    @Override
    public void simpleRender(RenderManager rm) {
    }
}

Make sure this is pointing towards your screen layout xml, the "start" screen inside the xml, and your nifty screen controller.

Now if you click run now you'll see an 3 ugly red, blue and yellow boxes. But these are the start to your own gui! The hard part is over, your gui is working, so now it's time to add functionality to it! Check out all available controls over here. I'll be back later with an in-depth look at these controls once I've learned more about them myself!

I hope this helped you get over any problems you had implementing a gui system into your jME3 project, or at the very least I helped you avoid the same headaches I went through.

Feel free to use ALL CODE above in your own projects, commercial or otherwise, without attribution! All of the code you see above was either written entirely by myself, or available through the jME sdk interface in some fashion. Most of the Nifty code was discovered or based on code found through their sourceforge  wiki.

Veteran coders! If you see me doing something deliberately stupid, or perhaps just incorrect or maybe there's an easier way to do it, let me know in the comments! I write these articles to help other newbies over-come the same hurdles I had to, and any additional information or discussion is always welcome.

Tuesday, July 23, 2013

Before you begin...

Before you begin to think to hard about your game, you should first understand at least the concept behind Java and the jMonkey Engine.

Java actually has some very good documentation about where to start located here. These short lessons are very well written and an absolute must for beginning to understand how to make a game.

jMonkey Engine also has some nice tutorials, though these aren't quite as nice as the Java ones, you should at least flip through them and definitely read the Best Practices section.

Those 2 are required reads, even if they do seem difficult to understand. When you start to see the code implemented it starts to make more sense.

Hello!

Hello and welcome to Adventures in jME! This is a blog devoted to my personal struggles with learning Java and using it to make games in the awesome jMonkeyEngine.

I have been interested in game development for years, but mostly dabbled in the art side creating assets or doing some simple scripting in existing games for fun. About 6 months ago I decided to start working on a game. I decided Unity would be a good starting point because of it's ease of use and community. After discovering how many features are really hidden from you until you purchase a professional license, I decided to try my hands at a completely free and open source engine.

I am not a professional programmer. This will probably become readily apparent throughout this blog. I hope that despite my lack of general programming knowledge I can help others over-come the hurdles of learning to program in Java, and get over the nuances of learning to program without schooling in general.

I hope you can stick with me as I pass on what I learn, as I learn it.

Happy Coding!