Merging Quaternion rotations and Translations (and bullet updating)

Perhaps I have need to read more, but having looked at the jme math for dummies, and the wikipedia articles for quaternions and spatial rotation, conversions between quaternions and euler angles and a bunch of stuff from euclideanspace.com. I still cannot come to a conclusion how to fix this. Granted, there are some things I have to be missing, I’m tired, and looking at that math is making my brain fry.

I pretty much want this: A spacecraft with the Z axis being it’s forward/back, x left/right, y up down, will always follow its nose when I hit forward not matter what rotations I send to it. I’ve gotten it to work somewhat. If the ship maintains it’s wings at a xy axis relative to the direction the nose is pointing it works, but once the ship banks its wings, the direction gets wonky.

The JME math for dummies seemed to present the answer, make a vector (in this case a solely z axis vector) and rotate it with a quaternion made from the angles of rotations that accumulated from previous input. But I’m getting wonky changes. Here is the relevant code.

[java]

public void transform(float gox, float goy, float goz,

float pitch, float yaw, float roll) {

Vector3f add;

Vector3f up = new Vector3f(0,goy,0);

Vector3f forward = new Vector3f(0,0,goz);

Vector3f sideways = new Vector3f(gox,0,0);

curr_pitch += pitch; //x

curr_yaw += yaw; //y

curr_roll += roll; //z

curr_pitch = curr_pitch % FastMath.TWO_PI;

curr_yaw = curr_yaw % FastMath.TWO_PI;

curr_roll = curr_roll % FastMath.TWO_PI;

Quaternion change = new Quaternion();

change = change.fromAngles(curr_pitch, curr_yaw, 0); //or alternatively curr_roll.

// cx += gox;

// cy += goy;

// cz += goz;

add = change.mult(forward);

mesh.rotate(pitch, yaw, roll);

mesh.move(add);

}

[/java]

Again, there must be something I’m missing, but reading the materials above, I am not seeing how I can fix it so I hope someone can give me a hand here.

Thanks

PegasusJF

ps…

If you don’t mind, I would like to bring another question not related to this.

When I first started on this app, I tried making, just for testing, a Projectile class. Basically it’s a box that gets attached when “fired” goes for a little while checking it’s life (current translation amount vs max) and detaches from the rootNode when that limit is reached. It was just a little and created an array of five to be fired whenever I hit space and there is an open spot in the array. I put a for loop in simpleUpdate() to run through the projectile array to allow for the bullets to animate and end when they reached their limit.

It bogged down the machine so bad I was getting 1 fps, and right now I’m just using one to test inputs from packets over a socket and locally. Since my game idea will require a great many bullets that will have to be checked almost continuously (client side of course) to determine collisions and lifecycle, there has to be something I’m doing wrong. Could you point me in the direction of resources/tutorials that will allow me to do these calculations (obviously thorugh simpleUpdate or something similar) without causing bogging down?

tralala said:

2) bullets in real life die based on time, not on distance.
3) you have crap code, thats why it has 1 fps. Do you use sleep() / wait() ? thx for pausing jme for no reason and making it have 1 fps. Jme gives you float tpf, add this to a variable totalTime every frame and if totalTime > 3 sec then remove bullet.
Packets = Sleep() / wait(); do it another thread, and they may arrive after 100-300 frames.


Thanks for the code, I'll look at it. I don't believe I've seen any tutorials that cover levitate (or some of the methods you're using), could you provide some sources about them? Finally, is this code for a object that has a full 6 DOF? Or is it for more terrestial flying ship?

But about the projectile code.
Crap code, well, quite likely since it was one of my first attempts using JME3 after going thorugh to the input tutorial. I used distance simply as a way to give the bullet a start and stop point. It was a basic implementation to test, that test obviously failed and I have yet to find an efficient means of keeping track of multiple projectiles with their movement vectors and alive/dead states, not to mention collision.

I did not use sleep/wait, I used an array of projectiles (at that time in the main class) in an array and ran a for loop in simple update that went though every array index every update call. I grant that might be too much, considering your average game has tens or hundreds of projectiles to look over, so how do I do it more effectively?

