Java-Gaming.org Hi !
Featured games (90)
games approved by the League of Dukes
Games in Showcase (702)
Games in Android Showcase (203)
games submitted by our members
Games in WIP (775)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
   Home   Help   Search   Login   Register   
  Show Posts
Pages: [1] 2
1  Discussions / Java Gaming Wiki / Making a Dynamic Plugin System on: 2016-06-25 00:13:25
You have a project. You need plugins for that project. Plugin, by this definition, is a module loaded which adds functionality to your program.

Lucky, for you, making a plugin system is easy. There are only a few steps you have to follow.
1. Make the loader
2. Make the plugin environment
3. Make the abstract plugin environment
4. Make the plugin
5. Load the plugin

Making a plugin is a pretty lengthy job, but that is only because the amounts of clicks and file exploring involved.

Okay let's get into the meat.

1. Make the loader

The theory of this plugin system goes: you include a jar, which finds a plugin class using a config file. A new instance, utilizing this config file, of this class is then generated and its functionality is used accordingly. Utilizing a configuration file will be necessary. It allows up to point to the Plugin class in the cluster, that is the jar. It will also provide additional information, such as plugin name, version, and other metadata.

1  
2  
3  
final File plugin = new File(location);
final JarFile jf = new JarFile(plugin);
final HashMap<String, String> settings = new HashMap<>();

So the first step in loading is to get the plugin jar file to load. 'location' points to your jar file. 'config' refers to the name of the file, since it will be in the root of said jar. If it isn't in the root, it needs to be pathed accordingly. You create a JarFile from that file, as we are going to get a resource from the jar. This requires that we treat the file as a jar file and get Entries out of the file. We will be getting only the config file, as loading the Plugin class takes a different route. You can alternatively skip the JarFile step in a modded version, given that the config file is outside the jar. It is much neater to include the config file into the jar file, but it is not necessary.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
final BufferedReader br = new BufferedReader(new InputStreamReader(jf.getInputStream(jf.getJarEntry(config))));
String in;
while((in = br.readLine()) != null) {
   if(in.isEmpty() || in.startsWith("#"))
      continue;
   final String[] split = in.split(": ", 2);
   settings.put(split[0], split[1]);
}
br.close();
jf.close();

The next step is to open the config file and read it in; using a basic BufferedReader this is possible. The reason I use BufferedReader is I wanted to read the config file per line, it being a text file of course. You will need to access the jar file by using jarfile.getInputStream() which will open a stream to a zip entry, which jf.getJarEntry's return is an extension of ZipEntry named JarEntry. Then you just load that into a reader for the buffered reader to use.

To read, you just read by line. I chose to delimit keys from values by a ": ". Just to make sure its safe, I put a 2. That way entries like "Example: whatever: is this" is a valid key-pair. The key is "Example" and the value is "whatever: is this".

1  
2  
3  
4  
final Class<?> clazz = Class.forName(settings.get("Main"), true, new URLClassLoader(new URL[]{plugin.toURI().toURL()}));
final Plugin instance = (Plugin) clazz.newInstance();
instance.setConfig(settings);
return instance;

The final step to loading is simple. We will get a class. Class, by nature, is generic and needs a type reference. We can set this to ?. Using Class.forName, you can gain access to a specific resource. You must pass true, because we need the initialized state, but we also need to use the URLClassLoader. UrlClassLoader has a required parameter of URL[] that calls for the classes to be loaded. We only care about one. So you need to cast the File to a URL, after from a URI. I wouldn't recommend wrapping the location variable by new URL, as File will determine pathing better than you might. This way works well. Do not use File.toURL() because thats deprecated :^).
The first parameter comes from the settings that we loaded. 'Main' points to the plugin class, which is the combinations of packages to the plugin class delimited not by "/" but by a period. For example, com.whatever.plugins.Plugin would be an acceptable path to the plugin. Not com.whatever.plugins.Plugin.class, for example. Finally, newInstance() the class and return it. I added, to the plugin class, the config. Just note that for #2.

2. Make the plugin environment

So your plugin needs to have some mass to it. What we want in our plugin is very subjective so I will go over two basic things. Storing the settings and an entry function. You can add fields and functions. The class Plugin is abstract. In #1, I added the setConfig() which you can see working below. I do NOT have a constructor here. The reason is newInstance() doesn't allow passing args. Simples.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
public abstract class Plugin {

   private HashMap<String, String> config;
   
   public void setConfig(HashMap<String, String> config) {
      this.config = config;
   }
   
   public abstract void initialize();
   
   public String getSetting(String setting) {
      return config.get(setting);
   }
   
   public void setSetting(String setting, String value) {
      this.config.put(setting, value);
   }
   
}

This will be extended by the user. So there is no problem here. This is a template class. It allows you to detail what minimum the user needs to do. The program itself will be totally blind to any fields that the user creates inside the extended class of this, just as normal. So when you load a plugin, you can't do PluginLoader.loadPlugin(place, config.cfg).someFieldNotDefinedInPluginClass, but you can do .initialize(). We require the user to @Override initialize and do stuff in it, so anything that that utilizes, such as the fields the user creates when they extend it.

3. Make the abstract plugin environment

Naturally, you will have things inside the Jar that the plugin user will need to use, such as new Vec3() or even jframe.setTitle("Whatever"). Create a new Project. Put all classes the user will use inside the new project. Make all the bodies empty, except for things such as enums. This will make it so the user doesn't utilize the code or anything, because its meant to be a template. Include this Plugin class. Just copy it over without change. Make sure all packages are exact. Jar it.

4. Make the plugin

Making the plugin is simple. Take this jar that you created and put it into a new project. Configure your build path. Create a class, which extends Plugin. This should and will force you to overwrite the initialize abstract void function. Put something simple, like Syso("Testing plugin 123");. Don't use the default package please. Thats gross. Jar it, and then all you need to do is load it and utilize it, but not before making the config.cfg file to determine your main class' location. Here is an example file.

Quote
Name: Test Plugin Example
Main: test.plugin.Example

Inside of settings you will have two things. Name, which points to Test Plugin Example. And Main, which points to test.plugin.Example. Let's connect this back to...
1  
final Class<?> clazz = Class.forName(settings.get("Main"), true, new URLClassLoader(new URL[]{plugin.toURI().toURL()}));

settings.get("Main") points to what I was talking about.

5. Load the plugin

So now let's load it in and utilize it.

1  
2  
final Plugin plugin = PluginLoader.loadPlugin("res/plugins/PluginTest.jar", "config_file.cfg"); //called my config file config_file.cfg, which is in my jar
plugin.initialize(); //this does its thing, which I set to Syso("Testing plugin 123");


And thats all there is to it!

I will edit this post later to include a video of this.

2  Discussions / Java Gaming Wiki / FPS Camera Tutorial on: 2016-05-22 05:40:58
I've noticed the serious lack of good explanation of FPS camera methods. I've seen everything from using cross product to using sketchy pi calculations and back around to poorly explained trigonometry. I am writing this forum post for novices in hopes that a random google search will pick it up... but whoever browses is good too! Smiley

This tutorial is not based off OpenGL and doesn't use 3rd party libraries. I've seen many people use OpenGL fixed function pipeline and many other inadapatable means of showing what entails a FPS camera. So.. that was a problem. I am going the trig route because its fast, simple, and easy to understand. Pure math.

Things you should know before this:
Using trigonometry functions sin, cos, and tan (sin and cos are to be used)

I am writing this in Java, because well... this is JGO.
Okay let's get started!



We are in the main game loop, what we want to do is this:
If a key is down move, in the direction the object is facing, with respect to the key's direction. Also, strafing.



Simple enough. As you see in the picture, I've put out a right triangle on a smiley face. Since, in game, we allot a predefined variable for speed, we can set this as the Hypotenuse, or the distance. In the game, the object has rotation. Let the Yaw value (pitch = x, yaw = y, roll = z) be the angle between the hypotenuse and the adjacent side. I am calling this angle A for alpha, as per the angles name. We have everything we need now.

This is what they mean, in case you had no idea. Sine works with opposite and hypotenuse, Cosine works with adjacent and hypotenuse, and tangent works with opposite and adjacent. We are going to use both Sine and Cosine.
S.oh C.ah T.oa
Sine Cosine Tangent


