Skip to content

stanleynguyen/holey-moley

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

79 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Holey Moley

banner

Whack-A-Mole is a popular arcade redemption game invented in 1976 by Aaron Fechter of Creative Engineering, Inc. We have all played this game at least once when we go to arcade game shops with friends during our childhood. We attempted to make it "multiplayer" by recording the score and compare among our group of friends. What if we can make it truly "multiplayer" and real-time? Introducing Holey Moley, the true multiplayer Whack-A-Mole game implemented with modern technologies. Maybe it's time to reconnect with that long-lost friend over a game of Holey Moley? Play it NOW

Game Concept

Our group want to create something that is retro with a taste of modern technology. The aim of Holey Moley is to bring nostalgic feeling with more fun from the classic game of Whack-A-Mole. As such, the game can bridge the generation gap, bringing family members of different generations together to play a game that each one of them knows.

As for the above concept, we decided to implement a real-time online multi-player version of Whack-A-Mole that can be played with smart phones. Inside Holey Moley, you can battle other players in a Whack-A-Mole showdown where you can use items to affect your opponent. Experience and Gold can be earn through matches for acquiring more powerful items. This Gold-for-special-powers system is designed to motivate the players to keep playing to accumulate Gold.

Game Components

The different components that make up our awesome Holey Moley

Game Login

login1 login2 login3 login4

This is where users can register for new accounts, or log in using their credentials.

Game Lobby

lobby1 lobby2 lobby3 lobby4

This is where all the purchases, equipment of items, display of user info are made. Users can also start games via the game menu.

Gameplay

game1 game2 game3 game4

This is where the actual game takes place, objective of the game is score higher, or out-live your opponents during the game. Users can hit mole to get more points, and energy to use items. These items enhances their advantages or sabotages their opponents.

System Requirements

User Requirements

  • Users need to be able to join and play with another player in real time
  • Users need to transfer and receive data instantaneously during game
  • Users need a system (profiles, items, adds-on, etc) that is just right in term of complexity to have fun but not too steep learning curve for new players
  • Users want a game that is aesthetically pleasing and responsive

Functional and Non-Functional Requirements

Funtional Requirements:

  • Concept: Modern Whack-A-Mole game that is way more fun to play but still easy and intuitive enough as its classic counterpart
  • Functionality: The game should have a players system with levels and gold for acquiring items to use in game. The gameplay should be able to handle real-time user IO.
  • IO Operations: The game needs to be responsive and reliable
  • Logic: The game should have logical and modularized implementation

Non-Functional Requirements:

  • Responsiveness: The game should be very responsive to user interactions
  • Reliability: The game should be reliable and clean of bugs
  • Availability: The game should be easily accessible and available all the time
  • Security: The game should be secure. Users' data must be protected. Third-party services should be trustable
  • Cost: The game should cost little to nothing

Use Cases and Use Case Diagrams

Registration & Login

ID HoleyMoley_registeringNewAccount
Name Registering Account
Objective Registering new account to start playing Holey Moley
Pre-Condition User must go to our landing page
Post-Condition Success
a. Account successfully created
b. User redirected to lobby
Failure
a. Duplicate account
b. Registration fail
Actors Primary
a. Player
Secondary
a. Backend Server
Trigger "Register" button on landing page
Normal Flow 1. User click on "Register" button and the prompt appears
2. User fill in all required information (e.g. username, password)
3. Information checking by server
4. New account successfully registered
Alternative Flow Scenario 1:
1. User enter information that doesn't satisfy conditions (e.g. duplicate username, not secure password)
2. Visual Warning on the page
3. User re-enter the information
Scenario 2:
1. Server Error
2. User is signified to try again later
Interacts With Landing page, User checking use case
Open Issues 1. How to signified to admin in case of server error?
2. User experience of filling information

Registration Diagram

ID HoleyMoley_loginToGame
Name Login Account
Objective Login to start playing Holey Moley
Pre-Conditions Success
a. Account successfully logged in
b. User is redirected to lobby
Failure:
a. Wrong credentials
b. Login fails
Actors Primary
a. Player
Secondary
a. Backend Server
Trigger "Login" button on landing page
Normal Flow 1. User click on "Login" button and the prompt appears
2. User fill in all requested information (e.g. username and password)
3. Information checking by server
4. Login successful
Alternative Flow Scenario 1:
1. Wrong credentials
2. Visual warning on the page
3. User re-enter the information
Scenario 2:
1. Server Error
2. User is signified to try again later
Interacts With Landing Page
Open Issues 1. How to signify admin in case of server error?
2. User experience of filling up information