you mean you want the ship to move without levitate ?

Use this :

[java]

public void move(Vector3f movement)

{

if (levitate)

{

node.setLocalTranslation( node.localToWorld(movement,movement));

}

else

{

Vector3f rotation = getRotation();

node.move( Utilities.localToWorldCoordinatesIgnoreHeight(movement.x, movement.y, movement.z, rotation.x, rotation.y) );

}

}

/Convenience method returning Rotation in radians, multiply result with FastMath.RAD_TO_DEG to convert to degrees.*/

public Vector3f getRotation()

{

float[] rotation = node.getLocalRotation().toAngles(null);

return new Vector3f(rotation[0],rotation[1],rotation[2]);

}

/
Converts local cordinates "(dx,dy,dz)" to world coordinates based on Vector3D "rotation".

  • <a href="http://jerome.jouvie.free.fr/OpenGl/Tutorials/Tutorial26.php"> More info : </a>

    *
  • This kind of deplacement generaly used for player movement (in shooting game …).
  • The x rotation is ‘ignored’ for the calculation of the deplacement.
  • This result that if you look upward and you want to move forward,
  • the deplacement is calculated like if your were parallely to the ground.

    */

    public static Vector3f localToWorldCoordinatesIgnoreHeight(float dx, float dy, float dz, float rotationX, float rotationY)

    {

    //Don’t calculate for nothing …

    if (dx == 0.0f & dy == 0.0f && dz == 0.0f)

    {

    return new Vector3f();

    }

    double xRot = -rotationX;

    double yRot = -rotationY;

    //Calculate the formula

    float x = (float) (dx * Math.cos(yRot) + 0 - dz * Math.sin(yRot));

    float y = (float) (0 + dy * Math.cos(xRot) + 0);

    float z = (float) (dx * Math.sin(yRot) + 0 + dz * Math.cos(yRot));

    //Return the vector expressed in the global axis system

    return new Vector3f(x, y, z);

    }//localToWorldCoordinatesIgnoreHeight

    [/java]
  1. bullets in real life die based on time, not on distance.
  2. you have crap code, thats why it has 1 fps. Do you use sleep() / wait() ? thx for pausing jme for no reason and making it have 1 fps. Jme gives you float tpf, add this to a variable totalTime every frame and if totalTime > 3 sec then remove bullet.

    Packets = Sleep() / wait(); do it another thread, and they may arrive after 100-300 frames.

How many projectiles do you have?



Beyond that you will have to show us your simpleUpdate().

pspeed said:
How many projectiles do you have?
Beyond that you will have to show us your simpleUpdate().