Looking back at the picture, let's imagine the hypotenuse, coming out of Mr. Smiley, is the direction that we want to go. Now look at the adjacent side and the opposite side... they describe how much you need to "go over" and "go up" in order to reach that goal. Genius right?

So if the adjacent comes out to be 5 and the opposite comes out as 5 (no you don't just get an equilateral triangle) you need to translate your object's x by 5 and y by 5.
Opposite = y
Adjacent = x


We need to do maths for that now.

Here is the formula for the adjacent side (what we are trying to find)
Cos(A) = adj / hyp

Here is the formula for the opposite side (what we are trying to find)
Sin(A) = opp / hyp

Since we have the hypotenuse, and opp and adj are variables, we should multiply hyp over.
hyp * Cos(A) = adj
hyp * Sin(A) = opp


Now we have obvious means.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
// define some variables

float hypotenuse = 1f; // our distance we want to travel
float rotation = 0f; // the rotation of our object around the y axis (yaw), in degrees

// do the calculations

float adjacent = hypotenuse * Math.cos(Math.toRadians(rotation)); // note, toRadians because we were working in degrees
float opposite = hypotenuse * Math.sin(Math.toRadians(rotation)); // cos and sin only accept radians

// move the camera

Camera.x += opposite;
Camera.z += adjacent;


That wasn't so bad. You want to make this code run when you have arrow key up or W pressed. This allows you to move forward. If you want to move backwards instead, repeat the code... but switch the +='s with -=, naturally.

If you increase and decrease the rotation with keys A and D plus move the object as shown, you get a normal FPS camera, but you maybe want strafing. Strafing is the act of looking forward, but moving to the side, still looking forward. Like the hammer time dance.

<a href="http://www.youtube.com/v/otCpCn0l4Wo?version=3&amp;hl=en_US&amp;start=" target="_blank">http://www.youtube.com/v/otCpCn0l4Wo?version=3&amp;hl=en_US&amp;start=</a>

If you think about it, we are going to rotate 90 degrees to the right and 90 degrees to the left then move. Naturally, we want to not alter the rotation permanently, because we don't want to instantly face the way we are walking... or have to translate the rotation back. This would be an example of redundancy. So we will just add 90 degrees to our Yaw (y) temporarily.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
// code as before

float hypotenuse = 1f;
float rotation = 0f;

// manipulated rotation with not permanent 90 degrees

float adjacent = hypotenuse * Math.cos(Math.toRadians(rotation+90));
float opposite = hypotenuse * Math.sin(Math.toRadians(rotation+90));

Camera.x += opposite;
Camera.z += adjacent;


That wasn't so bad. You want to make this code run when you have arrow key left or A pressed. This allows you to move left. If you want to move right instead, repeat the code... but switch the +='s with -=, naturally.

Alternatively, you can do use ternary operations.

1  
float hypotenuse = isADown() || isWDown() ? 1f : isDDown() || isSDown() ? -1f : 0f;


Anything I didn't go over? Any questions? I will edit this post.

3  Discussions / Java Gaming Wiki / Website offering 3D Models specifically for games for free on: 2016-04-29 12:56:17
So during my brief stint as a game developer for the past five years, I experienced the problem of finding low-poly 3d models. All the models I found for free were usually high poly or not well textured.

Which is why I've opened a website to give away all the models I've made during this period so new game developers don't experience the same problem.

http://lowpoly3dmodels.com







4  Discussions / Java Gaming Wiki / Math: Resources on: 2015-10-22 07:46:10

Vectors/Linear Algebra


  • immersivemath is a web site with interactive figures.  The authors are graphics people so the examples might speak to you more than some other presentations of the same material.
5  Discussions / Java Gaming Wiki / Math: Inequality properties on: 2015-09-30 16:06:05
A gentle introduction to the properties of inequalities.

The goal is to give a basic understanding of the basic properties of inequalities.  For more in depth treatment, see the references.  We will only consider mathematical integers and reals and not their computer equivalent (integer and floating-point) to not need to consider issues related to overflow and underflow.  I'm also going to toss in how these are related to geometric operations. (A change of coordinates doesn't change the problem).  The Wikipedia article was the base template for this.  I wanted to say some of the same things but in a different way.  This route allow for comparing the two, which might be helpful for some.

For visualization purposes we can think of the values as being points on a number line and the inequality states how they are ordered on that line.

We start with the basic inequalities:
  • a < b
  • b > a
  • a <= b
  • b >= a

The first two are called strict inequalities and the second two are non-strict.  Note that the values 'a' and 'b' represent arbitrary expressions.  The first says that 'a' is to the left of 'b' on the line. The second says that 'b' is to the right of 'a'. The second pair allow for touching on the line.

By reading the inequalities above from right-to-left we get the converse property:
  • b > a
  • a < b
  • b >= a
  • a <= b

So each pair strict/non-strict are really the same. Where there is no difference in behavior between strict and non-strict, then the non-strict equivalent will be used.  Differences will be explicitly stated.

addition/subtraction
If we add or subtract a value from both sides, it's equivalent to translating the pair and it does not effect the relation.  Given: a >= b, then:
  • a+c >= b+c

comparing against zero
Since we can subtract a value from both sides, we can convert the inequality into a comparison against zero.  Given: a >= b, we can subtract both sides by 'b' or subtract both by 'a', which respectively yield:
  • a-b >= 0
  • 0 >= b-a

multiplication/division
The comparing against zero form converts the relation such that its result only depends on the sign of the expression.  So if we were to multiply by a positive non-zero value c, then the relation doesn't change since the sign does not change. Likewise for division by non-zero positive c.  Given: a >= 0 and c >= 0, then:
  • ac >= 0
  • a/c >= 0

If c is negative then the sign flips and requires inverting the inequality. Given: a >= 0 and c < 0, then:
  • ac <= 0
  • a/c <= 0

Combined with the addition-subtraction property we have:
Givenmultiplydivide
a >= bc>0ac >= bca/c >= b/c
a >= bc<0ac <= bca/c <= b/c

Note this is equivalent to a scaling of the system.

additive inverse
Given: a >= b, Subtracting by both by the LHS and then by the RHS or by multiplying by -1 we get:
  • -a <= -b

This is equivalent to point inversion.

Taking the above results we could list the multiplicative inverse properties, but the main interest here is to reduce the computational complexity of a comparison.  These are listed on Wikipedia.

Applying a function to both sides
This is where shit starts to get Real, baby. Using the above properties allow eliminating redundant computations and nuking divisions.

We gotta use a little bit of math-speak, here are some informal definitions:

Interval: we're going to talk real numbers, so the legal range of values in the inequality. [min,max]

A Monotonic function f(x) is a function that preserves order (Wikipedia, MathWorld).

This implies that the slope (first derivative) of f(x) never changes sign.  (wait for it)

If f(x) has the properties: given a<=b then f(a)<=f(b) for all 'a' and 'b' on the interval, then f(x) preserves order and is monotonically increasing on the interval.

This means that the slope is always positive or zero across the interval. If you scan the graph of f(x) from the low end of the interval (min) to the high end (max) then the 'y' value is always greater than or equal all points below the current 'x'.  Or if we were to think of this function as being how some point moves up and down in time (where x represents time), then as time increases the point is either moving up or not moving.  It never moves down.

If f(x) has the properties: given a<=b then f(a)>=f(b) for all 'a' and 'b' on the interval, then f(x) preserves order (reverses it) and is monotonically decreasing on the interval.

So the slope is always negative or zero across the interval.  Scanning the graph from low to high..y is always smaller or the same than all to the left.  The point in time is always moving down or stationary.

We can apply a monotonically increasing function (on the interval) to both sides of a non-strict inequality without changing the result.
We can apply a monotonically decreasing function (on the interval) to both sides of a non-strict inequality without changing the result if we change to the opposite comparison.

If f(x) has the properties: given a<b then f(a)<f(b) for all 'a' and 'b' on the interval, then f(x) preserves order and is strictly monotonically increasing on the interval.

If f(x) has the properties: given a<b then f(a)>f(b) for all 'a' and 'b' on the interval, then f(x) preserves order (reverses it) and is strictly monotonically decreasing on the interval.

These are simply more strict versions of the increasing/decreasing above.  They disallow the slope to ever be zero (expect at the end-points of the interval).  A strictly increasing function (on the interval) can be applied to both sides of either a strict or non-strict inequality.  And likewise for a strictly decreasing function when you change to the opposite comparison.

