CS/IMGD 411x Project 3

Fruit Ninjas - Multiplayer Fruit Ninja

[Fruit Ninjas]

Due date: Sunday, September 29th, 11:59pm


Overview

The goal of this project is to leverage the code and skills acquired in Project 1 (Serialize) and Project 2 (Yak) to design and implement Fruit Ninja's, a multiplayer, networked version of Fruit Ninja. Doing so reinforces the concepts in the previous two projects (game programming, serialization, sockets, client-server programming) and extends skills in multiplayer game programming.


Overview | Details | Tips | Submission | Grading


Details


Details: Synch | Messages | Game Objects | Server | Client


Synchronization

Fruit Ninjas - the multiplayer, networked version of Fruit Ninja - can, and should, make extensive use of the existing Fruit Ninja game, taking advantage of game sprites and sounds and game objects provided. The base requirement must include the core gameplay (i.e., slicing fruit with a mouse-controlled sword, tallying points in the process), but not necessarily extra features commonly found in commercial multiplayer games (e.g., no server lobby). Instead, the game can start right into the gameplay when the desired number of clients are connected and end/exit when the timer runs out.

Fruit Ninjas must use a client-server architecture with an authoritative server. The server can be headless. The client should provide an interface for the player to input the server hostname and then connect at a well-known port.

For functionality, Fruit Ninjas needs to support at least two players and at most five players playing simultaneously (i.e., slicing the same fruit) from different, independent computers connected to the Internet. Players should be able to see the swords of the other players. Kudos messages should be either shown only to the player that earned them or should be distinguishable (e.g., by color) as to the player that earned them. Feel free to be creative in extending Fruit Ninja with new gameplay (e.g., competitive or cooperative). A possible screenshot showing competing Ninjas is shown below.

[Fruit Ninjas Screenshot]

In general, there are a variety of ways that the game objects can be modified and synchronized between server and clients, especially player-controlled objects. Usually, only "important" objects and associated events are synchronized. For example, in Fruit Ninja, a fruit being sliced is an important (perhaps, the most important) event and should be synchronized across all computers. Explosions when a Fruit is sliced, on the other hand, only provide decorations and, as such, do not need to be synchronized.

For this project, a client must only gather player input and send it to the server but not act upon the input. This means the client gets mouse movements and sends the data (i.e., the (x,y) coordinates) to the server. The server then moves the mouse and syncs the new location with the clients. Given this restriction - only the server moves Swords in response to mouse input - the recommended design is to have the server determine when a Fruit is sliced.

Note, in theory, having the same random seeds on clients and the server could mean that random events (controlled by rand()) such as the spawning of Fruit do not have to be synchronized, but in practice, this requires events to take place at specific game clock times. Such timed delivery of events is not currently supported by Dragonfly. So, the suggested implementation has only the server spawn Fruit (via the Grocer), with the newly-created game objects then synchronized with the clients.


Details: Synch | Messages | Game Objects | Server | Client


Messages

A message format and protocol (a core component of any client-server communication) should be designed for both server-to-client communication and client-to-server communication. The client may only communicate player input (e.g., mouse positions) to the server, but the server needs to communicate at least several types of messages (e.g., sync object, destroy object, game over). And both client-to-server and server-to-client options should include an exit message if they disconnect. Note, message types can be setup as an enum class.

A suggested format is to include a base header for all messages:

Additional elements depend upon the message type.

Synchronize

When the message type is to synchronize an Object, the body is then:

Delete

When the message type is to delete an Object, the body is:

Exit

When the message type is game over or exit, there is no body.

Mouse Movement

For client-to-server communication, when the message type is mouse movement the body is:

Processing Messages

After pulling the message from the socket (via the NetworkManager receive()), the server or client can subsequently check the message type and take appropriate action.

The server takes actions for the incoming message type:

The client actions for the incoming message type:


Details: Synch | Messages | Game Objects | Server | Client


Game Objects

Some suggestions for modifications to the base Fruit Ninja objects in order to support multiplayer gameplay.

Sword

Grocer

Fruit

Points

Timer

Kudos

GameOver


Details: Synch | Messages | Game Objects | Server | Client


Server

Server-only functionality is most easily handled by a Server game object.

Upon creation, the Server object sets the NetworkManager to server mode (setServer(true)).

The Server handles network events and step events. For network events:

For step events, the Server primarily looks to see if any Objects need to be synchronized with the clients.

For ease of Object management, the Server should keep track of all Swords and Points with a list (e.g., an array or a std::vector) for each.