Here you go. A few code snippets, to my surprise it works great (though the machine is an i7 vs Core 2 Duo) and it fundementally follows the same as that real basic one when I first started.
[java] public void simpleUpdate(float tpf) {
shipList.get(0).updating(tpf);
if (remote_test) {
shipList.get(1).updating(tpf);
//add new ships here
}
}
[/java]which then calls to the ship3D class.
[java]
public void updating (float input) {
for (int i = 0; i < 5; i++) {
if (bullet != null) {
bullet.update();
if (!bullet.status())
bullet = null;
}
}
if (!isLocal)
getPacket();
base.move(move);
}
}[/java]
Well, it works fine now, but this is only the first of first prototypes. How much volume can this handle? In the future there may be multiple weapons each with their own bullet updating, some with AI if they are homing projectiles. Is there a better way to do this that sustain higher volumes?
Because on the core 2 duo lab computer on which I do most of my work, sometimes the same code caused the engine to CRAWL. I try to force garbage collecting, sometimes have to restart the engine, sometimes have to restart the machine (though the task manager doesn't show abnromal usage). Either way, one more question....
What is the best way to make the update numbers bigger (since right now I use very small numbers for my motion.) Should I upscale the models (right now at abotu 25% import size), upscale the space, or perhaps just have large integer multiplied by the update tpf?
Thanks, making this work is really a rewarding experience.

Ummm… what is getPacket() doing? That looks super scary right there.



If I read the above code right, you have two ships and 5 bullets each max… 10 bullets and 2 ships should be no problem at all. You should be able to update those thousands of times per second.

pspeed said:
Ummm... what is getPacket() doing? That looks super scary right there.

[java]
public void getPacket() {
Packet data;
int buffer_amt = 0;
try {

buffer_amt = buffer.getBufferAmt(id);

for(int i = 1; i <= buffer_amt; i++) {

data = buffer.get(id);
if (data == null)
throw new NullPointerException();

transform(data.translate.x, data.translate.y, data.translate.z,
data.rotate.x, data.rotate.y, data.rotate.z);

if (data.fire) {
fire();
}
}
}
catch ( NullPointerException npe ) {
// System.out.println("No data at read index " + ridx +
// ":" + widx + " in Ship: " + id );
System.err.print("Buffer read error: buffer_amt: " + buffer_amt);
// buffer.setReadIndex(id, ridx);
}

}[/java]
A packet is a id int, 2 vector3fs, and a boolean, which is the local id, 2 position/rotation vectors, and a boolean showing a fire command being sent. This is actually a multiplayer game, or hopes to be one. As it stands the client for every key press sends data to the i/o threads which goes to the server (right now, just bounces them right back with a different id number) which interacts with what I call a ThreadBuffer to get the data since trying to update the ship class directly (which does node work) is BADDDDD! This code at this time has a second copy of the ship which mirrors the movement of the first.

The Threadbuffer is pretty much circular packet arrays in a ArrayList that is accessed via getPacket(). (The id number is the index in the relevant Array List. Code is in the PS.

Yes, I know there is a native jMonkey MP game api, but this project is actually for a distributed algorithms/networking class, so I think my partner and I better do the server/client aspect myself if I want a good grade, this project is a huge chunk and could spare me having to take a final.

getPacket() pretty much is how the ships on other clients are updated on the local server. If you remember the update method in the main class, their is a second ship, that ship is a remote ship. We're still working on creating ships, probably in the future the client will send only what it is doing and the server will instantiate and send other ship classes from remote players that a client will start up locally.

I dunno, I started this project less than 2 weeks ago with litte foreknowledge of how games are programmed and even less of this engine, so it's kind of on the seat of my pants. But I'm enjoying myself.


If I read the above code right, you have two ships and 5 bullets each max... 10 bullets and 2 ships should be no problem at all. You should be able to update those thousands of times per second.


Well yes, I guess that will work fine (still baffled why a previous attempt went so badly...). What is a good rule of thumb for the amount of objects the engine can continously update, how does one make more room if this limit is reached?

Thanks for you help

ps...the ThreadBuffer code

[java]package mygame;

import java.util.*;
import java.lang.Exception.*;

public class ThreadBuffer {
private ArrayList<Packet[]> input_buffer;
private int count;
private int threshold;
private final int BUFFER_COUNT = 100;
private int[] read_idx;
private int[] write_idx;
private int[] packet_buffer;

public ThreadBuffer(int c) {
count = c;
threshold = 4*c;
read_idx = new int[threshold];
write_idx = new int[threshold];
packet_buffer = new int[threshold];
}

public void init() {
input_buffer = new ArrayList<Packet[]>();
for (int i = 0; i < count; i++) {
System.out.println(i);
input_buffer.add(new Packet[BUFFER_COUNT]);
}
input_buffer.ensureCapacity(threshold);
}

public synchronized void set(int i, Packet input) {
int idx = write_idx;
Packet[] data = input_buffer.get(i);
data[idx] = input;
input_buffer.set(i, data);
write_idx = (write_idx + 1) % BUFFER_COUNT;
packet_buffer++;

// System.out.println("Write: " + i + ": " + write_idx);
}

public synchronized Packet get(int i) {
Packet returnData;
int idx = read_idx;
returnData = getArrayAt(i, idx);
read_idx = (read_idx + 1) % BUFFER_COUNT;

// System.out.println("Read: " + i + ": " + read_idx);
packet_buffer--;
return returnData;
}

public int getBufferAmt(int i) {
return packet_buffer;
}

public int getReadIndex(int i) {
return read_idx;
}

public void setReadIndex(int i, int val) {
read_idx = val;
}

public int getWriteIndex(int i) {
return write_idx;
}

private Packet getArrayAt(int i, int idx) {
Packet data[];
Packet nullPacket = new Packet();
try {

data = input_buffer.get(i);
if (data == null)
throw new NullPointerException();

return data[idx];

}
catch ( NullPointerException npe ) {
System.out.println("No data at index in Client :" + "idx: " + i );
return nullPacket;
}

}


}[/java]

The way I read it, getPacket() could take a really long time in frame terms… I’m reasonably sure that is where your slow down is coming from.



You should try to do as much of the network processing on the network thread as possible. All that the update() needs to know is “where to draw the ship NOW”… and in most network games “now” is an interpolation of a last value and a ‘future’ value, ie: the most recent data received from the network. But even just grabbing the most recent value is better then what it looks like you are doing now.



I’m not exactly sure what ThreadBuffer is trying to do but I think there are simpler ways to go. Have you looked at the java.util.concurrent classes or is there some reason that you must avoid them?



While it’s not necessarily optimal, you could update literally hundreds and hundreds of objects this way with really decent performance. So the performance dip is likely elsewhere.

In a previous iteration I had the network I/O threads working directly with the transform methods of the ship objects, but that was causing scene graph errors. All the documentation I’ve read says that threads cannot interact with any object or any part of an object that makes changes to Nodes or spatials. So prety much the threadbuffer was created to put an intermediary between the network I/O threads and the ship classes. The network I/O proecesses the strings data over the network and puts it into packets, and sends it to the buffer and the ships reads them. The errors stopped.



Of course…the ship objects themselves where threads (I’m still pretty newbish here) and I think that they were also straight objects before I added the threadbuffer. But the documentation states that threads should not even interact with the fields of a class that works with nodes.



Unless you know of some more nuanced way to go about it, perhaps just a method in the ship class itself that acts in place of the threadbuffer, I’m not sure if I can remove it.

One thought occured to me for alternatives…



Would the application still be thread safe if the threadbuffer was moved to the input thread and a ship object called it from the transform method if it was not the local ship? Would that give any performance bonus over the current implementation?

Yes, but right now it looks like you are shoving a bunch of data into your shared data structure that you will just throw away… and you make the update thread get at it by doing some heavy synchronized() calls… which, by the way, are not free in the best of cases and can take 10+ ms under contention.



Since your update is pretty basic at this point then you could probably just get away with some shared volatiles or using AtomicReference.



For example, some shared data structure has:

AtomicReference pos = new AtomicReference();



Your network code calls pos.set( theVectorReadFromTheNetwork )



Then your update loop calls:

Vector3f v = pos.get();



And uses v to update the ship’s translation.



The nice thing about this is that if you get 50 network messages between frames then you waste little time dealing with them as the update loop will just grab whatever is most current… and you avoid heavy synchronization because AtomicReference is doing way smarter things.

And note that my last reply was really from before your second one but the forum ate my post the first time.

You gave me a lot to look over and think about, plus I asked my professor about this and well, it’s a lot of info. Man, this is not easy to absorb.



But, perhaps I can make some immediate improvements, but I can’t overly focus on this because I have more to worry about than just network I/O, but I think there needs to be a buffer between the ship class and the client server i/o threads to prevent scene graph errors.



So, let throw some ideas at you that might improve performance.


  1. Change the threadBuffer to a single variable or a single array with an index for each object in the game and send absolute coordinates and rotations with motion predicition. This will also have an index so the client doesn’t use something twice, and relies on the motion prediction for packet loss.



    Right now I send the relative changes in rotation/translation which I feel needs the 100 cell buffer. This change should eliminate the need of synchronization, since the network threads only writes, and the client only reads, there should be little data corruption.


  2. I’ve never heard atomicreference before, I’m going to do some research and look at examples. How does using the atomics compare to my suggested speedup? How do atomics handle larger and larger scenes and more and more objects. What is the best way(s) to handle such large updating needs?


  3. Is there any way to put a conditional in the update loop, say every 10 iterations of the loop then use this? What exactly is the tpf value?



    Thank you for your insight, it is very helpful and appreciated.
pegasusjf said:
Right now I send the relative changes in rotation/translation which I feel needs the 100 cell buffer. This change should eliminate the need of synchronization, since the network threads only writes, and the client only reads, there should be little data corruption.


These are famous last words. Unless you really really understanding localized thread memory architectures and the ins and outs of volatile, etc., I'd stick to JDK threading classes whenever possible. They are really good.

You definitely don't want a situation where the ship is updated with proper x and y and not z or whatever... also on multi-core systems without proper memory barriers thread 2 may take a long time to see the changes of thread 1 since they are each dealing with their local cache.

If you are buffering deltas then just do it in the same AtomicReference. Unless you are trying to do proper interpolation, etc. which is more complicated than this space allows. So your network code reads the deltas, adds them to the previous vector and stores the new vector into the atomic reference. All update does is read the latest vector and set the translation.

If you wanted to do interpolation then things get a little more complicated as you have to treat previous and next values together atomically and index by time.


tpf is the length of time (in seconds) since the last frame. It can be used to scale animation to be framerate independent.

I don’t have any code down yet, but perhaps I can describe my plans to you for an upgrade to Threadbuffer



Theadbuffer will no longer be a arraylist of packet arrays, but an array of packets (it will be one packet sent at a time) (which will likely become updated with more datatypes as the game gets more complex and more objects are added to consideration. Therefore there will be no more need for the write index or read index. It will not be synchronized, however there will be a lock, an arraylist of atomicbooleans (since array list will allow for any number of objects) one for each object the client is tracking. These atomic booleans will be the new lock between the ship/item objects and the I/O threads.



if the boolean is true the objects will do a read and get the info and set it to false, and if false the i/o thread will do a write and set it to true.



I’m tempted to do a getandset with the atomicboolean, but the data might be overwritten before the next command write reads.



until the conditions are met, the thread i/o will continue to make additions to the packet it will send.



I’m hoping this will make it better, it will get rid of the synchronized call and reduce the data load, any ideas if this isn’t good?



another idea was to send absolute coordinates and vectors over the web (that might be necessary to send absolute updates every second or so in case of lag) but I’m not sure how I can gracefully get all the info because user input is relative.



One more question, is it wise to throttle the update, one issue I have is the fire command sends 5 bullets at once. Could I have a variable that would cotinually add tpf in update function, and only active if it’s above a certain amount (say 1/120th of a second?) Could I use this to reduce bottlenecks by timing different items differently?



Again, thanks for your input.

For the networking code, I’d use a ConcurrentHashMap and not do any of the boolean stuff. The only way to do the boolean stuff is to somehow wait in the network thread which you don’t need to do.



The network code does a put() the update() code does a get.



If you send absolute coordinates/rotation over the network then you can even do it with UDP since if you miss one it’s no big deal. TCP will kill any real time performance if that’s a requirement. A socket can stall for long periods of time as it tries to catch up from a dropped packet.



I’m not sure what you are asking about for the bullets. Is it a bug that it sends five bullets at once and you are trying to stop that or is that the desired behavior and it causes some other issue.



Note: a typical architecture would have the “physics” separate from the render loop anyway so that it can run without worrying about how fast you are rendering. All the update loop needs to do is update based on current positions… just like for the networking.



…but we are really starting to get off of the deep end here.

It’s for a networking class, obsessing over this from the get go is an act of insanity otherwise :stuck_out_tongue: One benefit of doing this is I’m taking a game development class (probably TAing it) so I’ll have a nice head start, but that will be a SP project!



So use a concurrent hash map for the packet class…got it.



The bullets, well, I notice by looking over a packet that the typical fire button press sends about a dozen commands, and all I have is a listener. I suppose I could have a boolean that says if prev not fired don’t fire, or a timer based on tpf…

You have an ActionListener registered with input manager?



If so then you could also just fire on release and ignore the “pressed” events… otherwise you will get a bunch of “press” events.

Ok, I would say the performance is much improved. Most of the time I get about 100 to 400 fps with my code having my ship, moving around, firing bullets, and sending the string packets which are bounced back to the client to move the ship object that represents the “remote” ship.



Sometimes I still get bogging down, but that seems to be an engine hangup, which affects other demos and even when I turn multiplayer support off. Usually a force garbage collection, restarting the IDE, or worse case (rarely) a soft reboot of windows fixes the issue. Would making an executable and running that outside the IDE reduce some of these slowdowns?



I think further optimizations might be a world orientation update at some many frames or packets might be good, because there still is some sync errors, but that will have to await when I’m testing a regular server with my partner.



I have a feeling the update scheme will change, instead of the ships performing I/O with the networking threads, I’m going to move that to the main code. Ultimately, the server will have more to do that just a passive channeler of packets, ultimately it will control the creation of game objects (like asteroids fragments, this project is basically multiplayer asteroids, (with whatever enhancements we can throw in before the due date.) and will require special packet commands to create objects in the client, and likely the main code will send relevant packets to the relevant ship objects.



Bullets are working fine now too. Speaking of which, what is the easiest way of determining hits? I looked in the old jme2 tutorial and it seems that the functions in com.jme3.bounding might be good for a quick and dirty means of having hit detection between the boxes I fire now and bounding boxes over my ship and low poly asteroid models).



Man, these last couple weeks have really opened my eyes, I had a much bigger idea in mind when I started, now I’ll be happy to have a relatively simple asteroids game within the last week I got. It’s been hard, but fun, and I look forward to making something even greater after this.



Thanks for your help,



PegasusJF



ps…if you wish to purse, the relevant code files as they currently stand.



Client_IO: The network I/O code with Client_Input subclass.

[java]

package mygame;



import java.io.;

import java.net.
;

import java.util.;

import java.lang.Thread;

import com.jme3.math.Vector3f;

import java.util.logging.Level;

import java.util.logging.Logger;



public class Client_IO implements Runnable {

private int id;

private Socket client;

private ObjectOutputStream output;

private ObjectInputStream input;

private int WAIT_SEND;

private float tx = 0, ty = 0, tz = 0, rx = 0, ry = 0, rz = 0;

private int transform_count = 0;

private boolean fire = false;

private ThreadBuffer buffer;

private Thread clientI;

private int count = 1;



private final String IP_ADDRESS = “127.0.0.1”; //“131.230.133.25”;

private final int PORT = 12345;



public Client_IO (ThreadBuffer input, int wait) {

id = 0;

buffer = input;

WAIT_SEND = wait;

}





public void run() {

try {

connectToServer();

getStreams();

} catch (IOException ex) {

System.out.println(“connect error”);

}

}



public void packetData(char where, boolean b_input, float val) {

switch (where) {

case ‘X’: //move x

tx += val;

transform_count++;

break;

case ‘Y’: //move y

ty += val;

transform_count++;

break;

case ‘Z’: //move z

tz += val;

// System.out.println(transform_count + " - TZ: " + tz + " VAL: " + val);

transform_count++;

break;

case ‘x’: //rot x

rx += val;

transform_count++;

break;

case ‘y’: //rot y

ry += val;

transform_count++;

break;

case ‘z’: //rot z

rz += val;

transform_count++;

break;

case ‘f’: //fire

fire = b_input;

transform_count++;

break;

case ‘!’: //exit

transform_count = -1;

sendData(“QUIT CONNECTION::EOF”);

closeConnection();

break;

default:

transform_count = -1;

System.out.println(“Default Case reached”);

sendData(“QUIT CONNECTION::EOF”);

closeConnection();

break;

}

if (transform_count != -1) {

if (transform_count >= WAIT_SEND) {

sendData();

reset();

}

}

}



private void connectToServer() throws IOException {

client = new Socket(

InetAddress.getByName(IP_ADDRESS), PORT);

}



private void getStreams() throws IOException {

output = new ObjectOutputStream(client.getOutputStream());

output.flush();

input = new ObjectInputStream(client.getInputStream());

clientI = new Thread(new Client_Input(input, buffer));

clientI.start();

}



private void closeConnection() {

try {

output.close();

input.close();

client.close();

}

catch (IOException e) {

System.out.println(“Close error”);

}

}



private void sendData() {

String message = id + " " + count + " " + tx + " " + ty + " " + tz + " " +

rx + " " + ry + " " + rz + " " + fire;

try {

// System.out.println(count + " :Data Rcvd Val: " + tz);

output.writeObject(message);

output.flush();

count++;

}

catch ( IOException e) {

System.out.println(“send error”);

}

}



private void sendData(String message) {

try {

output.writeObject(message);

output.flush();

}

catch ( IOException e) {

System.out.println(“send error”);

}

}



private void reset() {

tx = 0; ty = 0; tz = 0; rx = 0; ry = 0; rz = 0;

transform_count = 0;

fire = false;

}



//handles input

private class Client_Input implements Runnable {

private ObjectInputStream inputc;

private ThreadBuffer buffer;

// private boolean stop = false;



public Client_Input(ObjectInputStream i, ThreadBuffer j) {

inputc = i;

buffer = j;

}



public void run() {

String message = “”;



do {

try {

message = (String) inputc.readObject();

processMessage(message);

}



catch ( ClassNotFoundException e ) {

System.out.println(“Message error”);

}



catch ( IOException e ) {

System.out.println(“Read IO Error”);

System.exit(0); //how can I do this nicely?

}



} while (true);



}



/


public void stop_connection() {

stop = true;

}



/



private void processMessage(String input) {

Vector3f move = new Vector3f();

Vector3f rot = new Vector3f();

boolean fire;

Packet data = new Packet();

int id, count;

StringTokenizer st = new StringTokenizer(input);



//id of ship

id = Integer.parseInt(st.nextToken());

//count of packet

count = Integer.parseInt(st.nextToken());

//x y z translation of input

move.x = Float.parseFloat(st.nextToken());

move.y = Float.parseFloat(st.nextToken());

move.z = Float.parseFloat(st.nextToken());

//x y z rotation of input

rot.x = Float.parseFloat(st.nextToken());

rot.y = Float.parseFloat(st.nextToken());

rot.z = Float.parseFloat(st.nextToken());

//fire

fire = Boolean.valueOf(st.nextToken());



data.id = id;

data.count = count;

data.translate = move;

data.rotate = rot;

data.fire = fire;



buffer.set(id, data);



}

}

}

[/java]



ship2d - the ship class.

[java]

package mygame;





import com.jme3.material.Material;

import com.jme3.math.
;

import com.jme3.scene.;

import java.lang.Exception.
;





/**

*

  • @author Owner

    /

    public class Ship2D {

    private Spatial mesh;

    private Node parent, forward_gun, base;

    private Material proj_material;

    private Projectile[] bullet;



    private final int PROJ_MAX_DISTANCE = 50;

    private final float PROJ_SPEED = .1f;

    private final int NUM_BULLETS = 5;



    private float curr_pitch = 0, curr_yaw = 0, curr_roll = 0;



    private float speed = 0;

    private Quaternion rotate;

    private Vector3f move;

    private boolean isLocal;

    private int id;

    private int prev_packet = 0;

    private ThreadBuffer buffer;

    private float max_speed = .05f;

    private float min_speed = -.0125f;

    private int bullet_idx = 0;



    public Ship2D(float locx, float locy, float locz,

    float rotx, float roty, float rotz, float scaling,

    Node p_node, Spatial model, Material proj_mat,

    int id_in, boolean local, ThreadBuffer io) {

    mesh = model;

    parent = p_node;

    proj_material = proj_mat;

    rotate = new Quaternion();

    mesh.setLocalTranslation(locx, locy, locz);

    move = new Vector3f(0,0,0);

    mesh.rotate(rotx, roty, rotz);

    mesh.scale(scaling);

    isLocal = local;

    id = id_in;

    buffer = io;



    }



    public void start() {

    bullet = new Projectile[NUM_BULLETS];

    forward_gun = new Node("forward_gun");

    base = new Node("base");

    base.setLocalTranslation(mesh.getWorldTranslation().x,

    mesh.getWorldTranslation().y, mesh.getWorldTranslation().z);

    parent.attachChild(base);

    base.attachChild(mesh);

    base.attachChild(forward_gun);

    forward_gun.setLocalTranslation(0,0,1);

    }



    public void transform(float gox, float goy, float goz,

    float pitch, float yaw, float roll) {

    Vector3f add;

    Vector3f up = new Vector3f(0,goy,0);

    Vector3f forward = new Vector3f(0,0,speed + goz);

    Vector3f sideways = new Vector3f(gox,0,0);

    float[] debug_f = {0f, 0f, 0f};

    Quaternion debug_Q;



    curr_yaw += yaw;

    curr_yaw = curr_yaw % FastMath.TWO_PI;





    if (((speed + goz) <= max_speed) && ((speed + goz) >= min_speed))

    speed += goz;





    rotate = rotate.fromAngles(0, curr_yaw , 0);



    if (speed != 0)

    move = rotate.mult(forward);



    base.rotate(0, yaw, 0);



    /


    if (!isLocal)

    System.out.printf("%s: %f - %s - %s: %f deg %s: %f deg %s: %f deg :: %s: %fn",

    "Remote - Current Speed", speed, "Transform Command", "Pitch",

    curr_pitch * FastMath.RAD_TO_DEG, "Yaw", curr_yaw * FastMath.RAD_TO_DEG,

    "Roll", curr_roll * FastMath.RAD_TO_DEG,

    "Speed", speed);



    else

    System.out.println("Local - Current Speed: " + speed);







    debug_Q = base.getLocalRotation();

    debug_Q.toAngles(debug_f);



    System.out.println("Local Yaw: " + debug_f[1]*FastMath.RAD_TO_DEG);
  • /

    }



    public void getPacket() {

    Packet data;

    int current_packet;

    try {



    data = buffer.get(id);

    current_packet = data.count;

    if (data == null)

    throw new NullPointerException();







    if (current_packet != prev_packet) {

    // System.out.println("Packet receieved: " + data);

    prev_packet = current_packet;



    transform(data.translate.x, data.translate.y, data.translate.z,

    data.rotate.x, data.rotate.y, data.rotate.z);



    if (data.fire)

    fire();

    }



    }

    catch ( NullPointerException npe ) {

    //System.err.println("Buffer read error");

    }



    }



    public void fire() {

    if (bullet[bullet_idx] == null) {

    // System.out.println(bullet_idx);

    Vector3f start = forward_gun.getWorldTranslation();

    bullet[bullet_idx] = new Projectile(parent, proj_material, PROJ_MAX_DISTANCE,

    start.x, start.y, start.z, rotate, PROJ_SPEED);

    bullet[bullet_idx].init();

    bullet_idx = (bullet_idx + 1) % NUM_BULLETS;

    }

    }



    public void updating (float input) {

    for (int i = 0; i < NUM_BULLETS; i++) {

    if (bullet != null) {

    bullet.update();

    if (!bullet.status())

    bullet = null;

    }

    }

    if (!isLocal)

    getPacket();



    base.move(move);

    }

    }

    [/java]



    And finally threadbuffer, new and improved!!! :smiley:

    [java]

    package mygame;



    import java.lang.Exception.
    ;

    import java.util.concurrent.;



    public class ThreadBuffer {

    private final int CONCURRENCY = 2;

    private final float LOAD = .75f;



    private int count;

    private ConcurrentHashMap <Integer, Packet>input_buffer;



    public ThreadBuffer(int c) {

    count = 2
    c;

    input_buffer =

    new ConcurrentHashMap<Integer, Packet>(count, LOAD, CONCURRENCY);

    }



    public void set(int key, Packet value) {

    input_buffer.put(key, value);

    }



    public Packet get(int key) {

    return input_buffer.get(key);

    }



    }

    [/java]

I use ray based bullets, they do only a ray based collision check, cause it needs less calcualtion power than real physic objects and are quite simple to do.