06MA4010991AP
Computer Game Design

Week 9

Multiplayer Games

A multiplayer video game is one which more than one person can play in the same game environment at the same time. Which enables flexibility and ingenuity of regular human thinking, other than AI controlled opponents.

There are two types of multiplayer platforms:
1) Single System
- several controllers / take turns
- split screen
- console / arcade games

2) Networking among multiple Systems
- network interface / protocol
- architecture and latency

Multplayer design elements

1) Discovery
In most successful games, players uncover new elements as they progress; people want to find new depths at their own pace. This is easy to do online where you literally add to the host any time, as long as the architecture you have built allows it. Special scenarios can be organized by the company or by players themselves.

2) Amount of winners and losers
Games where I win and you lose are bad. Worse still is "I win and all the rest of you lose". Notwithstanding the current cultural obsession with endzone strutting by winners, losers do not enjoy themselves and if you can help take the sting out of it, you should. Alliances, cooperative play, ranked "winners" rather than "A winner" with a bunch of losers are all options.

3) Personalization
Let players define their own icons that the others see or somehow personalize their own game space. A big part of the enjoyment of being with others is expressing yourself. A bunch of player avatars all dressed from the same menu gives me the creeps. Encourage graffiti.

4) Facilitate relationships
Allow players to form clubs, clans, groups and facilitate scheduled as well impromptu meetings online. Help strangers mix and friends find each other.

5) Time limits
Whenever possible design your game so it can be played within a fixed time limit. This will allow people to schedule their involvement. A game you can play a couple of times in an evening would be a good design goal. If you can't end the game at specific times try to at least facilitate a graceful exit opportunity such that a player quits while they are having fun and not after they're so exhausted they'll never come back again.

6) Game balance
Try to keep the distance between the losers and the winners small enough that the outcome is in doubt as long as possible. You can adjust random events, attrition factors or whatever. They'll thank you for keeping the games interesting even though you should probably not tell them what you're doing.

7) Handicapping
Let players handicap themselves if they want. Some players are willing to play with one hand behind their back so let them. (The most common use of this will be parents and kids playing together).

8) Persistence
Players want to have a permanent effect on the world, and this illusion helps suspend disbelief. The difficulty is in making an environment consistent yet not cluttered by debris from previous play, and/or hostile to players entering for the first time.

 

Simple multiplayer game

tutor_9_multiplayer_v0.zip



float p1_arrowX;
float p1_arrowY;
float p1_arrowAngle;
float p1_arrowAcceleration;
float p1_arrowSpeedX;
float p1_arrowSpeedY;
 
boolean p1_upPressed,p1_downPressed,p1_leftPressed,p1_rightPressed;
 
float p2_arrowX;
float p2_arrowY;
float p2_arrowAngle;
float p2_arrowAcceleration;
float p2_arrowSpeedX;
float p2_arrowSpeedY;
 
boolean p2_upPressed,p2_downPressed,p2_leftPressed,p2_rightPressed;
 
void setup()
{
  size(800,600);
  smooth();
  frameRate(30);
  p1_arrowX = width*0.25;
  p1_arrowY = height/2;
  p1_arrowAcceleration = 0;
  p1_arrowAngle = -PI/2;
  p1_arrowSpeedX = 0;
  p1_arrowSpeedY = 0;
   
  p2_arrowX = width*0.75;
  p2_arrowY = height/2;
  p2_arrowAcceleration = 0;
  p2_arrowAngle = -PI/2;
  p2_arrowSpeedX = 0;
  p2_arrowSpeedY = 0;
}
 