Note, when creating the initial Sword on the server upon connection and then synchronizing with the clients, care must be taken not to have an Object id be the same as another Object id on a client. The suggestion is to set the id manually on the Server when it is created iniitally, using an offset of a large number (e.g., 100) and the socket index for the id.

Tip: The Server can tell if an Object is newly created if the method Object::isModified(df::ObjectAttribute::ID) returns true.

Tip: The Server can tell the type of an Object with either a dynamic_cast (e.g., if ((dynamic_cast <Fruit *> (p_o)) != NULL) ... for a Fruit) or via Object::getType() (e.g., if (p_o -> getType() == SWORD_STRING) ... for a Sword).

Tip: A modified object ID can be checked via Object::isModified() and a df::ObjectAttribute::ID mask (e.g., unsigned int mask = (unsigned int) df::ObjectAttribute::ID).

Tip: A modified Points value can be checked via ViewObject::isModified() and a df::ViewObjectAttribute::VALUE mask (e.g., (unsigned int) df::ViewObjectAttribute::VALUE).


Details: Synch | Messages | Game Objects | Server | Client


Client

Core client-only functionality is most easily handled by a Client object.

Upon creation, the Client object sets the NetworkManager to client mode (setServer(false)). It should also provide a way for the player to enter the server hostname (e.g., by spawning a ServerEntry object).

The Client should handle network events. For network events:

Tip: The Client can tell if an Object already exists via trying to fetch it with WM.objectWithId().

Tip: For modularity and readability, the Client may want a method that creates an Object of the indicated type and returns a pointer to it. e.g., Object *createObject(std::string object_type). It can use this method upon receiving a sync message from the server and not having an Object with the indicated id.


Details: Synch | Messages | Game Objects | Server | Client



Overview | Details | Tips | Submission | Grading


Tips

Additional Network Support

It may be helpful to extend the NetworkManager to support more general sending messages. While sent messages have a common header, the body depends upon the type. Versions of the sendMessage() method can be invoked based on the message type and parameters passed in, formatting and actually sending the message as appropriate. Versions could include:

  // Send message from Server to Client.
  // GAME_OVER or EXIT
  // Return 1 if something sent, 0 if nothing sent, -1 if error.
  int sendMessage(MessageType msg_type, int sock_index=-1);

  // Send message from Server to Client.
  // SYNC_OBJECT or DELETE_OBJECT
  // Return 1 if something sent, 0 if nothing sent, -1 if error.
  int sendMessage(MessageType msg_type, df::Object *p_obj, int sock_index=-1);

  // Send message from Client to Server.
  // MOUSE_INPUT
  // Return 1 if something sent, 0 if nothing sent, -1 if error.
  int sendMessage(MessageType msg_type, df::Vector mouse_position, int sock_index=-1);

The sock_index=-1 parameter defaults indicate the send should be to all connected sockets.

Solo Development

For development and testing on a single computer, the hostname localhost can be used to run a server and have clients on the same computer connect to it. Having multiple clients running on one computer is easier when the clients are not in fullscreen mode. With Dragonfly, this is done in the configuration file via: window_style:default,. Then, the window dimensions can be made small - small enough to fit multiple client windows on one monitor via something like: window_horizontal_pixels:600, and window_vertical_pixels:450,.

For mouse input for a specific client, it can be helpful to only respond when the mouse is over the corresponding window. This can be done in Dragonfly via:

  // Check if mouse outside game window.
  sf::RenderWindow *p_win = DM.getWindow();
  sf::Vector2i lp = sf::Mouse::getPosition(*p_win);
  if (lp.x > df::Config::getInstance().getWindowHorizontalPixels() ||
      lp.x < 0 ||
      lp.y > df::Config::getInstance().getWindowVerticalPixels() ||
      lp.y < 0) {
    // Outside window so don't respond to mouse input.
  } else {
    // Inside window so respond to mouse input.
  }

Development Order

For development, start with just the Sword, and not other objects. Have it created at the server when a connection comes in from a client. Then, mouse input at the client is sent to the server and the server moves the sword. The new position is sent back to the client and sees the Sword move. Doing this will help get the foundations of server synchronization with the client (to create the Sword), client-to-server communication (mouse movement) to move the Sword, and then again server synchronizaiton with the client (to move the Sword).

Once the Sword is successfully implemented and debugged, then add a single piece of moving Fruit, created on the server and synced with the client. Then, add Fruit slicing and out of bounds (done at the server), then deleted and synced (with the client)

Then, the Grocer (at the server) that spawns multiple Fruits. Then, add Points. Then, GameOver. Then, the Timer. Lastly, Kudos.

Misc

Make sure the window size (in characters) is the same on the server as it is on all the clients. This is true even if the server is headless, as the window size parameters provide the default game world size, too. e.g.,

