Jump to content

  • Log In with Google      Sign In   
  • Create Account


Member Since 22 May 2004
Offline Last Active May 24 2016 10:01 AM

#4945385 Android 3D and 4D vector classes

Posted by clb on 01 June 2012 - 12:20 PM

If your game code is in Java, you want to have your math library in Java. If your game code uses Android NDK, you want to have your math library in C/C++. Crossing the interop barrier is more trouble than the small performance difference with Java and C++. This is because for most primitive operations, a single cache miss or a function call is already way more costly than doing the operation inlined in code of same language.

If your game code is in Java, the only benefit for having C++ math code is in batched math operations: transforming a vertex array by a matrix, or doing CPU-side skinning in batches, batch-testing primitives for intersection, and so on. As commented already above, using NEON here can offer even more performance.

#4945027 C++ what other IDE other than VC++

Posted by clb on 31 May 2012 - 10:58 AM

If you want to use some other compiler than Visual C++ compilers, while using Visual Studio as an IDE, have a look at vs-tool plugin in my sig. It supports compiling Visual Studio solutions using MinGW, llvm-clang and a few other exotic toolchains. Even though you do not like VS2011, naturally VS2010 isn't going away, and one can still use it.

#4944711 Compiling with NDK without stuffing C++ code in JNI folder?

Posted by clb on 30 May 2012 - 10:04 AM

If you are on windows, you can also use the vs-android plugin, which enables you to compile your solution/projects for Android, independent of which directories your code files lie in. The plugin appears in the Solution Platform dropdown menu, see http://dl.dropbox.com/u/40949268/emcc/vs-tool.png (the other items in that image are from my vs-tool plugin, which is an adaptation of the vs-android plugin for other architectures).

#4944603 Gathering updates before transmitting across network

Posted by clb on 30 May 2012 - 02:26 AM

Our scene layer is three-leveled: scene consists of Entities, which comprise of Components, which have instances of IAttributes. Most components are statically structured, which means that the set of IAttributes that they contain is specified at compile-time. There is special support for DynamicComponent, a component type which allows runtime addition and deletion of IAttributes contained within.

IAttribute itself cannot not contain sequences of elements. If we need vector-like structures, we typically create a new DynamicComponent into the entity in question, and add the sequence/collection of IAttributes into the single DynamicComponent. Scripts can access the Entity-Component-Attribute hierarchy to set up and operate on the data structure.