We can take the properties above and express them as applying a function to both sides:
Property      FunctionConstraintsSlopeType
addition/subtraction f(x)=x+Knone       f'(x)= 1 strictly increasing
additive inverse     f(x)=-x none       f'(x)=-1 strictly decreasing
multiplication       f(x)=Kx K>0        f'(x)=K  strictly increasing
multiplication       f(x)=Kx K<0        f'(x)=K  strictly decreasing
division             f(x)=x/KK>0        f'(x)=1/Kstrictly increasing
division             f(x)=x/KK<0        f'(x)=1/Kstrictly decreasing

NOTE: that the properties from the first part of this (including the multiplicative inverse that I blew off) can also be use to transform an expression into a form where we apply a function to both sides.  Specifically by changing the interval of the function to where it has one of the properties listed above.

Some example named inequalities
https://en.wikipedia.org/wiki/Triangle_inequality
https://en.wikipedia.org/wiki/List_of_triangle_inequalities

References
6  Discussions / Java Gaming Wiki / Rendering resources on: 2015-08-13 07:40:51
ALSO SEE: List of Learning Resources



General topics

Misc Collections

Blogs

Collection of collection
  • Ke-Sen Huang (Eurographics, SIGGRAPH, SIGGRAPH Asia, and more)

GCD Collections

SIGGRAPH (SEE: Collections of collections)

Antialiasing and releated
7  Discussions / Java Gaming Wiki / Networking Resources on: 2015-08-13 07:40:43
ALSO SEE: List of Learning Resources

http://gafferongames.com/

https://developer.valvesoftware.com/wiki/Latency_Compensating_Methods_in_Client/Server_In-game_Protocol_Design_and_Optimization

Tribe's networking model: http://gamedevs.org/uploads/tribes-networking-model.pdf
8  Game Development / Newbie & Debugging Questions / How Do I Expand My Game? on: 2015-06-14 11:34:43
So, I am new here, and the main reason why I came is because I need help.  I have a game I've been working on as a final project, a sort of rpg, but I actually am very invested in it.  But, it's only text-based, and I'd like to take the next step and move the game out of the console, but I just can never seem to understand graphics, menus, and everything else!  I had something before, but I lost it.  So anyway, if someone could give me an idea on what the next step would be, that would be good.

(post by bashfrog)
9  Discussions / Java Gaming Wiki / Intersection Methods on: 2015-05-29 08:19:33


http://www.realtimerendering.com/intersections.html
10  Discussions / Java Gaming Wiki / Understanding relations between setOrigin, setScale and setPosition in libGdx on: 2014-10-09 22:34:59
For card animations in my Gods of Sparta game I'm using the largest card graphics all around. The cards get scaled and rotated as they move. To rotate the image around it's center, you need to setOrigin to (width/2, height/2). However, the origin is also used for scaling, so if you scale the image it will no longer stay at the same (x,y) position you set with setPosition.

To get the scaled image in some particular position, you need to offset the coordinates. See the image below for the exact math:



We want to position the scaled image to (60,70), but since it has setOrigin, it shows up in a different spot. To place it properly, we need to move it half of the difference between full and scaled image.

Now that we know how it works, it all makes sense. I hope this saves other developers some time.
11  Discussions / Java Gaming Wiki / Definite guide to supporting multiple device resolutions on Android (2014) on: 2014-10-02 22:36:02
Hi all,

I spent some time to investigate all the devices out there and do some analysis on the screen resolutions out there. For 3D games, you don't really care, but if you are making a 2D game you want graphics to be crisp clear. And only way to do that is to use 1:1 pixel mapping, i.e. set the game camera to the same resolution as the device screen.

Of course, this means drawing all the assets in multiple sizes. I found that it not too hard, you can always draw stuff big and scale it down. I also like to use ImageMagick to add text to images that are already scaled down. If it's more complex, you can code it in Java as well. Anyway, drawing is not the problem if you know which resolutions you want to support and how big your pictures should be.

In the end, I came up with six different sizes that should cover 99% of devices that are currently out there. I explained each one in detail. Take a look:

http://bigosaur.com/blog/31-android-resolutions-definite-answer

I hope this helps anyone who starts a new 2D Android game project.
12  Discussions / Java Gaming Wiki / Resources for WIP games on: 2014-08-01 16:19:49
***WIP GAME RESOURCES***

USEFUL TOOLS

http://www.online-convert.com/ - Multimedia sound converter

http://www.tsm-resources.com/alists/pow2.html - Great for choosing sprite dimensions



ART

http://tsgk.captainn.net/ -Community with many sprite sheets

http://opengameart.org/ - All types of game art (Categorized)

http://www.deviantart.com/ - Popular and some artists allow the use of their art


MUSIC

http://www.pulseboy.com/ - Great for making 8bit music once you learn it

http://www.virtualpiano.net/ - Use a PlayBack Recorder to record yourself, or just make some basic tunes

http://www.warmplace.ru/soft/pixitracker/ - Music creation software

http://bfxr.net/ - Retro SFX creation software.

http://media.io/ - Audio converter
13  Game Development / Articles & tutorials / Java and Game Development Tutorials on: 2014-06-13 22:47:22
I wanted to share my new Youtube series about Java and Game Development and I thought this was the right board to put it in. The first episode skims over basics such as methods, variables, arguments, logical operators etc.

I dont think this was the appropriate board, sorry.  Shocked

My voice has been a little scratchy and I accidently had the gain on my *sensitive* blue yeti microphone on max so, headphone users, your ears may bleed a little. Just a fair warning.  Pointing

I would love some feedback and point in the right direction, and if I made a mistake give me a time and I will put an annotation.

<a href="http://www.youtube.com/v/LHVV0o4YrMg?version=3&amp;hl=en_US&amp;start=" target="_blank">http://www.youtube.com/v/LHVV0o4YrMg?version=3&amp;hl=en_US&amp;start=</a>
14  Discussions / Java Gaming Wiki / Experimental Toys on: 2014-04-28 11:24:22
Adopt OpenJDK:
  https://java.net/projects/adoptopenjdk/
  https://plus.google.com/communities/104849759654403050599
  https://github.com/adoptopenjdk/

Garbage collectors:
Shenandoah: An attempt at a pauseless collector
  http://rkennke.wordpress.com/
15  Discussions / Java Gaming Wiki / Escape Analysis on: 2014-04-25 08:22:13

Overview


Yet another stub -- is probably completely wrong

HotSpot details


Like all HotSpot features this can only describe a particular version (JDK8 snapshot on 20140425)

https://wikis.oracle.com/display/HotSpotInternals/EscapeAnalysis

For spot checking of impact escape analysis can be disable by: -XX:-DoEscapeAnalysis

Partial list of situations where HotSpot conservatively assumes a reference escapes:
  • The object requires a finalizer
  • The reference is passed to an invokedynamic call (e.g. lambda and method references)
  • The reference is passed to an instance method where the call isn't known to be monomorphic (the method can be overridden).
  • The reference is passed through a greater call chain depth than MaxBCEAEstimateLevel
  • The reference is passed to method whos bytecode size is greater than MaxBCEAEstimateSize

Detailed information about escape analysis can be queried with: -XX:+BCEATraceLevel = (1,3)

HotSpot source code:
hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp
hotspot/src/share/vm/opto/escape.cpp
16  Discussions / Java Gaming Wiki / Good Examples on: 2014-04-01 16:40:34
This wiki page is supposed to contain "good examples" of specific kinds of thread topics, so everyone can link to this to explain, how their topic should improve.

Good Examples For:


Asking for teammates


A new topic for asking for additional teammates for a project should always contain a lot of information about the project itself, the work that already has been done, what kind of help is wanted and how helpers / interested persons can get in contact. You should never ask for teammates without a project or without having done much work, it won't work, nobody is going to be impressed.
A good example for such a kind of topic/thread should look like this:
http://www.java-gaming.org/topics/2d-morpg-looking-for-talent/32656/view/topicseen.html

Making Tutorials/Articles in the article section


Tutorials in the article section are not allowed to only contain links to tutorials or similar, they are supposed to be directly included in the thread. If you wrote a blog post or similar, simply try to copy n' paste it into the article section and re-format it. You can find more information in the sticky post regarding the article section rules.
An excellent example for that would be this tutorial on creating a 3D camera.,
or this especially good part of the LWJGL Tutorial Series - Lighting.
17  Discussions / Java Gaming Wiki / Anonymous/Local/Inner class gotchas on: 2014-03-10 13:19:36
If it isn't defined as static then it implicitly keeps a reference to it's outer instance.  One issues is memory leaks due to entanglement.