Login Diagram

Lobby

ID HoleyMoley_buyingPowerUps
Name Shopping
Objective Getting power-ups to use inside game
Pre-Conditions Player must have earned enough gold and have at least required level to buy the desired item
Post-Conditions Success
a. Payment went throught and item added to inventory
Failure:
a. Failed to pay or server error
Actors Primary
a. Player
Trigger "Shop" button in Game Lobby
Normal Flow 1. Player goes inside shop by pressing "Shop" in lobby screen
2. Player looks for desired item by searching/filtering/sorting
3. Player presses on the item
Player receives item in Inventory
Alternative Flow Scenario 1:
1. Not enough gold or level to buy
2. Player is signified that he/she doesn't have enough gold
Scenario 2:
1. Server Error
2. Player is signified that the transaction didn't go through and asked to try again later
Interacts With User login
Open Issues 1. How to prevent user from hacking gold?
2. How to notify admin when there's server error?

Shop Diagram

Gameplay

ID HoleyMoley_gamePlay
Name Playing Holey Moley
Objective Getting most points before time's up or outliving your opponent
Pre-Conditions There must be at least 2 players
Post-Conditions Success
a. Time's up and winner is determined
Failure
a. Player leaves game before time's up
Actors Primary
a. Players
Secondary
a. Backend server providing real-time data
Trigger "Random Match" button on game mode choosing screen
Normal Flow 1. Both players have equipped the desired power-ups and searching for random match
2. 2 Players will be matched against each other
3. Players can accumulate energy to use their power-ups (e.g. Spawn bombs to the opponent, freeze the opponent) to give them advantages
4. Time's up
Winner is determined. Experience and gold are earned
Alternative Flow Scenario 1:
1. Player quits during them game
2. The other player is declared winner
3. The game is discontinued and the game room destroyed
Scenario 2:
1. Server Error
2. No penalty to players
3. Users are signified to try again later
Interacts With User login, Joining game
Open Issues 1. How strong the connection needs to be?
2. What is the penalty for in-game quitting?

Gameplay Diagram

System Design

Clients (Users on Web Browsers or Phone App) communicate with a server in 2 ways:

  • HTTP: For any users' data related requests like login/logout, purchases of items, equip items
  • WebSocket: For in game interactions like signaling score update, usage of items

Overall Architecture and Technologies Stack

Overall Model

The server is written in NodeJS using a minimal frameworks called Express. The database used is MongoDB. The web application is in HTML, CSS, and Javascript without any external library. The mobile application is written in Java with Android Studio. For realtime communication, Socket.io is used.

Below are the communication models:

Communication Model

Web App Architecture

Code Structure (inside /server folder)

The web app is structure based on the Model/View/Controllers pattern. Explanation for each folder is below:

  • /index.js: entry point to start the application
  • /package.json: records of dependencies and app scripts
  • /models: data models for all users' data
  • /api: implementation of all API endpoints
  • /controllers: implementation of views rendering
  • /middlewares: middlewares to ensure endpoints security
  • /routes: routing actual endpoints to all implementation
  • /socket: implementation of web socket
  • /views: templates for views
  • /public: all assets, stylesheets, and client-side javascript files served to users
  • /test: all tests for application's components

NodeJS backend

Our choice of this backend technology is because of its asynchronous nature, which makes it able to handle tens of thousands of concurrent connections (this will be further elaborated in Concurrency Section). The fact that our game does not need much CPU-intensive computations but rather than I/O supports makes NodeJS good option.

MongoDB database

We chose MongoDB as out database because of the flexible nature of a NoSQL database. Since we don't have much time to carefully craft the models but rather do it on the go as we implement the app, this flexibility will help our database to be change-tolerant and save our time as we carry out migrations

Socket.io

Socket.IO enables real-time bidirectional event-based communication. It works on every platform, browser or device, focusing equally on reliability and speed.

From Microsoft Office, Yammer, Zendesk, Trello... to hackathon winners and little startups.

One of the most powerful JavaScript frameworks on GitHub, and most depended-upon npm module.