I could find two screenshots of the editor (don't mind the content displayed, the screenshots were made to show bug reports): http://dl.dropbox.com/u/40949268/AvatarOrientationFixUp.png and http://dl.dropbox.com/u/40949268/Tundra/Tree.png

The technology is called 'realXtend Tundra', and it is open source, if you want to dig into the codebase. Downloadable binaries at http://code.google.com/p/realxtend-naali/downloads/list , and source code at https://github.com/realXtend/naali .

#4944113 Gathering updates before transmitting across network

Posted by clb on 28 May 2012 - 01:28 PM

We use the method you describe as 'dirty flags'. For us, the drawback you describe does not apply. The synchronizable data is structured into attributes, which are changed through a single well-defined interface (IAttribute::Set<T>) and it's not possible to miss setting a dirty flag. In our case, it was not encountered as a burden or being particulary difficult. The server has a constant network rate (typically 20Hz, but configurable in the engine), in which it reads all changed variables and sends them to network in well-coalesced datagrams. This is nice since it disallows multiple individual small datagrams from going out, and keeps the datagrams/second rate well capped (most often to 20/second, if everything fits in one datagram). We haven't encountered much issues with this design, and I don't currently think I'd like to do it any other way. To augment these state sets, we use RPC-like commands what we call 'actions', to provide things like 'player fired', or 'car exploded'.

#4943273 Sleep() not reliable?

Posted by clb on 25 May 2012 - 10:26 AM

Calling Sleep(0); can still sleep any amount of time, e.g. 5ms - 30ms spikes are commonly observed.

The reality is that Windows is not a "hard" real-time multitasking operating system. There are very few of those around, perhaps notably the OS used by RIM in Blackberry is one.

To most precisely time your updates is to target against the vsync of the display, which you do simply by enabling vsync in your game. That gives you (typically) a smooth 60Hz update rate, and how it works is that the driver does some kernel-side magic to track the vblank signals. If you want to do e.g. 30Hz or 15Hz, you can use the presentation interval option to limit to updating every second vblank, or every third, and so on.

Another method to use if vsync is not viable, is to do first compute how much to sleep, then sleep e.g. one msec less than that, and do a busy spin-wait for the rest of the time. I have observed having multiple Sleep(0); calls instead of a single Sleep(target-someconstant); to be more prone to jitter, since each Sleep individually can vary for a long period of time. After that, do an empty "while(tick() < targetTickToPresent()) ;" loop to wait for the exact moment. But the bottom line is that any kind of Sleep pattern cannot guarantee a given hard target timing, and neither will a spinwait loop.

#4941641 Intersection of two line segment in 3 dimensions

Posted by clb on 20 May 2012 - 08:20 AM

When doing computational line-line tests in 3D using floating point, the typical path is as follows:

1. Compute the closest pair of points on both lines. See e.g. MathGeoLib. (link to code).
2. If their distance is smaller than some arbitrary small threshold value (e.g. 0.001f), consider the lines intersecting, false otherwise. Vector distance.

The threshold value effectively transforms the two lines into infinitely long cylinders, and tests them for collision.

Edit: As pointed out below, just noticed the question was for determining intersection between a pair of line <b>segments</b>. For that case, the same method above is used, but computing the closest point pairs in #1 requires clamping the points onto the line segment range. See LineSegment::ClosestPoint(LineSegment) (code) in MathGeoLib.

#4939359 MMO Client == Server

Posted by clb on 11 May 2012 - 12:17 PM

One thing to remember is that when an average user's computer is connected to the internet, it potentially has
1. a firewall and/or a restrictive proxy software running on his computer
2. a firewall and/or a restrictive proxy running on his home network box, local network, or company network
3. a firewall and/or a restrictive proxy running on his ISP's routers
4. a network address translation (NAT) layer on his home network box
5. a (second) NAT layer on his ISP's routers

All these prohibit you from spontaneously connecting direct peer-to-peer connections. The issue nr. 1 is sidesteppable by appropriate firewall exception configuration, the issues nr. 2 and 4 are sidesteppable by a knowledgeable user, but basic users don't understand how to do this. The issues nr. 3 and 5 might be sidesteppable by agreements with the ISP, potentially having money involved. Of course, you can't negotiate with ISPs for the customer's behalf, and you will generally need to be able to solve all of the items above.

The general techniques that are employed by peer-to-peer systems today to solve these are:
- NAT punchthrough. ([1], [2]) This is not possible with TCP for security reasons, but you will have to use UDP. NAT punchthrough will require a centralized arbiter to hand off connections.
- Masquerade into known ports, like TCP 80. Some firewalls allow inbound connections to these. Skype extensively utilizes these to penetrate network firewalls.
- Fallback to using centralized server architectures when neither of the above works. This might sound disappointing, but it is the only way to provide a robust system which guarantees 100% connectivity.

Skype and various Torrent architectures provide interesting case studies on how creating connections "from the internet" towards a single client can be handled.

#4939012 Mouse Events in OpenGL ES2.0

Posted by clb on 10 May 2012 - 09:21 AM

The OpenGL ES 2.0 API does not relate to mouse or any other input methods in any way.

If you are doing windows programming, you can react on the events WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_XBUTTONDOWN, WM_XBUTTONUP, WM_MOUSEMOVE in the WndProc of your main window to receive mouse events. See e.g. this page, or this page.

Alternatively, on Windows, one can use Raw Input to read mouse, keyboard and HID devices (joysticks, gamepads, racing wheels) in general.

#4939006 Cleaning up a vector of pointers?

Posted by clb on 10 May 2012 - 09:14 AM

You have confirmed that commenting out only the 'delete *iter;' line removes the crash?

In that case, I suspect you are either doing double delete, or the 'this' pointer in Map dtor is bad to start with. Check that you don't make value copies of the Map object, or that if you do, you have proper copy-ctor and assignment operators defined, since otherwise making copies of _mazeMap containers will cause duplicates of the pointers to be created, leading to a double delete on the long run.

#4939003 Character Movement Sync

Posted by clb on 10 May 2012 - 09:05 AM

What we do in all of our games which follow the client-server architecture is that the client sends movement actions (==keypresses & releases) to the server. The server updates the game according to the received presses, and streams absolute object positions back to each client.

To keep the bandwidth requirements to a minimum, the data the server sends for each client is carefully compressed bit by bit, using both lossless and lossy compression techniques.

The effect of compressing versus not compressing are of this magnitude: http://dl.dropbox.com/u/40949268/Tundra/Tundra_RigidBody_PhysicsScene.png This application consisted of some 50-100 boxes falling from the sky and colliding onto a ground terrain. Overall, we now require about 0.55KB/sec of data to continously stream the position of one player character from a server to one client while the character is moving. ( http://dl.dropbox.com/u/40949268/Tundra/NewRigidBodyPackets_11b.png )

The code to perform this kind of compressing replication is available in github at https://github.com/realXtend/naali/blob/tundra2/src/Core/TundraProtocolModule/SyncManager.cpp#L703

To perform the low-level compression, it utilizes a serializer object in the kNet networking library: DataSerializer.h

Feel free to borrow any code and techniques there if it's of any help.

#4938777 Reliable UDP and packet order

Posted by clb on 09 May 2012 - 02:57 PM

To implement ordering guarantees to an UDP datagram stream, store a running "packet number" counter in each sent datagram. When receiving datagrams, you can examine the packet numbers to detect out of order receives. When you receive a datagram out of order, you generally have two choices:
- Queue up the datagram and wait for the earlier datagrams before processing the first datagram you received out of order. (This is what TCP does, and it causes head-of-line blocking and incurs additional latency)
- Immediately process the datagram and choose to discard the older datagrams in case they will be received in the future. This is called "latest data guarantee" messaging, because this method does not guarantee that all datagrams will be processed by the receiver, but that at least the most recent/newest version of the data will be seen by the receiver.

Another problem you will need to solve with UDP is accidental datagram duplication caused by the network. UDP does not guarantee that if you send one datagram, that the other end would receive at most one datagram, but instead, the datagram may get duplicated along the way, e.g. due to resends. When you have these unique packet number counters attached to datagrams, you can easily detect duplicate datagrams and discard them.

I have implemented an UDP-based game networking library, perhaps that is of help for reference: kNet over UDP documentation, source code that implements kNet over UDP.

#4938759 Voronoi two-sphere war game (similar to Go)

Posted by clb on 09 May 2012 - 02:19 PM

I'm a long-time go player, and looking at this, the rules seem to be the same, except for the board shape and the connectivity structure between the nodes.

Playing Go on board shapes different from the 9x9/13x13/19x19/some other square grids is not a particularly new thing. In real life, some of the more exotic board variants I have stumbled onto are Go on 3D cylinder boards (one-sided, flattened onto a 2D plane), three-player Go on a triangular board and Go on a multi-level board, e.g. a bit like 3D chess. For a change from the standard Go game, it's a lot of fun! I wish some of the online sites like gokgs.com would adopt these game variants, that would make them a lot easier to play.

#4936892 Breaking out of a double for loop

Posted by clb on 02 May 2012 - 03:37 PM

When the outer loop is not of for-each style, you can do
for(int i = 0; i < n; ++i)
   for(int j = 0; j < m; ++j)
      if (condition(i, j))
         i = n; // Clear the condition of the outer loop so we don't make any extra iterations after finishing the inner loop.
         break; // Break inner loop.

If the conditions of the outer loop are complicated, you can transform that to similar thing you do using a boolean variable (but there's really no need to make it static):

bool iterating = true;
for(int i = 0; complicatedCondition(i) && iterating; ++i)
   for(int j = 0; j < m; ++j)
      if (condition(i, j))
         iterating = false; // Clear the condition of the outer loop so we don't make any extra iterations after finishing the inner loop.
         break; // Break inner loop.

But most often, as was mentioned above, I also favor turning the double loop into a single loop and a helper function which encloses the inner loop.

#4926760 How do I handle Inverse Proportions when a value can be zero?

Posted by clb on 30 March 2012 - 12:41 PM

If I understand correctly, in that flashcard context, a value 0 means "the player has not answered this card correctly even once, or, the player has not seen this card even once." I would give them a value of one, i.e. the first option in my original list of choices.

Perhaps those two cases might be even further differentiated - a card that the user hasn't seen even once should appear with a higher probability than a card the user has seen, but hasn't answered correctly even once?