JLS ยง8.6: Instance Initializers

This will create a special class for 'bar' and bar holds a reference to it's container.

1  
2  
3  
4  
5  
  @SuppressWarnings("serial")
  HashMap<String,String> bar = new HashMap<String, String>() {{
    put("foo", "xyzzy");
    put("bar", "yzzyx");
  }};


which can be trivially reworked to this (without an anonymous class):
1  
2  
3  
4  
5  
  HashMap<String,String> bar = new HashMap<>();
  {
    bar.put("foo", "xyzzy");
    bar.put("bar", "yzzyx");
  }

There's still a style gotcha here in that this is using an instance initializer and if 'bar' was changed to static the code would be executed each time a new instance of the container is created.  The initializer would also have to be changed to a static one.

18  Discussions / Java Gaming Wiki / HotSpot Options on: 2014-02-10 09:47:15
-Xms
Sets the inital heap space.
EXAMPLE: -Xms2g

-Xmx
Sets the max heap space.

-XX Options



To check all options supported by your VM:
java -server -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal


http://jvm-options.tech.xebia.fr/#
http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html

Pregenerated: 1.8.0 60 64-bit

Behavior Options


IgnoreUnrecognizedVMOptions (Boolean: false)
Ignore unrecognized VM options.

EagerInitialization (Boolean: false)
Eagerly initialize classes when possible.

GenerateRangeChecks (Boolean: true)
Generate range checks for array accesses

ForceTimeHighResolution (Boolean: false)
WIN32.

OnError (Comma seperated string list: empty)
Run user-defined commands on fatal error; see VMError.cpp for examples

OnOutOfMemoryError (Comma seperated string list: empty)
Run user-defined commands on first java.lang.OutOfMemoryError.
Example: -XX:OnOutOfMemoryError ="sh ~/somescript.sh"

UseCompressedStrings (Boolean: false)
Use byte arrays for strings which are ASCII.

Memory Options


InitialHeapSize (Integer: 0)
Initial heap size (in bytes); zero means OldSize + NewSize

MaxHeapSize (Integer: 96M)
Maximum heap size (in bytes).  -Xmx maps to this.

InitialRAMFraction (Integer: 64)
Fraction (1/n) of real memory used for initial heap size

MaxDirectMemorySize (Integer: -1)
Maximum total size of NIO direct-buffer allocations.

MaxHeapFreeRatio (Integer: 70)
Max percentage of heap free after GC to avoid shrinking.

InitialCodeCacheSize (Integer: platform specific)
Initial code cache size (in bytes)

ReservedCodeCacheSize

UseCodeCacheFlushing

Runtime Compiler Options


AggressiveOpts (Boolean: false)
Turn on optimizations that are expected to be default in upcomming version.

CompileThreshold (Integer: platform specific)
Number of interpreted method invocations before (re)compiling.  Lowering this number gives the compiler less time to gather accurate statistics which could result in slower code and will cause the compiler to run more often which increases CPU burden within a given time window.

DontCompileHugeMethods (Boolean: LOOKUP)
Don't compile methods larger HugeMethodLimit if true.

HugeMethodLimit (Integer: 8000)
Don't compile methods larger than the value if DontCompileHugeMethods is true.

MinInliningThreshold (Integer: 250)
Minimum invocation count a method needs to have to be inlined.

MaxInlineLevel (Integer: 9)
Maximum number of nested calls that are inlined.

MaxRecursiveInlineLevel (Integer: 1)
Maximum number of nested recursive calls that are inlined.

MaxTrivialSize (Integer: 6)
Maximum bytecode size of a trivial method to be inlined

MaxInlineSize (Integer: 35)
Maximum bytecode size of a method to be inlined.

FreqInlineSize (Integer : platform specific)
maximum bytecode size of a frequent method to be inlined

InlineFrequencyRatio (Integer: 20)
Ratio of call site execution to caller method invocation.

InlineSmallCode (Integer: )
Only inline already compiled methods if their code size is less than this.

DelayCompilationDuringStartup (Boolean: true)
Delay invoking the compiler until the main class is loaded.

DesiredMethodLimit (Integer: 8000)
Desired maximum method size (in bytecodes) after inlining.

InlineAccessors (Boolean: true)
Inline accessor methods (get/set)

PerBytecodeRecompilationCutoff (Integer: 200)
Per-BCI limit on repeated recompilation (-1=>'Inf')

PerMethodRecompilationCutoff (Integer: 400)
After recompiling N times, stay in the interpreter (-1=>'Inf').

Garbage Collector Options (General)