void draw()
{
  background(0);
  p1_arrowAcceleration *= 0.99;
  p1_arrowSpeedX *=0.99;
  p1_arrowSpeedY *=0.99;
   
  p2_arrowAcceleration *= 0.99;
  p2_arrowSpeedX *=0.99;
  p2_arrowSpeedY *=0.99;
  if(p1_upPressed)
  {
    //p1_arrowAcceleration += (25 -arrowSpeed) * 0.1;
    p1_arrowAcceleration++;
    if(p1_arrowAcceleration >50)
 p1_arrowAcceleration = 50;
    p1_arrowSpeedX = p1_arrowSpeedX*0.99 + cos(p1_arrowAngle)*p1_arrowAcceleration*0.01;
    p1_arrowSpeedY = p1_arrowSpeedY*0.99 + sin(p1_arrowAngle)*p1_arrowAcceleration*0.01;
  }
  if(p1_downPressed)
  {
    //p1_arrowAcceleration += (-25 -arrowSpeed) * 0.1;
    p1_arrowAcceleration--;
    if(p1_arrowAcceleration <-50)
 p1_arrowAcceleration = -50;
    p1_arrowSpeedX = p1_arrowSpeedX*0.99 + cos(p1_arrowAngle)*p1_arrowAcceleration*0.01;
    p1_arrowSpeedY = p1_arrowSpeedY*0.99 + sin(p1_arrowAngle)*p1_arrowAcceleration*0.01;
  }
  if(p1_leftPressed)
  {
    p1_arrowAngle -= radians(5);
  }
  if(p1_rightPressed)
  {
    p1_arrowAngle += radians(5);
  }
 
  p1_arrowX += p1_arrowSpeedX;
  p1_arrowY += p1_arrowSpeedY;

   
  if(p1_arrowX<0)
    p1_arrowX += width;
  else if(p1_arrowX>=width)
    p1_arrowX -= width;
 
  if(p1_arrowY<0)
    p1_arrowY += height;
  else if(p1_arrowY>=height)
    p1_arrowY -= height;
   
     
  if(p2_upPressed)
  {
    //p1_arrowAcceleration += (25 -arrowSpeed) * 0.1;
    p2_arrowAcceleration++;
    if(p2_arrowAcceleration >50)
 p2_arrowAcceleration = 50;
    p2_arrowSpeedX = p2_arrowSpeedX*0.99 + cos(p2_arrowAngle)*p2_arrowAcceleration*0.01;
    p2_arrowSpeedY = p2_arrowSpeedY*0.99 + sin(p2_arrowAngle)*p2_arrowAcceleration*0.01;
  }
  if(p2_downPressed)
  {
    //p1_arrowAcceleration += (-25 -arrowSpeed) * 0.1;
    p2_arrowAcceleration--;
    if(p2_arrowAcceleration <-50)
 p2_arrowAcceleration = -50;
    p2_arrowSpeedX = p2_arrowSpeedX*0.99 + cos(p2_arrowAngle)*p2_arrowAcceleration*0.01;
    p2_arrowSpeedY = p2_arrowSpeedY*0.99 + sin(p2_arrowAngle)*p2_arrowAcceleration*0.01;
  }
  if(p2_leftPressed)
  {
    p2_arrowAngle -= radians(5);
  }
  if(p2_rightPressed)
  {
    p2_arrowAngle += radians(5);
  }
 
  p2_arrowX += p2_arrowSpeedX;
  p2_arrowY += p2_arrowSpeedY;
  if(p2_arrowX<0)
    p2_arrowX += width;
  else if(p2_arrowX>=width)
    p2_arrowX -= width;
     
  if(p2_arrowY<0)
    p2_arrowY += height;
  else if(p2_arrowY>=height)
    p2_arrowY -= height;
pushMatrix();
  translate(p1_arrowX,p1_arrowY);
  rotate(p1_arrowAngle);
  triangle(-10,-10,-10,10,15,0);
  popMatrix();
   
  pushMatrix();
  translate(p2_arrowX,p2_arrowY);
  rotate(p2_arrowAngle);
  triangle(-10,-10,-10,10,15,0);
  popMatrix();
 
}
 
 
void keyPressed()
{
  if(key == 'w')
  {
    p1_upPressed = true;
  }
  else if(key == 's')
  {
    p1_downPressed = true;  
  }
  else if(key == 'a')
  {
    p1_leftPressed = true;
  }
  else if(key == 'd')
  {
    p1_rightPressed = true;
  }
  else if(keyCode == UP)
  {
    p2_upPressed = true;
  }
  else if(keyCode == DOWN)
  {
    p2_downPressed = true;  
  }
  else if(keyCode == LEFT)
  {
    p2_leftPressed = true;
  }
  else if(keyCode == RIGHT)
  {
    p2_rightPressed = true;
  }
}
 
void keyReleased()
{
  if(key == 'w')
  {
    p1_upPressed = false;
  }
  else if(key == 's')
  {
    p1_downPressed = false;  
  }
  else if(key == 'a')
  {
    p1_leftPressed = false;
  }
  else if(key == 'd')
  {
    p1_rightPressed = false;
  }
  else if(keyCode == UP)
  {
    p2_upPressed = false;
  }
  else if(keyCode == DOWN)
  {
    p2_downPressed = false;  
  }
  else if(keyCode == LEFT)
  {
    p2_leftPressed = false;
  }
  else if(keyCode == RIGHT)
  {
    p2_rightPressed = false;
  }
}


tutor_9_network_v1_server.zip

tutor_9_network_v1_client.zip



import processing.net.*;
 
Server myServer;
PFont font;
String sendingString;
 
void setup()
{
  size(600, 400);
  background(0);
  myServer = new Server(this, 10002); // Starts a myServer on port 10002
  font = loadFont("ScalaSans-Caps-32.vlw");
  sendingString = "";
}
 
void draw()
{
  background(0);
  Client c = myServer.available();
  if(c != null)
  {
    println("Client said: "+c.readString());
  }
  textFont(font);
  text(sendingString,10,height/2);
}
 
void keyPressed()
{
  if(keyCode == ENTER)
  {
    println("Server said: "+sendingString);
    myServer.write(sendingString);
    sendingString = "";
  }
  else if(keyCode == BACKSPACE && sendingString.length()>0)
  {
    sendingString = sendingString.substring( 0,sendingString.length()-1);
  }
  else if(key != CODED)
  {
    sendingString += key;
  }
}



import processing.net.*;
 
Client c;
PFont font;
String sendingString;
 
