Aims
Objectives Tasks
Submission
Aims
CSCI399 Autumn Session 2015
Assignment 2: HTML5 and friends
10 marks
This assignment will let you explore some aspects of the new web client – specifically <canvas> and Web Sockets.
Objectives
You are to implement a multi-person on-line game that utilizes only standard HTML5, Javascript, and PHP. (Since there isn’t really a standard HTML5 yet, the effective standard for this assignment is defined as those features supported by current Google Chrome).
The display aspects of the game are to be handled by Javascript drawing pictures in a <canvas> element. Standard HTML buttons are used for user inputs (you may substitute key- stroke or other mechanisms). User inputs generate commands that are sent via a WebSockets connection to a server process (implemented in PHP) running at a specified port on a known server machine.
The PHP code in the server process implements the game logic and handles communications with all connected clients.
The objectives are for you to:
- Learn how to use the new <canvas> graphics via the defined Javascript API.
- Implement a server application based on one of the current implementations of the WebSockets server model.
- Use the Javascript WebSocket API to connect a web client to a server.
The code for the WebSockets example from the lectures (the “Meet me at …” application) will be available in the /share/cs-pub/399 directory; this includes the version of the PHP Web Sockets server implemented by Kaiser and Samtleben. Your server application will be implemented as a concrete sub-class of their partially implemented abstract class Application.
The /share/cs-pub/399 directory will also contain code of a Java application. This code is a rough draft solution for a Java “ports and sockets” assignment that was set back in 1998. The code illustrates a very similar, but not quite identical multi-player game. It does not involve any web-technologies, both client and server applications are pure Java and the communications use text messages sent over TCP/IP using the Java version of Berkeley sockets. The Java server is of course a multi-threaded server rather than a “select” server as in the PHP application. The old Java code is provided to give you some ideas as to how to implement the game if, and only if you find the task too challenging to attempt independently. It is old code; some of the classes that it uses, e.g. java.util.Vector, have been deprecated.
Supplied WebSockets example
Copy the contents of /share/cs-pub/399/A2/WebSocketExample (on banshee machine) to your machine.
There are two NetBeans projects: MeetingClient and MeetingServer. The MeetingClient is a NetBeans HTML5 project. The MeetingServer is a NetBeans PHP project; but it is not a typical project as its “Properties/Run” identifies it as a script that should be run from the command line.
It is easiest run the server from a terminal session:
The client can be run by dragging its index.html file into Chrome. You will need at least two client sessions (the Javascript contains a “localhost” URL – change to a proper URL if you will be running the client and server on different machines).
When the client starts, it opens a connection to the server. You need to specify a location (- 34.43, 150.88 gives you somewhere in region of Wollongong); and load the map. (The map does not auto-scroll.) You assign you avatar a name.
Try moving the two avatars to the Unibar on UOW campus.
Tasks
You are to implement a version of the “Maze Wars” game using only “standard” Web technologies.
Maze Wars game – overview
The “Maze Wars” game is, I suppose, related to the old “Pac Man” game. There is a maze; its walls are impenetrable, the corridors and open spaces can be traversed by the avatars that are controlled by the users. The maze is “folded” – if you move your avatar along a corridor to the right then, when you pass the rightmost boundary, you will reappear in the equivalent corridor at the left of the maze. In Pac Man, you play against computer controlled “ghosts”. In “Maze Wars” you play against the other users. As in Pac Man, the display shows the maze (a kind of “top-down” view) and the positions of the avatars for all active players; the display is updated every time any player moves.
“Maze Wars” doesn’t involve cannibalism; you don’t eat your opponents as you do in Pac Man. Instead, you shoot them! (You can also kill an enemy by running into them – but then you die as well.) Your avatar can project a bolt of magical energy in the direction that it is facing. This magic bolt will damage any opponent that it hits; the amount of damage rapidly diminishes with distance. (Magic does work through intervening walls, but its intensity is attenuated.) Each avatar starts out with the same “health” (10 units); health is diminished by opponents’ magical fire; health is slowly regained while you move (though this process does not increase health above 10 units). If you kill an enemy, you receive a health bonus (your health is increased by whatever number of health points your enemy had before your last magic bolt destroyed them); there is no upper limit to the number of health points you can acquire through murder.
When a player starts, their avatar will appear at some random location in the maze. They can move, they can fire, and they can get killed. On being killed, you drop out of the game. But you are still connected to the server and can start again.
Implementing Maze Wars
My version of “Maze Wars” is described in the following paragraphs; you can change the details to whatever extent you wish provided that you create an application with equivalent functionality that relies solely on “standard” HTML5 features and a PHP WebSockets server.
The screen shots below show my clients using different instances of Firefox and Chrome browser processes that are all running on the same Windows computer (the WebSockets server was running on my Ubuntu computer). Of course, it would be more typical for a multi-player game if each client ran on a different computer – but that was impractical to set up and would have required more screenshots to illustrate. Note that there are control parameters in Kaiser-Samtleben’s “server.php” driver file; these parameters limit the number of connections from, and requests from a particular IP address. You might have to adjust the settings – but the defaults seemed OK when I ran the example.
Start
On first loading the client web page (HTML file, CSS file, Javascript file), a user will see a “Login form”:
My client has actually already opened a web sockets connection to the server (it does this “on load”). But the user is not really involved until they “log in” and supply a nickname. The nickname is checked for uniqueness, if you pick a nickname that is already in use then the login request will be refused. (An alert is shown for such a refusal; but nothing really changes, you can try again with a different nickname.)
Once logged in, the user will see the “Maze” (in a <canvas> image), some controls for movement, and a list with the nicknames for the other players connected to the same server. (It is of course the same HTML page. The <div> with the “login form” has been hidden, and previously hidden <div>s are now shown.)
Fire and movement controls; <input type=’button’ …> with icons
“start” (and “quit”) controls
In my version, the data defining the maze are represented as an array of strings consisting of 0 and 1 characters – a 1 represents a wall (shown as red). My maze is 50×50 squares; so it’s represented by 50 strings with forms like “1011110…”. I have a fixed maze defined by static data in the server application. These data are sent to the client as part of a JSON data structure that is returned in response to a successful log in. (If you were smarter, you could generate a new randomised maze each time the server process was restarted.) The Javascript code uses these maze data to create a background image of the maze. The <canvas> shows this image and, for active players, the super-imposed images for their avatars.
The server keeps track of currently logged in users. When a new user logs in, the server sends another JSON struct with a list nicknames. This list is sent to all logged in users; so existing users see any additional user as soon as they join. The server allocates random colours to each user; these colour data are included in the same response as the nicknames. The colours are used in the nickname list, and they are also used to colour the avatars of active players.
Start game
The “Start” input button is used to start the player in the game. The Javascript handling this button sends a “start” request to the server. (To avoid any confusion, the “start” button is then disabled. It will be re-enabled as part of the handling of a subsequent “Die!” message sent by the server.)
All requests that are sent to the Kaiser/Samtleben server have the same form. They are JSON stringified Javascript objects with an “action” field, and a “data” field. The data field can be a simple string (e.g. a nickname for a “login” action), or an integer (e.g. direction for a magic blast in a “fire” action), or a more elaborate structure.
When the server receives a “start” command from a particular client, it re-initializes that client’s avatar. A start position is chosen (obviously, you can not start on a wall square and you can not start on a square occupied by another active player). A direction is chosen (is the
A list with the nicknames of all players
avatar initially facing left|right|up|down). The avatar record in the server is marked as “in play”. The server will then compose a message that has data defining all active players. In PHP, this is an array of arrays. Each “row” in the two-dimensional array has data on a single active player – their position in the maze (row, column), the direction that they are facing, and their colour. The PHP array is JSON encoded and broadcast to all active players.
The Javascript code that handles such an ActivePlayerList message will update the display – the background maze image is redrawn, and then an appropriately coloured avatar image is superimposed at the correct position for each of the players.
(The big text labels are just part of the diagram; they don’t appear in the game.) I used a set of little transparencies when generating my avatar images:
I could in effect fill these with the appropriate player’s colour. If that is too involved, just use a coloured circle.
Moving
The active players can now move their avatars, or get them to fire magic bolts.
I chose to use button controls for movement and fire operations; you might instead set the keyboard focus and then catch keystrokes (the usual WASD movements I presume).
The client does some checking in Javascript. If, for example, the player has used the “left” movement control –
Well, if the avatar is not currently facing left (client code needs to keep details of the avatar position and direction) then this is a “change direction” command. A Javascript object is created (action=‘change direction’, data= ‘new direction’), JSON stringified, and sent to the server. The server updates its record for the client, and creates an update message with the new data that gets broadcast to all active players. When they receive this message, they will update their displays. (I simply send an ActivePlayersList message containing data on all players; you could try sending information relating only to the player whose data have changed but if you do that you will find that you must do a lot more record keeping in the client.)
However, if the avatar was already facing left, this use of the “left movement” control would be interpreted as an attempt to move leftwards. The client Javascript code checks whether this is possible. If the next square to the left is a wall, the action is simply ignored; no message gets sent to the server. If the square is not a wall, the Javascript code creates a “move” command that contains the new co-ordinates (row, and column). (It is the Javascript code that deals with the folded maze space – move off the left, reappear at the right etc.)
On receipt of a “move” command, the server code first checks for collisions. It examines the positions that it has recorded for all the other avatars and sees if this movement would result in two avatars occupying the same spot in the space-time continuum. If there is a collision, both avatar records are marked as “not in play”, the two clients involved each receive a customized “Die” message (the data in the message specify that death occurred as the result of a collision and identify the other party). But if movement can be made safely, the server simply updates the coordinates in its record for this client. In either case, an ActivePlayersList message is then broadcast with up-to-date data on all active players.
If a client receives a “Die” message, it will display an alert (including the details of how death occurred), it will redraw the maze to show just the background, and will re-enable the “start” button.
Collision imminent! Troubles for two:
But it is ok, you can start again:
Magic Fire
If you use your “Fire” button, your avatar fires a bolt of magic in the direction in which it is currently facing.
Waiting for him to come into range:
Gotcha:
After a couple more shots were exchanged:
Damage done by fire – 16, 8, 4:
Walls attenuate magic force, so damage is lessened:
The Javascript client handles “Fire” by sending a command with action “fire” and data being the direction.
The server handles this by first sending an equivalent “fire” update back to all active clients – the Javascript code in the client deals with a “fire” update by drawing some representation of the magic bolt (I was lazy and my code doesn’t properly represent bolts that are crossing the folds of the maze). The server continues by checking whether any opponent has been damaged. The range of a bolt is three maze squares in the direction specified – with damage 16, 8, and 4 units (power being halved for each wall square that must be penetrated). If an opponent is found, his/her health is decreased. If the opponent’s new health rating falls to zero, then he/she is “dead”. A “Die” message will be sent to the appropriate client; the message identifies the murderer; the client record in the server will be updated to show that they are no longer “in play”. The murderer’s own health is incremented. An “ActivePlayerList” update message gets sent to all remaining active players.
Summarizing my version
Commands sent via WebSockets and the possible responses:
Send Login command with nickname as data;
Receive a Login response; response data will either state that login was refused (nickname already in use) or indicate that login was successful in
which case the response also includes the data that define the maze layout. The client will use these data to create the background image of the maze.
After sending a Login response to the new client, the server will broadcast a “Player List” message to all clients. This message will contain the data with nicknames and colours. Clients update the player list area of the display.
- Send Start command (data is empty string);
There will be two messages in response.
The first is sent only to the client that sent the Start command. This response message contains the data that define the initial position and direction of the player’s avatar; these data are used to initialize variables in the client. The values in these variables will be checked and updated in subsequent change direction or move actions.The server will then broadcast an “ActivePlayersList” message to all active clients; this message contains data defining the positions, colours, and directions of all active players. The clients use these data to update the game display.
- Send Move command, the data are the updated row, column position of client’s avatar.
The server checks the data.
A collision will result in a “Die” message being sent to the participants in a collision; their server side records are updated as being not in play.
If there is no collision, the client’s record is updated to show the new position.The server then broadcasts an “ActivePlayersList” message to all active clients which will again result in their updating their displays.
- Send Direction change command, the data are the new direction. The server updates the client’s record.
The server then broadcasts an “ActivePlayersList” message to all active clients which will again result in their updating their displays.
- Send Fire command, the data are the direction of fire.
The server broadcasts a “fire” update message; the data are the co-ordinates of the firer and the direction of fire. Clients handle this message by drawing some representation of the magic bolt.The server then checks for damage to other players, updating their records as required. If a victim has been killed, the server will first remove the player from play, send a “Die” message to the appropriate client, and then broadcast
an ActivePlayersList update.
Client code
- Establish web socket connection, setting handler functions for connection close, and for handling a message sent from server.
Connection close – display an alert, and either close the page or disable all controls.
- Connection handler:
A dispatcher function that will invoke specific functions for handling the various messages that can be received from the server – login response with map, player list, start response with initial coordinates, active player list with its data, fire message, die message. - Event handlers for movement and fire buttons:
Javascript checking functions and functions to compose messages for server.Server code
- Class extending Kaiser/Samtleben’s PHP class Application
- Static data members with data for map
- onConnect – extra code to create an application information record that is added to the “Connection” object provided by the Kaiser/Samtleben code.
- onDisconnect – extra code to update player lists displayed by those players still connected.
- onData – handler invoking methods specific to the different commands that the client may send – login, start, direction, move, fire.
Your code may organize things differently.
Bonus marks
Your_final_mark = minimum( 10, mark_for_basic_assignment + bonus_marks)
The following are suggested extensions that might make the assignment more interesting.
A larger maze (1)
Work with a larger maze (e.g. 250×250) with each client displaying only a 50×50 segment that is approximately centred on the player’s avatar (it doesn’t have to re-centre the display after each move by the player, just whenever the player is getting
close to the edge).
The challenge here is to handle the folding of the maze neatly – when you
approach the right size of the 250×250 maze your 50×50 block should have some data taken from the left side. This shouldn’t involve anything more than a little function that remaps coordinates, and a function that fills the canvas with segments taken from a large off-screen 250×250 image – but I expect to see some really horribly convoluted code.
A display customized for your Android (or iToy device) (2)
Since I was designing for a desktop browser, I didn’t have any concerns about screen space. But really, an application like this is intended for mobile devices where screen space is limited, and interaction styles differ.
If you have a suitable mobile device with a browser that supports WebSockets and <canvas> then try implementing a suitable version of the client. (The need for WebSockets might exclude iToys – but there may be a way to enable the experimental WebSockets code that is in the iToy browser.)
You should try, as far as it is possible, to create the different client version by simply having different CSS stylesheets.
Your report will need to include some photos showing the application running on your mobile device.
POV – point of view (3)
Back in 1998, when this assignment was set for CSCI213, one student implemented a variant which was more like a first person shooter game. (There weren’t any bonus marks, he did it because he wanted to improve his skills in the use of the Java graphics library.) It changes game play a lot; it becomes much more a matter of luck – turn a corner, find that you are “behind” another player, blast them.
Instead of a top down view of the maze, his display was “point of view” as suggested by the following diagram
Submission
You are assessed on a report summarizing your work. This report should be prepared using a word processor and converted to PDF format prior to submission. You have to include several screenshots; screenshots can be obtained on the Ubuntu systems via the “Take Screenshot” accessory in the Applications menu.
The report should contain at a minimum
- An overview section explaining the exercise and summarizing the structure of the client and server projects.
- A summary of the messages that are exchanged using web sockets.
- Source for the HTML page, its CSS stylesheet(s), and your Javascript code.
- Your “class MazeServerApplication”
class MazeServerApplication extends Application { … } - Any other PHP classes/free-functions that you wrote.
- Screen shots illustrating your application running.
- Some server side tracing statements that detail operations by your server.
You can use PHP echo statements in your server code to log details of messages received and actions performed. These can help debugging and provide evidence for the system working, e.g.:
Dick, at [46,10], is firing in direction 0 Checking square [45, 10] That is a wall, damage reduced Checking square [44, 10]
Checking square [43, 10] Have hit Tom whose health is 10 doing 2 damage
turnin
For CSCI399, asignments are submitted electronically via the turnin system. For this assignment you submit your assignment via the command:
turnin -c csci399 -a 2 A2.pdf
This assignment would be due at end of week 5 (April 3rd), but that is the Easter holiday
weekend. So the assignment has been made due on April 10th – but there will be NO LATE
SUBMISSIONS!
Remember, turnin only works when you are logged in to the main banshee undergraduate server machine. Transfer your report file to banshee using an ftp client. Then login via ssh and run the turnin program.
Mark distribution
Overall presentation – 1 mark
Evidence for operation (screen shots, tracers) – 2 marks Overview and message summary – 2 marks
Client HTML and CSS – 1 mark
Javascript – 2 marks
class MazeServerApplication (PHP) – 2 marks