-- Socket.io statement

Socket.io is a Node.js module, so it runs in-process with Node. On the client side, it provides a library clients use to connect to the server.

socket.io lib

JSON Web Token

In authentication, when the user successfully logs in using their credentials, a JSON Web Token will be returned and must be saved locally (typically in local or session storage, but cookies can also be used), instead of the traditional approach of creating a session in the server and returning a cookie.

This is a stateless authentication mechanism as the user state is never saved in server memory. The server's protected routes will check for a valid JWT in the Authorization header, and if it's present, the user will be allowed to access protected resources.

-- Wikipedia

We chose JSON Web Token to implement our users' logging as it's a simple but secure, and easy to implement on other platforms (such as the Android Native App)

Front-end Technologies (HTML/CSS/JS)

We choose to not use any third-party library but rather browser native implementation because that way, our game will be more independent of any front-end vendor that constantly change.

In Frontend Development, the only constant is change

-- Anonymous Author

Heroku

Invest in apps, not ops. Heroku handles the hard stuff — patching and upgrading, 24/7 ops and security, build systems, failovers, and more — so your developers can stay focused on building great apps.

Choose Heroku for the same reasons disruptive startups do: it’s the best platform for building with modern architectures, innovating quickly, and scaling precisely to meet demand.

-- Heroku statement

We chose Heroku as our hosting because of its simplicity and zero-cost. Heroku saves us time from devOps as we can easily deploy with a single-line command. Moreover, Heroku has supports for HTTPS out-of-the-box as we care for our users' privacy and security.

Android App Architecture

Code Structure (inside /WhackAMole folder)

/app/src/main/java/zouyun/com/example/whackamole: contains all our java codes for the activities

  • WelcomeActivity.java: default page on open, for users to login or register
  • TabsActivity.java: game lobby that implements fragments for each page
  • Game.java: fragment that allows user to choose the game mode
  • Inventory.java: fragment that allows user to view their inventory and equip skills
  • InventoryAdapter.java: extends BaseAdapter to populate the inventory
  • Shop.java: fragment that allows user to view the shop and buy skills
  • ShopAdapter.java: extends BaseAdapter to populate the shop
  • Profile.java: fragment that shows user their profile
  • Parser.java: a class to handle parsing of JSONArrays to Java arrays
  • GameActivity.java: activity where the user plays the game

/app/src/main/res: contains our resources for the game

  • /drawable: contains assets in .png and .xml
  • /layout: contains activity layouts
  • /values: contains colour, dimensions, styles and string values
  • /mipmap-*: contains our app logo

Java

We chose to implement using vanilla Java with Android Studio rather than any third-party implementation like Unity as it's simple but elegant, enabling us to achieve more understanding and customizations.

System Testing

In this section, we will go through how to start the app, the tests implementation, and rationale for each test

Web Application Testing

All our unit tests for web application is implemented using Mocha and Chai.
Mocha is a feature-rich JavaScript test framework running on Node.js and in the browser, making asynchronous testing simple and fun. Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct test cases.
Chai is a BDD / TDD assertion library for Node and the browser that can be delightfully paired with any Javascript testing framework.

Getting Started

The web app can be started with our preconfigured npm scripts.
Note: Before starting the server, there will be a few environment variables that need to be set. This can be achieve in dev mode using a .env file base on the sample .env.sample

# script for starting server
npm start
# script for starting server in dev mode
npm run dev
# script for running test suite
npm run test
npm run test:watch # with watch mode

Test Cases

Since our architecture is modularized, we can easily carry out testing on each unit of implementations to cover all out implementations. For the server and web app, we tested the all our api endpoints, and socket implmentation. The below screenshot is 100% test coverage

test coverage

Android App Testing

The unit test cases for Android App are implemented using Android Instrumented Unit Tests.
Instrumented unit tests are tests that run on physical devices and emulators, and they can take advantage of the Android framework APIs and supporting APIs. Such unit tests are more reliable due to the fact that the they run on an instance of Android on a device or an emulator with access to the real device and its resources.
However, the speed of execution is noticeably slower.

Getting Started

