Hello, I am sill toying around with SpiderMonkey and would probably benefit from some advice.
I created a WorldServer application (Headless) that sends transformation data to a WorldClient.
The client loads a couple of models, attaches them to nodes and and waits for positional/velocity data coming from the server.
First thing I would like to have feedback on :
I assumed that the server might not be able to send timely transformation data to have a smooth rendering on the client (i.e. it might not be able to update the client at every frame).
Based on that assumption I implemented an interpolation of translation and rotation for every object. Interpolation is based on velocity only, not acceleration (so it is a linear interpolation, which might be ok I guess if the gap between two updates is not too high).
[java]
…
ConcurrentHashMap<Integer,ObjData> objects; // ObjData is pretty obvious, see below.
…
@Override
public void simpleUpdate(float tpf)
{
Iterator it = objects.entrySet().iterator();
while (it.hasNext())
{
Map.Entry entry = (Map.Entry)it.next();
ObjData od = (ObjData)entry.getValue();
// interpolation
od.rotation= od.rotation.add(od.rotVelocity.mult(tpf));
od.translation = od.translation.add(od.traVelocity.mult(tpf));
// update
Spatial sp = rootNode.getChild(""+(Integer)entry.getKey()); //I know I should improve this
if (sp!=null)
{
sp.setLocalTranslation(od.translation);
float[] rot = od.rotation.toArray(null);
sp.setLocalRotation(new Quaternion(rot));
}
}
}
[/java]
The server, so far, does not get any input (it is just a test) , so it simply interpolates the real position and rotation in the same way, but in theory I do expect the velocity vectors to be controlled by some input (maybe from another client etc).
I used a ScheduledExecutorService
[java]
ScheduledExecutorService updExec = Executors.newSingleThreadScheduledExecutor();
…
public void initUpdater(int msecs)
{
updExec.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
long newTime =System.currentTimeMillis();
if (lastUpdate>0)
{
Iterator it = objects.entrySet().iterator();
float tpf = ((float)(newTime-lastUpdate))/1000f;
while (it.hasNext())
{
Map.Entry entry = (Map.Entry)it.next();
ObjData od = (ObjData)entry.getValue();
od.rotation = od.rotation.add(od.rotVelocity.mult(tpf));
od.translation = od.translation.add(od.traVelocity.mult(tpf));
// objects.put((Integer)entry.getKey(), od);
}
server.broadcast(new ObjMessage(new HashMap(objects)));
lastUpdate = newTime;
}
}, msecs, msecs, TimeUnit.MILLISECONDS);
}
[/java]
It actually works (jsurt because JME & SpiderMonkey are so cool ), I am sending updates every 300 ms (normally it would be faster, but I am simulating an eventual ,load with many connected clients etc), rendering on the client is quite smooth thanks to the interpolation.
First thing :
Is this scheduled service an appropriate choice? It is basically a scheduled thread, nothing special…
Second thing : I am using a ConcurrentHashMap (thanks pspeed for the hint oin a previous thread here)
ConcurrentHashMap<Integer,ObjData> objects;
however I am not able to pass it to the Message class. I have to pass it as HashMap and convert it back (Instantiating a new object each time).
[java]
…
@Serializable
public static class ObjMessage extends AbstractMessage
{
HashMap objects;
public ObjMessage()
{
}
public ObjMessage(HashMap<Integer,ObjData> objs) // would not accept a concurrentHashMap here
{
objects = objs;
}
public ConcurrentHashMap getObjects()
{
return new ConcurrentHashMap(objects);
}
}
[/java]
It doesn’t look an efficient way of dealing with the data, is there any way I can remove the HashMap / concurrentHashMap step?
When I created my ObjData class I had to do this :
public class ObjData extends Serializer {
…
Should I create a wrapper for the CocnurrentHashMap extending the Serializer too?
Overall, am I on the correct path with this approach (threading, interpolation, objdata etc)?
thanks
Francesco