Preface: I am making a 2D networked game where each player controls a single character. Primary goal is getting more comfortable with Java, but I'm having fun making it too.
This topic has two parts. The first deals strictly with Java and implementing the key listeners to move a player.
The second I would like to pretty much detach from Java completely and deal strictly with pseudo-code or simply documentation.
1) Player Input in Java
Currently, my client GUI has a JPanel with addKeyListener(new ClientInput(this));
My ClientInput extends KeyAdapter and has functions for keyPressed, keyReleased, and keyTyped.
First problem is with continuous input. Just like when typing on here, if you hold a letter down, it is subject to your input delay. Press and hold "f" and you see it types one "f", you get a delay, then a steady stream of "f"s. At first I thought it was because I was using keyPressed instead of keyTyped, but it seems Typed does the same thing. How can I deal with this issue? I'm assuming I'll need to use something other than KeyAdapter.
2) Networked Movement Architecture
Preface note: I am using a TCP connection.
I have started everything with the most basic and straightforward implementation. As of now, this is how my client/server function:
a) Client presses "up" - sends "move up" message to server
b) Server moves the player up, sends "move up" message to ALL clients
c) All clients move the player up
As I said, this is the most "Brute force" method I could come up with. That was the idea - start simple, optimize later (as I've been told on several occasions). Well, I had 2 friends connect and we all started running around .. took about 5 seconds before all the clients crashed. It seems the server sent a null network message to everyone for some reason and everyone crashed. I am certain this is related to the high volume of messages as when we all re-connected and moved slowly, it worked. But moving steadily faster over time.. null message again. The server stays up and running, which was weird.
Firstly, does it make sense that 3 players connected to a central server, sending about 30 messages per second and the server with a thread for each client responding with 90 messages per second would cause problems? I know it seems like a lot but I kinda would have thought it could handle much more.
Secondly, I think it's time to look into a couple optimizations. I think if I can figure part 1 out, I can at least slow the player input down a little bit and lessen the number of messages sent. After reading through some other posts, I've gathered that this is a popular architecture:
a) Client presses "up"
b) Client performs client-side collision check. If it fails, end here. Else..
c) Client moves up (1). Sends "Moving up" message to server
d) Server gets "Moving up" message. Sets a "moving" flag to indicate this player is moving up.
e) ??? Update Thread ??? on server - every X ms, check for moving flags, update positions, broadcast updated coordinates to all clients
f) Clients get message from update thread. Update coordinates to what is broadcast.
g) Client releases "up"
h) Client stops locally, sends "Stopped" message to server
i) Server gets "Stopped" message. Clears movement flag.
This would involve adding a new thread to my server, the Update thread from step "e". I guess all it would do is store the "old" value of player positions and check the movement flags for each player (every X ms). If it is set, update the position of the player and send a message to all clients letting them know the player had moved.
(1)* I realize in this step (c), I would need to implement some prediction. Depending on the current latency, this may cause the player to stutter along as the server constantly corrects the player's position. I may end up needing to force a delay in here to make sure the client doesn't update the position too quickly.
This adds three levels of optimization. The first is the client doesn't even bother sending a move message if client-side collision fails. I realize there is a chance for error here - if the client has bad information, the client could fail collision even if there's really nothing there.
The second is limiting the number of messages sent to the server. The client will only send a message to indicate they've started moving (in a direction) or stopped moving (in a direction). The client will probably be moving a lot and updating their direction constantly, but probably not 30 times a second, thus limiting the number of messages sent to the server.
The third is capping the number of messages sent to the client. The update thread will only broadcast a message every X ms instead of on every single client move message. While this might cause a slight delay, I don't think it will affect my game too badly.
Anyone have any thoughts on this? Again, please keep anything pertaining to point 2 as pseudo-code or just steps. Not only does it make it easier for me to read, but it allows me to figure out the syntax myself (and allows non-Java readers to make use of it too). If there's nothing wrong with this.. great! Hopefully this can serve as a resource for others with the same issue. If there is though, please don't hesitate to point it out.
Thanks,
Jeremy