void setup()
{
  size(600, 400);
  background(0);
  c = new Client(this, "127.0.0.1", 10002);
  font = loadFont("ScalaSans-Caps-32.vlw");
  sendingString = "";
}
 
void draw()
{
  background(0);
   
  if(c.available() >0)
  {
    println("Server said: "+c.readString());
  }
  textFont(font);
  text(sendingString,10,height/2);
}
 
void keyPressed()
{
  if(keyCode == ENTER)
  {
    println("Client said: "+sendingString);
    c.write(sendingString);
    sendingString = "";
  }
  else if(keyCode == BACKSPACE && sendingString.length()>0)
  {
    sendingString = sendingString.substring( 0,sendingString.length()-1);
  }
  else if(key != CODED)
  {
    sendingString += key;
  }
}

 

About port numbers

Port Number Description
1 TCPPort Service Multiplexer (TCPMUX)
5Remote Job Entry (RJE)
7ECHO
18Message Send Protocol (MSP)
20 FTP-- Data
21FTP -- Control
22 SSH Remote Login Protocol
23 Telnet
25 Simple Mail Transfer Protocol(SMTP)
29MSG ICP
37Time
42Host Name Server (Nameserv)
43WhoIs
49Login Host Protocol (Login)
53 Domain Name System(DNS)
69 Trivial File Transfer Protocol(TFTP)
70 Gopher Services
79 Finger
80 HTTP
103 X.400 Standard
108SNA Gateway Access Server
109POP2
110 POP3
115Simple File Transfer Protocol (SFTP)
118SQL Services
119 Newsgroup (NNTP)
137 NetBIOSName Service
139NetBIOS Datagram Service
143Interim Mail Access Protocol (IMAP)
150NetBIOS Session Service
156 SQL Server
161 SNMP
179 Border Gateway Protocol(BGP)
190Gateway Access Control Protocol (GACP)
194 Internet Relay Chat(IRC)
197Directory Location Service (DLS)
389 Lightweight Directory Access Protocol(LDAP)
396Novell Netware over IP
443 HTTPS
444Simple Network Paging Protocol (SNPP)
445Microsoft-DS
458 Apple QuickTime
546 DHCP Client
547DHCP Server
563SNEWS
569MSN
1080Socks

SharedCanvasServer.zip

SharedCanvasClient.zip



/**
* Shared Drawing Canvas (Server)
* by Alexander R. Galloway.
*
* A server that shares a drawing canvas between two computers.
* In order to open a socket connection, a server must select a
* port on which to listen for incoming clients and through which
* to communicate. Once the socket is established, a client may
* connect to the server and send or receive commands and data.
* Get this program running and then start the Shared Drawing
* Canvas (Client) program so see how they interact.
*/
 
 
import processing.net.*;
 
Server s;
Client c;
String input;
int data[];
 
void setup()  
{
  size(450, 255);
  background(204);
  stroke(0);
  smooth();
  frameRate(10); // Slow it down a little
  s = new Server(this, 10002); // Start a simple server on a port
}
 
void draw()  
{
  if (mousePressed == true) {
    // Draw our line
    stroke(255);
    line(pmouseX, pmouseY, mouseX, mouseY);
    // Send mouse coords to other person
    s.write(pmouseX + " " + pmouseY + " " + mouseX + " " + mouseY + "\n");
    print(pmouseX + " " + pmouseY + " " + mouseX + " " + mouseY + "\n");
  }
  // Receive data from client
  c = s.available();
  if (c != null) {
    input = c.readString();
    input = input.substring(0, input.indexOf("\n")); // Only up to the newline
    data = int(split(input, ' ')); // Split values into an array
    // Draw line using received coords
    stroke(0);
    line(data[0], data[1], data[2], data[3]);
  }
}



/**
* Shared Drawing Canvas (Client)
* by Alexander R. Galloway.
*
* The Processing Client class is instantiated by specifying a remote
* address and port number to which the socket connection should be made.
* Once the connection is made, the client may read (or write) data to the server.
* Before running this program, start the Shared Drawing Canvas (Server) program.
*/
 
 
import processing.net.*;
 
Client c;
String input;
int data[];
 
void setup()  
{
  size(450, 255);
  background(204);
  stroke(0);
  smooth();
  frameRate(10); // Slow it down a little
  // Connect to the server's IP address and port
  c = new Client(this, "127.0.0.1", 10002); // Replace with your server's IP and port
}
 
void draw()  
{
  if (mousePressed == true) {
    // Draw our line
    stroke(255);
    line(pmouseX, pmouseY, mouseX, mouseY);
    // Send mouse coords to other person
    c.write(pmouseX + " " + pmouseY + " " + mouseX + " " + mouseY + "\n");
    print(pmouseX + " " + pmouseY + " " + mouseX + " " + mouseY + "\n");
  }
  // Receive data from server
  if (c.available() > 0) {
    input = c.readString();
    input = input.substring(0, input.indexOf("\n")); // Only up to the newline
    data = int(split(input, ' ')); // Split values into an array
    // Draw line using received coords
    stroke(0);
    line(data[0], data[1], data[2], data[3]);
  }
}