#
# Server configuration file.
#

# Run in headless mode (no graphics window or input).
headless:true,

# Window dimensions in characters.
window_horizontal_chars:80,
window_vertical_chars:26,

Overview | Details | Tips | Submission | Grading


Submission

Your assignment is to be submitted electronically (via Canvas) on the time and day due. You must hand in the following:

  1. Source code:

  2. A README file listing: platform (Windows, Mac or Linux), how to compile (if there are special settings), how to run (ditto) and anything else needed to understand (and grade) your game. You should indicate how the two players compete or cooperate, depending upon your implementation.

  3. VIDEO showing: A) your code compiling, B) your Fruit Ninjas server starting up, C) 2+ Fruit Ninjas clients starting up and connecting to your server, D) players interacting in 2+ different windows moving Swords with trails of different colors, having that data echoed on all screens, E) Fruit Ninjas gameplay commencing, including explosions, points, a timer and game over messages, and F) clients and server gracefully shutting down. The video should be 10 minutes or less. It does not need to be polished, just complete. Recording via Zoom can work well. The video can be included in the submission or hosted online and with a link to follow.

Before submitting, "clean" your project:

This will remove all the temporary (compiled) files. Failure to do may mean you file is too big to submit!

You do not need to submit any Dragonfly or SFML files.

Use zip to archive your files.

To submit your assignment (say, lastname-proj3.zip) via Canvas:

Open: Assignment - Project 3 Click: Upload Click: Drag your zip file,
Select: lastname-proj3.zip
Click: Submit Assignment

When successfully submitted, you should see a message similar to:

SUBMITTED on September 29, 2024 3:54pm

Important - you must click the Submit Assignment button at the end or your file will not be submitted!


Overview | Details | Tips | Submission | Grading


Grading Guidelines

Breakdown

Swords - 30% : Correctly supporting creation and synchronization of Swords across multiple clients is worth about 1/3 of the grade. This includes a single server with 2+ clients that can connect and move (and see each other's movement) of Swords. Implementing this aspect is crucial to demonstrate an understanding of multiplayer game programming and get the rest of the multiplayer game features working.

Fruit, Slicing and Points - 30% : Determining slicing on the server and synchronizing it (with explosions and sound) on the client is part of the core game functionality and worth about 1/3 of the grade.

Grocer, Timer, Game Over, and Kudos - 30% : Getting the "extras" working (created, synchronized) provides for complete gameplay and is worth about the remaining third of the grade.

Documentation - 10% : Not to be overlooked is including the documentation provided, as well as having that documentation be clear, readable and pertinent to the assignment. This primarily includes the README described above but also any needed supporting information. Having well-structured, readable and commented code is part of Documentation, too. Getting in the habit of good documentation is important for large software projects, especially when done in teams.

Note, bugs and/or code that has not been tested can result in points taken off for any of the areas above.

Rubric

100-90. The submission clearly exceeds requirements. The Swords are synchronized appropriately and appear to move flawlessly. Fruit-slicing and Points also work flawlessly. All extras - Grocer, Timer, Game Over, and Kudos - are in place for full-Fruit Ninjas functionality. Documentation is thorough and clear and code is well-structured, commented and readable.

89-80. The submission clearly meets requirements. The Swords are synchronized appropriately and appear to move smoothly. Fruit-slicing and Points work well. Most of the extras - Grocer, Timer, Game Over, and Kudos - are in place and work well. Documentation is thorough and clear and code is well-structured, and mostly well-commented and readable.

79-70. The submission barely meets requirements. The Swords are synchronized but may not work smoothly or robustly. Fruit-slicing and Points may not work consistently. Some extras - Grocer, Timer, Game Over, and Kudos - may be missing or not robust. Documentation is present, but may be unclear or missing aspects and code may be difficult to read and parts of the code poorly-structured and/or uncommented and difficult to read.

69-60. The project fails to meet requirements in key places. The Swords may not be correctly synchronized or working correctly. Fruit-slicing and Points may not work correctly nor robustly. Extras - Grocer, Timer, Game Over, and Kudos - are mostly missing. Documentation is inadequate or missing and some parts of the code are poorly-structured, uncommented and difficult to read.

59-0. The project does not meet many of the key requirements. The Swords are not be correctly synchronized or working correctly. Fruit-slicing and Points do not work correctly nor robustly. Many or even all extras - Grocer, Timer, Game Over, and Kudos - are missing. Documentation is woefully inadequate or missing and code is poorly structured, uncommented and difficult to read.


Overview | Details | Tips | Submission | Grading


Return to the IMGD 411x home page