InitialSurvivorRatio (Integer: Cool
Initial ratio of eden/survivor space size

InitialTenuringThreshold (Integer: 7)
nitial value for tenuring threshold

DisableExplicitGC (Boolean: false)
Choose if calling
System.gc()
does a full GC.

Debugging aides


LogCompilation (Boolean: false)
Log compilation activity in detail to hotspot.log or LogFile. It's in XML, co check out JITWatch, a HotSpot JIT compiler log analisys and visualization tool.

PrintAssembly (Boolean: false)
Print native assembly code after compiles. Requires an external disassembler plugin.
https://wikis.oracle.com/display/HotSpotInternals/PrintAssembly also covers related options that enable printing of native methods, stubs, interpreter code, etc., and selective printing using CompileCommand.

Both 32- and 64-bit Windows binaries of a disassembler plugin can be found at the FCML Downloads page

For windows 64-bit VMs a copy of this plugin can be found inside: Graal/Truffle builds.  Copy the library on your path (or side-by-side jvm.dll) to use with other OpenJDK based builds.

PrintAssemblyOptions (String: empty)
Options string for PrintAssembly

PrintCompilation (Boolean: false)
https://gist.github.com/chrisvest/2932907

PrintInlining (Boolean: false)
Prints inlining optimizations

PrintIntrinsics (Boolean: false)
prints attempted and successful inlining of intrinsics
19  Discussions / Java Gaming Wiki / Using random number generators on: 2014-01-30 10:22:50
STUB

Red Blob has a page about distribution of various RPG style dice rolls with interactive: CLICK HERE
20  Discussions / Java Gaming Wiki / Stupid enum tricks on: 2014-01-28 08:18:03
Number of elements
1  
2  
3  
4  
5  
6  
public enum Foo
{
  A,B,C;

  public static final int length = Foo.values().length;
}


As a singleton
Probably the easiest way to safely create a singleton in java if no parent is needed, but an enum can implement any number of interfaces:
1  
2  
3  
4  
5  
public enum Foo
{
  INSTANCE;
  // instance methods here
}

Note that the enum instance is constructed on class load:
1  
2  
3  
4  
5  
6  
7  
8  
enum E {
    $;
    {
        System.out.println("Whoa! Hello World?!"); //this will in fact print when E.class is loaded (main() is run)
    }
   
    public static void main(String[] a) {}
}


As a static utility class
1  
2  
3  
4  
5  
public enum Foo
{
  ;
  // static methods here
}


Tree relations
All kinds of stupid tricks you can do with this.  Minimal example here just shows a boolean test of hierarchy membership.
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
public enum TreeEnum {
  THING,
    SUB_THING_1(THING),
    SUB_THING_2(THING),
      SUB_SUB_THING_2(SUB_THING_2),
  OTHER,
    SOME_OTHER(OTHER),
    AND_YET_ANOTHER(OTHER)
  ;
 
  private final TreeEnum parent;
  private final int      depth;
 
  private TreeEnum() { this(null);}
 
  private TreeEnum(TreeEnum parent)
  {
    this.parent = parent;
   
    if (parent != null) {
      this.depth  = parent.depth+1;
    } else {
      this.depth  = 0;
    }
  }
 
  public boolean isA(TreeEnum other)
  {
    TreeEnum t = this;
   
    do {
      if (t == other) return true;
      t = t.parent;
    } while(t != null);
   
    return false;
  }
}
21  Discussions / Java Gaming Wiki / List of Learning Resources on: 2014-01-20 14:16:07

This page is dedicated to good quality learning resources.
Feel free to modify it and throw in any books/articles/tutorials/websites of worth.

Game Development Techniques


Articles & Tutorials



OpenGL - General


Articles & Tutorials


Modern OpenGL


Books


Websites



OpenGL - GLSL


Websites



Java2D


Articles & Tutorials



Math



The Java Language


Articles & Tutorials


Books


22  Discussions / Java Gaming Wiki / Stupid generics tricks on: 2014-01-14 15:50:40
Phantom Types

TODO:  Add cheesey type refinement (sketched in the phantom types thread as well)

Checked exceptions as unchecked

Java the language requires checked exceptions, where the JVM does not.  This uses type erasure to allow throwing a checked exception as unchecked.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
 public final class Util {
   
   /** For erasing the type of the checked exception */
   @SuppressWarnings("unchecked")
   private static <E extends Throwable> void throw_(Throwable e) throws E
   {
     throw (E)e;
   }
   
   /** Throws a checked exception 't' as unchecked. */
   public static void silentThrow(Throwable t)
   {
     Util.<RuntimeException>throw_(t);
   }
 }


Constructor hugger
1  
2  
3  
4  
5  
6  
7  
8  
public class Animal<T>
{
   public <P> Animal(P mommy, P daddy) {
      ...
   }
}

dog = new <Wolf>Animal<Dog>(wooo, woooo);
23  Discussions / Java Gaming Wiki / Quasi random number (low-discrepancy sequences) on: 2014-01-07 14:53:30
Wikipedia

Points in a unit square:  Pseudorandom on the left/top, Quasirandom on the right/bottom (Halton sequence)



See

References
24  Discussions / Java Gaming Wiki / Resources for learning software design. on: 2013-10-17 14:25:24
Hi. I'm looking for something that will let me dive deep inside the software architecture. The problem is I cant find a correct way to structure my software. There are multiple layers and separate modules. The stuff gets heavier and more verbose. I would like to read any resources that describe common software design problems and solutions to this.
I'm not looking for design patterns, which can solve rather small problems.

Thanks in advice.
25  Discussions / General Discussions / Netbeans 7.4 still bugs with Libgdx ( video ) on: 2013-07-24 17:32:13
http://www.youtube.com/watch?v=rMtMBR1Cfn8&feature=youtu.be

The video speaks for itself.

Im sending this to netbeans forum. But its good to show to other people.
AND YES< i tried with 7.3 and 7.2 as well.
26  Discussions / Java Gaming Wiki / Smoothing Algorithm Question on: 2013-05-28 00:57:32
COULD SOMEONE MOVE THIS TO THE GENERAL DISCUSSION SECTION. @_@

Hello! This is a question that's for all ya'll who have more experience in graphics and algorithms than myself. I'm working on a project (For work, and I did get permission to ask around) that requires the smoothing of a large set of data.

The basics of is that there is a data set that is a 3D matrix filled with 'slowness' values which is basically 'When moving through this cell how many units do you move per time step?' Initially, these values are filled in with a interpolated gradient from some min at the top to some max at the bottom. Then, this data set has a function applied to it repeatedly that takes the data set and another set of inputs, and updates certain cells in the matrix to new values. The updated data set is then fed back into the algorithm again and again until it converges or some maximum number of iterations is achieved.

This is where the major problems begin. For the most part, the function expects that there is some degree of smoothness to the data set, IE- there is some finite, but unknown, allowed difference between values in adjacent cells for which the algorithm will produce meaningful data. This is due to the fact that there is no guarantee that each application of the function will touch the same cells, only that it should touch cells that are close to those touched in the prior step. Due to the fact that the starting estimation (The gradient) is so bad the updates result in large discrepancies between updated and unupdated cells. To help combat this a filtering operation, namely a smoothing, is applied to the the entire data set before it is fed back into the algorithm. Currently, the smoothing operation is a Sliding Windowed Mean with the window size that changes as the iterations continue and as the estimation becomes more exact. Typically it starts out at a window size that is the size of the data set with a slide of 1 (In each direction).

For the size of data set that we're typically work on, this takes a large portion of time (Think a data set that's about 100x50x50, with a sliding windowed mean of 100x50x50 and a slide of in the (x,y,z) direction). This has two major problems: First, it takes a long time to perform this operations, and Second, at least in early iterations there is a 'large' contribution to the value of cells from those that are relatively far away.


So, while it would be nice to figure out a better initial data set, IE- One that will result in a smaller degree in discrepancies between early applications of the function, I've been asked to work on the problem of making  the filtering itself more efficient. So many, I'm asking about various filters and whether anyone has any resources for the use of them in 3D (As in smooth across depth instead of just height and width) resources, anything about how to figure out when the application of a filter will result in little-to-no change (IE- figuring out when I can exclude a cell from having the filter applied to it) and things like that?
27  Discussions / Java Gaming Wiki / Complex number cookbook on: 2013-03-14 16:44:34
By representing an orientation (or rotation) by a complex number instead of an explicit angle we can drop a fair number of expensive operations.  So instead of storing angle 'a', we store complex number (cos(a), sin(a)).

Another potential advantage is the algebra framework (just manipulating algebra) and reasoning.  Algebra's like complex number, vectors, quaternions, etc allow thinking in terms of relative information which can greatly simplify the process.

We will assume that standard mathematical convention of the X axis pointing the to right and the Y axis pointing up.  Additionally we will assume that the reference orientation of objects is pointing straight right. Combining these together when thinking about some specific entity, we can think in terms of its center being at the origin and its facing straight down the X axis.

NOTE: Although angles are talked about, this is for understanding and thinking purposes and not computation.

Basic examples in code:

Common definitions
Capital letter are complex number and small are scalars.
  X=(a,b)
  Y=(c,d)
  P=(x,y)
  R=(cos(a), sin(a))
  S=(cos(b), sin(b))
  

Complex number basics


Complex numbers are represented by two numbers, which we will denote as a pair (a,b).  The first number we will call 'x' and the second 'y'.

Conjugate
X* = (a,b)* = (a,-b)
R* = (cos(a),sin(a))* = (cos(a),-sin(a)) = (cos(-a),sin(-a))

So the conjugate reflects (wikipedia) about the X axis, which is the same as negating the angular information. (SEE: Trig identities: Symmetry)

Addition/Subtraction
X+Y = (a,b)+(c,d) = (a+c,b+d)
X-Y = (a,b)-(c,d) = (a-c,b-d)


Operation is component-wise.  Can represent translation.

Product
XY = (a,b)(c,d)
   = (ac-bd, ad+bc)
RP = (cos(a), sin(a))(x,y)
   = (x cos(a) - y sin(a), y cos(a) + x sin(a))
RS = (cos(a), sin(a))(cos(b), sin(b))
   = (cos(a)cos(b) - sin(a)sin(b), cos(b)sin(a) + cos(a)sin(b))
   = (cos(a+b), sin(a+b))


So the product sums the angular information of the two inputs. (SEE: Trig identities: angle sum)

SEE: C2D.mul(C2D)

Product combined with conjugate
X*Y = (a,b)*(c,d) = (a,-b)(c,d) = (ac+bd, ad-bc)
R*S = (cos(a),sin(a))*(cos(b),sin(b))
               = (cos(-a),sin(-a))(cos(b),sin(b))
               = (cos(a)cos(b)+sin(a)sin(b), -cos(b)sin(a)+cos(a)sin(b))
               = (cos(b-a),sin(b-a))


Since we can add angles with the product and can negate an angle with the conjugate, the two together allow us to subtract angles.  (AKA get relative angular information)

SEE: C2D.mulc(C2D) & C2D.cmul(C2D)

Magnitude (L2 norm)
|X| = |XX*| = |(a,b)(a,-b)| = sqrt(a2+b2)

Notice that we're not calling this length.  Complex numbers, vectors, etc do not have lengths (nor positions).  What they represent in a give instance might have a length equal to its magnitude.

Unit complex and trig form
Unit complex numbers have a magnitude of one and can be written in 'trig form':
  (cos(t),sin(t)).

Since scale factors can be pulled out (see scalar product) all complex numbers can also be written in 'trig form':
  m(cos(t),sin(t)).

Scalar product
sX = s(a,b) = (s,0)(a,b) = (sa, sb)

This can be reversed, so all scale factors can be pulled out.

Inverse
1/X = X*/(XX*) = (a,-b)/(a2+b2)
1/R = (cos(-a),sin(-a))/(cos(a)2+sin(a)2)
    = (cos(-a),sin(-a))
    = R*