Before running the unit test cases, there are some run configurations to edit.

  1. Click Run > Edit Configurations from the main menu
  2. Click Add New Configurations and select Android Tests
  3. In the Name field, enter a name for your new configuration (eg.MyTest).
  4. In the Module dropdown menu, select app
  5. For Test, select All in Module
  6. For Deployment Target Options > Target, I suggest selecting Open Select Deployment Target Dialog
  7. Click OK

Now you can simply run the unit test cases by clicking Run and select the deployment target, which can be a connected Android device or an emulator.
Note: Please ensure that the screen of the device is on at all time when running the test cases.

Test Cases

  • Game Play test results

  • Server Login/Register test result2

Concurrency

Javascript/NodeJS

Javascript offers an asynchronous behavior by default that sets it apart from other programming languages. In asynchronous programs, you can have two lines of code (L1 followed by L2), where L1 schedules some task to be run in the future, but L2 runs before that task completes. For example, in a restaurant, if you order a steak, and then I order a glass of water, I will likely receive my order first, since it typically doesn't take as much time to serve a glass of water as it does to prepare and serve a steak.
Note that asynchronous does not mean the same thing as concurrent or multi-threaded. JavaScript can have asynchronous code, but it is generally single-threaded.

jsthreading

Threading

All operations in Javascript are thread-safe since Javascript programs are single-threaded, making it impossible for any 2 statement to execute at the same time.
Nevertheless, other than your code, everything else runs in parallel which might cause problem at run-time. To tackle this issue, we embrace Functional Programming, encapsulating our operations into blocks that does not affect the global environment (making them as "pure" as possible).

NodeJS's Non-Blocking I/O

This is the secret sauce to NodeJS's high performance despite the fact that NodeJS applications are single-threaded. Much like Javascript in the browser, NodeJS utilizes a fixed-size C++ thread pool behind the scene to handle all blocking I/O tasks.
NodeJS server will accept requests from clients with a single-threaded event loop and dispatch the task to C++ worker threads for processing, freeing the main event loop to accept new requests.

nodethreading

Browser Javascript Asynchronousity

Thanks to the asynchronous nature of Javascript, our browsers like Google Chrome, Mozilla Fire fox can easily executes multiple task while waiting for users' input but still are very responsive to new user inputs/requests. This is achieved by decoupling main thread listeners from worker threads which do all the processing.

browserthreading

Java/Android

Android Gameplay Concurrency

The game requires multiple tasks to execute simultaneously, e.g. moving the mole up and down while informing server the special power employed. Since there are a lot of animations in fast pace, it is important to utilize resources effectively, hence multithreading is used to improve performance and avoid busy waiting. Multithreading is especially used to make sure that certain action is triggered only when certain requirement is fulfilled. By using wait() and notifyAll(), busy waiting is avoided and computational space is saved. For example, in our game design, we will need the user to accumulate certain amount of energy (mana) in order to enable a special power. Hence every time a mole is popping out, the energy level is checked and if it passes the basic requirement, notifyAll() will wake up every thread that is waiting on the lock, then subsequent action will be performed. The diagram can be seen below.

game threading

In the player thread, each method is synchronized to achieve thread-safety so that only one operation in the player thread is able to operate at a time. Since the operations in the player thread are mainly number calculation takes minimal time, starvation is unlikely to happen to affect the performance.

Android UI Concurrency

The user interface from the login page to the game lobby are made concurrent using AsyncTask. AsyncTask enables proper and easy use of the UI thread, allowing us to perform background operations and publish results on the UI thread without having to manipulate threads or handlers.

Information is fetched from the server in the background to allow users to log in or register, as well as to get data to populate the shop, inventory and user profile. Since the fetching operation is expected to be short (depending on network connection), AsyncTask would work well for our application.

When the background computation finishes, the onPostExecute() method will run, and the UI elements will be updated. For instance, the game lobby activity will first check for the user’s information in the background. During this short period of checking, a loading spinner will be shown while the inventory’s grid view is hidden. Once the user data is received, the inventory’s grid view is populate and shown to the user.

Android UI Concurrency

Team Members

Team #11

  • Kai Lue (1001779)
  • Ruth Wong (1001795)
  • Stanley Nguyen (1001692)
  • Zou Yun (1001831)

Acknowledgement

SUTD 50.003 Elements of Software Construction Instructors and TAs:

  • Prof. Sun Jun
  • Prof. Sudipta Chattopadhyay
  • Pham Hong Long
  • Chen Yuqi