The multiplicative inverse of a unit complex is the same as its conjugate.

SEE: C2D.inv()

Counterclockwise rotation of point about the origin
Falls directly out of the product.  Given rotation (R) and point (P), the point after rotation (P'):
P' = RP
   = (cos(a), sin(a))(x,y)
   = (x cos(a) - y sin(a), y cos(a) + x sin(a))


Example:
  P  = (3,3)
  R  = (cos(pi/4), sin(pi/4)) = (.707107, .707107)
  P' = (3,3)(.707107, .707107)
     = (0, 4.24264)


How do I find rotation of A into B
Solve the above.  Assuming A & B are unit vectors:
  RA = B
  R  = B(1/A)
  R  = BA*


Example:
  A  = (0.809017, 0.587785)
  B  = (0.5, -0.866025)
  R  = BA*
     = (0.5, -0.866025)(0.809017, 0.587785)*
     = (0.5, -0.866025)(0.809017, -0.587785)
     = (-0.104528, -0.994522)


Counterclockwise rotation of point about arbitrary point
We can rotate about the origin, to rotate about an arbitrary point (C) translate the system to the origin, perform the rotation and then undo the translation.
P' = R(P-C)+C
   = RP-RC+C
   = RP+C-RC
   = RP+C(1-R)
   = RP+T


where T = C(1-R).  Look at the last line. It is telling you that the rotation R about point C is equivalent to a rotation about the origin R followed by a translation T.  And C is recoverable from T & R: C = T/(1-R) (assuming R isn't 1...or no rotation).

Composition of rotations
Falls directly out of the product.  Given rotation (R) followed by rotation (S):
RS = (cos(a+b), sin(a+b))

Orthogonal direction
To find a direction orthogonal in a right-handed sense is the same as rotating by pi/2 radians (90 degrees), which is to multiply by (cos[pi/2], sin[pi/2) = (0,1).

ortho(X) = ortho((a,b)) = (a,b)(0,1) = (-b,a)

Relation to dot and cross products
Falls directly from the product where one is conjugated:
X*Y = (a,b)*(c,d) = (a,-b)(c,d) = (ac+bd, ad-bc)

dot(X,Y)   = ac+bd
cross(X,Y) = ad-bc

The dot product is the parallel projection and the cross is the orthogonal projection.  Cross product is related to dot product by: cross(X,Y) = dot(ortho(X),Y).

Basic geometry



On which side of a line is a point?
A line can be represented by a direction (L) and a point on the line (A).  The simplest case is a line which coincides with the X axis, L=(1,0) & P=(0,0), in which case we can simply examine the 'y' value of a test point (P).  If 'y' is positive, then it is above, zero on the line and if negative then it is below.  Moreover the value is the orthogonal distance of the point from the line.

Next let's consider an arbitrary line through the origin with unit direction L.  We can simply rotate the system such that the line coincides with the X axis as above and we're done.  Our modified test point becomes: P'=PL*.  Now the 'y' of P' is exactly the same as above.  To fully generalize we simply need to move the line to the origin which give us: P'=(P-A)L*.

If we were to plug in symbolic values: P=(px,py), L=(lx,ly) & A=(ax,ay) and expand we would see that we have unused intermediate values.  This is because we are ultimately only examining a single component..we're only examining the orthogonal projection of the point into the line (SEE: cross product above).

Additionally the direction of the line does not need to be normalized if we're only interested in above, on or below line question.  The reason is because we only care about the sign of the result to answer our question.

So the 'which side' question reduces to: cross(L,P-A), which expands to the following pseudo-code:

  return lx*(py-ay)-ly*(px-ax)

Aside: the previous can be expanded to cross(L,P)-cross(L,A) = cross(L,P)-m.  The scalar 'm' can be stored instead of the point 'A' to represent the line.  This value 'm' is commonly called the 'moment about the origin'.

Basic examples


At the top we say we can represent an entity by its position and orientation and think about its center as being at the origin and facing straight down the X axis (the reason for this is because that's the entity's local coordinate frame).

Let's call it's position E and orientation F and we have some test point P.  We can translate the system to the origin (P-E) and then we can undo the rotation of the system by multiplying by F*, which gives us: (P-E)F*.  So P in the reference frame of our entity is:

P' = (P-E)F*

Example:
  P  = (100,100)
  E  = (200,200)
  F  = (.92388, .382683)  <- Pi/8 or 22.5 degrees
  P' = ((200,200)-(100,100))(.92388, -.382683)
     = (130.656, 54.1196)


If you've ever worked with vectors, this should seem similar: find the delta distance and perform the dot and/or cross product. The above equation is finding the delta distance and then effectively computing both. (Obviously you only compute one if only need one).  So the dot product is simply the 'x' coordinate in the local coordinate frame (parallel projection) and the cross is the 'y' coordinate (orthogonal projection).

What's my unit direction vector?
It's pretending the unit complex number of the orientation is a unit vector. It has the same numeric values for 'x' & 'y'.

Is it behind me?
As noted above the dot product is 'x' in the local coordinate frame, so the sign of the dot product.  If negative it's behind the center point with respect to facing and positive if forward.

Turn clockwise or counterclockwise?
As noted above the cross product is 'y' in the local coordinate frame, so the sign of the cross product.  If positive the shortest turn is counter clockwise, if negative it's clockwise and if zero it's straight ahead.  

Turn toward point with constant angular velocity
Again, the sign of cross product tells the minimum direction. Take a constant angular velocity, store as a unit complex number 'A'.  If the sign of the cross product is negative, we need to conjugate A (negate it's 'y' component). Multiply the current facing 'F' by the potentially modified 'A'. Take our new 'F' and cross again.  If the sign has changed, we've overshot the target.

Is point within field of view
Given an entity in its local coordinate frame:  image some field of view (<= Pi or 180 degrees), which become a pair of line segments symmetric about the X-axis (or triangle or cone).  We can immediately note a couple of things.  The first is that if our x component of a test point P=(px,py) is negative that it cannot be inside.  The second is that given the symmetry about the X-axis, P and P* will always return the same results. Given the second we can form a new test point P'=(px,|py|).  Now the problem is identical to on which side a point falls with respect to a line through the origin and we the first observation isn't required to compute the result. Since we're asking 'below' the line, we negate the result to convert into the convention of positive is inside, yielding the following pseudo-code:

  return ly*px-lx*Math.abs(py);

As with the point to line test, our direction L does not need to be normalized and L is half of the field-of-view.

Which unit direction forms the minimum angle with the local X axis.
Although related to point/line and view-of-view, this case reduces to simply the direction with the greatest x component.

Bounce reflection
Given a vector (v) of something that hits a surface with normal (n) the resulting vector (v') has the same orthogonal part and the parallel part is negated.  The parallel part is dot(n,v), so v-n(dot(n,v)) removes the parallel part and v-2n(dot(n,v)) results in the parallel part being negated.

For point reflections: negate the bounce reflection equation.
SEE: C2D.uref (this is point refection implementation)
28  Discussions / Java Gaming Wiki / Forms of Randomness on: 2012-12-08 22:46:42

Forms of Randomness


I. Random Number Generators


i. Introduction


Random number generators create a sequence of random bits. The client to a random number generator class can request the raw bits directly or interpreted data derived from the bit sequence (floats, doubles, values between two other values, values with a certain distribution, etc.) Random number generators produce bits in a sequence and have a state. It may not be possible to achieve random access to a number in the sequence produced by an RNG. Random numbers are also not be suited for applications with data in multiple dimensions stretching to infinity or finite grids that are too large to store in RAM. If you need random data as a function of one or more variables, you can use a hash function or an RNG seeded from the value of a hash function.

1. RNG Seed


A value called a seed can be used to derive the initial state of a Pseudo Random Number Generator. If you provide the same seed to a PRNG, it will produce the same sequence of numbers every time (but only for the same algorithm). This is useful for creating reproducible procedurally created content, synchronizing random number sequences between multiple computers, or any other scenario require consistency or reproducibility.

2. RNG State


The state of a PRNG is normally hidden to the user of the object. You can create a PRNG that lets you copy it's state into a different object, so you can create identical sequences starting from the middle of a sequence (instead of just the beginning using a seed) and so you can save and restore the state of the PRNG in the middle of a sequence. All pseudo random number generators have a state. PRNGs are deterministic and do not return truly random sequences.

ii. Cryptographic Random Number Generators


Cryptographic random number generators have special properties useful for security related applications. They exploit properties of number systems that can be used for private communication, authentication, and zero knowledge proofs. They work with large numbers and may be too slow for applications that do not require them, such as simulations or games. If you think you need one in your game but don't know how it works or what it's used for, then you probably don't need one.

iii. Non-Deterministic Random Numbers


You don't need true random number generators for the same reason you don't need cryptographically secure random number generators. Cryptographic PRNGs may benefit from keys derived from real world noise in order to prevent some attacks, but a game won't have to worry about such attacks. To get this type of randomness, computers use input from the physical world that can be considered random. The "state" of this RNG is the state of the real world. It does not have the useful properties of PRNGs other than the appearance of randomness. Computers might utilize this source of randomness or user inputted key to seed a cryptographic PRNG instead of a timer to prevent certain side channel attacks. If you're not using cryptography, don't look for this type of randomness.

II. Hash Function


i. Introduction


Hash functions take a sequence of bits and transform them to a new sequence of bits, usually of some fixed length. The
hashCode()
function for Java Objects produces a 32 bit output. Hash functions are sometimes (that is, very rarely) referred to as compression functions because they take a sequence of bytes and shorten it to a smaller sequence. One way to do this is to simply truncate the sequence (for example "Java Gaming" could be hashed to "Java"), but it's generally better to have some type of random output. This way "Java Gaming" and "Java Programming Language" don't create a hash collision. One good reason to never call a hash function a compression function is that it can easily be confused with a compression algorithm. A compression algorithm also shortens a sequence of bits, but in a way that is meant to be reversible.

In a way, hash functions work the opposite of a random number generator. A random number generator may take a 32 bit seed and be used to create a much larger sequence of random numbers. A hash function takes a long sequence of bytes and can convert it to a "random" 32 bit hash. A PRNG always produces the same output sequence given the same seed. And a hash function always produces the same hash given the same input.

This article uses H(X) = Y to represent a generic hash function. X is the input and Y is the output, or "hash," or "hash value."

1. Cascade Effect and Relation to PRNGs


The cascade effect says that if you change one bit of the input to a hash function, then about half the bits of the output should change, too, on average. This means that H("StringA"), H("StringB"), and H("StringC") all produce very different output. A random number generator where each output bit had a uniform probably of being zero or one will produce a similar outcome. One way a cryptographic PRGN can be created is to take the hash of a counter using a cryptographic hash function, although this would be too slow to use in a video game. Some general purpose PRNGs operate in the form
state = f(state);
where f(x) is a one-to-one hash function. Special care must be taken to ensure that f(x) has a long enough period for all valid states and that its sequence still appears random.

iii. Randomness, collisions, and Hash Tables


Hash tables take advantage of hash functions to make make fast searches for key values. Java's hashCode() function compresses the data represented by an Object (such as a String, which can be much longer than 32 bits) so that it can be manipulated as an int. The first location the hash table looks for an object is at array index
key.hashCode() % arraySize
If different values map to the same array index (or hash value if not further compressed using %, then those two values are said to cause a collision using that hash function, which makes look up slower. Collisions in hash functions used in procedural content generation may create visual artifacts. Good hash functions are unpredictable, have the cascade effect, and are statistically as likely to produce one value as any other, so that the chance of collision is minimized.

iv. Procedural Content, Salting, and Spatial Hashing


Hash functions are useful for generating random values that can be found without sequential access or a look up table. For example, if I had a randomly generated RPG world but if I wanted the same people to appear, I could combine a hash function and RNG to generate similar characters with the same name in alternate realities. In this example Bob may be a character with brown hair, a green shirt, blue pants, black shoes, and no glasses. In other save file, he might look the same but have brown hair. Or have glasses in a third save file.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
public static Character createCharacter(String characterName, String worldId)
{
  // Seed RNG by NPC name
  Rng rng = new Rng(characterName.hashCode());
  Character c = new Character(characterName);

  // Set basic characteristics of NPC
  c.setHairColor(rng.nextInt(0, MaxHairColorId));
  c.setShirtColor(rng.nextInt(0, MaxShirtColorId));
  c.setPantsColor(rng.nextInt(0, MaxPantsColorId));
  c.setShoeColor(rng.nextInt(0, MaxShoeColorId));
  c.setGlasses(rng.nextBoolean);
  c.setGlassesColor(rng.nextInt(0, MaxGlassesColorId));

  // Reseed RNG
  rng.reset((characterName + ":" + worldId).hashCode());
  // Modifiy character slightly in this alternate reality
  switch(rng.nextInt(0, 5)
  {
    case 0:
      c.setHairColor(rng.nextInt(0, MaxHairColorId));
      break;
    case 1:
      c.setShirtColor(rng.nextInt(0, MaxShirtColorId));
      break;
    case 2:
      c.setPantsColor(rng.nextInt(0, MaxPantsColorId));
      break;
    case 3:
      c.setShoeColor(rng.nextInt(0, MaxShoeColorId));
      break;
    case 4:
      c.setGlasses(!c.hasGlasses());
      break;
    case 5:
      c.setGlassesColor(rng.nextInt(0, MaxGlassesColorId));
      break;
  }
  return c;
}


Another way to use hash functions is to hash x-y coordinates. Separate your game world into grids and randomly generate content in a grid one grid at a time. You can generate them all ahead of time, or you can generate them on the fly by using a hash function H(x, y) to seed the RNG in that grid location. When the player leaves that area, you can forget about that grid cell and recreate the exact same area the next time the player goes to that area.

One potential problem with this approach is that if a person replays the game, all maps will be the same. This may be desirable. (And it may be helpful. Procedurally created worlds may let you distribute a small binary file and no extra resources (Java4k?) and still have consistent user experience.) One way to change the output of a hash function is to add a "salt" value. You could store the salt in the player's save file or derive one from their username. Modifying the salt is like modifying the RNG seed. Utilizing String's hashcode function again, you could have a salt-less version of a hash function that returns
(x + ", " + y).hashCode()
and a salted version that returns
(playerName + "..." + x + ", " + y).hashCode()
.

Spatial hashing is one you take a point in multidimensional space, determine what grid cell (square, hexagonal, cubic, or whatever) it is in, and convert the position of that cell to a value.

III. Other sequences


Other sequences may be used that look random to humans and provide certain properties, but aren't actually. Halton and Sobol sequences are examples of low discrepancy sequences and are also called quasi-random sequences.

IV. Noise


Noise combines one or more of the above forms of randomness and algorithms to produce a desired affect. Perlin noise, for example, requires a grid of random values, which can either be derived ahead of time using an RNG (for small grids) or on the fly at any point using a hash function (for large or infinite grids,) and interpolates between those values for other locations.

White noise in the real world represents a signal with many many frequencies present over an entire spectrum of frequencies. The intensity of the noise is completely random. You could convert the output of an RNG to a PCM sound data to produce (1D) white noise sound or set the brightness of each pixel in a black and white image to the output of an RNG to produce a (2D) white noise image. White noise generally isn't very useful.

Noise may be generated with specific aesthetic, frequency spectrum, or structural properties instead. See other articles for descriptions of types of noise, noise algorithms, and applications of noise.
29  Discussions / Java Gaming Wiki / GLSL tricks on: 2012-12-07 04:44:28
Todays GPUs are very powerful but it's important to understand the limitations of the hardware of GPUs. For example, branching in GLSL is very expensive due to the way that the stream processors on GPUs work. In many cases branching causes both branches to be executed and the correct result is then picked afterwards.

A general tip when coding shaders is to use the built-in functions as much as possible. They are always faster than manually doing the calculations.

  • Never manually normalize a vector by calculating the length of it using a square root and dividing it by it. Always use normalize().
  • Don't use branching to clamp values. Use min(), max() and clamp() for that.
  • A very common function is linear blending and there's a function called mix() for it.


Generating random numbers

Generating random numbers on a GPU in a traditional way is impossible since we can't use a global seed (well, we can in OGL4+ using atomic counters, but I wouldn't count on good performance). Random numbers can be useful to introduce noise to counter banding in algorithms like HBAO (randomly rotate the sampling ray) or volumetric lighting (random offsets) to trade banding for noise which is much harder to spot and looks better when blurred. This one-line function is a pretty simple noise function seeded with a 2D position (you can use the screen position or texture coordinates as the seed).

Generating random numbers on the GPU presents a couple of challenges.  The first is that from a practical standpoint you start with some non-random data (say a texture coordinate) which needs to be hashed to give a "random" starting value.  The second is that most GPUs currently in use are very slow at integer computations which are invaluable in hashing and generating PRNGs.  The results needing to perform very hacky hashing and random number generation entirely in floating point until your low end target has full-speed integer support.

1  
2  
3  
float rand(vec2 co){
    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}


Permutation polynomials. In use examples: (Local value noise, gradient and simplex noise)
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
// repeated for other type
vec2 mod289(vec2 x)     { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec2 permute(vec2 x)    { return mod289(((x*34.0)+1.0)*x); }
vec2 rng(vec2 x)        { return fract(x*1.0/41.0); }

// minimal example: take a 2D coordinate and convert into a hash value, then
// generate multiple random numbers by rehashing the hash.
float bar(vec2 x)
{
  float h, r;
  vec2 m = mod289(x);             // values must be bound to (-289,289) for precision

  h = permute(permute(m.x)+m.y);  // hash the coordinates together
  r = rng(h);                     // first random number
  ...
  h = permute(h);                 // hash the hash
  r = rng(h);                     // second random number
}




Dot products

The dot() function is used to calculate the dot-product of two vectors, which is the same as multiplying the vectors component-wise and then adding them together. For a 3D vector, that means that
dot(v1, v2) = v1.x*v2.x + v1.y*v2.y + v1.z*v2.z
. This is a very useful function for doing many things. For example, calculating the distance between two points using Pythagoras' theorem:
1  
2  
3  
4  
5  
6  
7  
8  
vec3 p1;
vec3 p2;

//...

vec3 delta = p1-p2;
float distSqrd = dot(delta, delta); //Distance^2, can be useful for lighting which saves you the square root
float dist = sqrt(distSqrd);


Converting a color to grayscale:
1  
2  
3  
4  
5  
vec3 color;

//...

float grayscale = dot(color, vec3(0.21, 0.71, 0.07));





Shadow mapping

Shadow mapping is basically a software depth test against a shadow map. The shadow map coordinates are interpolated as a vec4, so we need to do a w-divide per pixel, get the shadow map depth at that coordinate and compare it to the pixel's depth. A simple implementation does this:

1  
2  
3  
4  
5  
6  
7  
8  
9  
uniform sampler2D shadowMap;

float shadow(){
    vec3 wDivShadowCoord = shadowCoord.xyz / shadowCoord.w; //z-divide

    float distanceFromLight = texture(shadowMap, wDivShadowCoord.xy).z;
   
    return distanceFromLight < wDivShadowCoord.z ? 0.0 : 1.0;
}


This is not optimal. By using the function called step() we can eliminate the branch by just writing
return step(wDivShadowCoord.z, distanceFromLight);
instead.

Even better, the GPU can do the shadow test for us in hardware with some basic shadow filtering if we use a sampler2DShadow instead of a normal sampler2D. That way we just feed in the xyz w-divided shadow coordinates into it. On the shadow map, set up the following parameter to enable hardware shadow testing:
GL11.glTexParameteri(GL_TEXTURE_2D, GL14.GL_TEXTURE_COMPARE_MODE, GL14.GL_COMPARE_R_TO_TEXTURE);
and change the sampler type to sampler2DShadow. It's also possible to enable GL_LINEAR as the texture filter and get 4-tap PCF bilinear filtering.

There is one final optimization. Not only can the GPU do the shadow test in hardware with filtering, it can also do the w-divide in hardware using
textureProj()
! It can't get better than that!

1  
2  
3  
float shadow(){
    return textureProj(sampler, shadowCoord);
}


We get better performance, better image quality thanks to the PCF filtering AND a simpler shader. However, the first shader is extremely fast anyway, so why optimize it this much? Shadow filtering. To get smoother shadow edges you do lots of shadow tests on nearby pixels in the shadow map, usually 8 to 16 of them. In that case we would've gotten 16 branches, not just one, so eliminating them means a lot here. Using hardware filtering also gives you 4 samples per texture lookup instead of just one, allowing you to sample a bigger area.




GLSL Gotchas

  • Array declaration is broken on Mac Snow Leopard[1]
30  Discussions / Java Gaming Wiki / Uniform feature points on: 2012-12-05 15:27:32
Main/Procedural content

STUB (YEAH, I'M MAKING LOTS OF THESE) TO REMIND MYSELF TO DO A WRITE-UP.

Uniform Feature Points


Let us imagine that we have a 100x100 meter field and in this field we what there to be, on average, two flowers per meter squared.  So we could create an array with 100x100x2 = 20,000 elements to explicitly store the positions of each flower.  Using a seeded uniform random number generator we could then fill the array with repeatable coordinates for each.  If we were to examine the placement of flowers we would notice that there would be regions with none and areas where they are clummped up.

1  
2  
3  
4  
5  
6  
7  
rng.setSeed(someValue);

for(int i=0; i<100*100*2; i++) {
  float x = 100*rng.nextFloat();
  float y = 100*rng.nextFloat();
  doMyFlower(x,y);
}

Now if were to examine each square meter (or some other regular chunk) and count the number of flowers it contains, then the "distribution" of the counts approaches the Poisson distribution (Wikipedia, MathWorld).

So instead of precomputing a explicit list of "features", the space in question can be broken down into parts. For each part one computes a poisson random number to determine the number of features inside it.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
// From Knuth, reasonable on modern machines for smallish
// means.  There are many ways this can be computed.
// eMean = exp(-mean)
public static final int poisson(float eMean)
{
  int   r = 1;
  float t = rng.nextFloat();
 
  while (t > eMean) {
    r++;
    t *= rng.nextFloat();
  }
  return r-1;
}

// Sketch below this point
private static final float FLOWER_POWER = (float)Math.exp(-2);

private void doSomeCellFlowerThing(...)
{
  rng.setSeed(hashOfThisCell);

  int num = poisson(FLOWER_POWER);

  for(int i=0; i<num; i++) {
    // coordinates local to the square meter in this example
    float x = rng.nextFloat();
    float y = rng.nextFloat();
    ...
  }
}


Assuming that the chosen hashing function does a reasonable job, then the "look" of the localized vs. global versions should be similar.  Up until now I've avoided too much techo-speak but some definitions are required.  All of the above rng.nextFloat() calls are assume to return a uniformly distributed random number on [0,1) which is the standard base contract for a uniform floating point result (actually the inclusion/exclusion of the end-points may vary, but I'm assuming the presented).  In probability a uniform distribution (Wikipedia, MathWorld) means that all results on the range are equally probable...like in a single fair die roll.  So in the examples above the 'x' coordinate of each flower is completely independent of 'y', which should be expected.  Moreover the coordinates of each flower is independent of any other.  This leads to the previously mentioned empty and clumpped up areas.  This result, like many from probability, is likely to seem counter-intuitive.  Most likely "uniform" will tend to invoke notions of uniformly (or evenly) covered areas.  This is a radially different notion of uniform as implies that all of the values are related to each other rather than independent.  Note that these two different notions of uniform approach one another as the number of features (or event) increase.
Pages: [1] 2
 
Lunch (78 views)
2016-12-06 16:01:40

ral0r2 (303 views)
2016-11-23 16:08:26

ClaasJG (437 views)
2016-11-10 17:36:32

CoffeeChemist (525 views)
2016-11-05 00:46:53

jay4842 (575 views)
2016-11-01 19:04:52

theagentd (599 views)
2016-10-24 17:51:53

theagentd (581 views)
2016-10-24 17:50:08

theagentd (525 views)
2016-10-24 17:43:15

CommanderKeith (521 views)
2016-10-22 15:22:05

Roquen (472 views)
2016-10-22 01:57:43
List of Learning Resources
by elect
2016-09-09 09:47:55

List of Learning Resources
by elect
2016-09-08 09:47:20

List of Learning Resources
by elect
2016-09-08 09:46:51

List of Learning Resources
by elect
2016-09-08 09:46:27

List of Learning Resources
by elect
2016-09-08 09:45:41

List of Learning Resources
by elect
2016-09-08 08:39:20

List of Learning Resources
by elect
2016-09-08 08:38:19

Rendering resources
by Roquen
2016-08-08 05:55:21
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!