Ask and ye shall receive. Here is some code I typed up when I learned basic multiplayer concepts in 2 weeks. That's all it takes, and your well on your way.
Include Script:
Code:
//--------------------------------------------------------------------
// Globals
//--------------------------------------------------------------------
//Skills
define server_angle, skill20;
//define server_angle2, skill21;
//define server_angle3, skill22;
define server_origin, skill23;
//define server_origin2, skill24;
//define server_origin3, skill25;
//Pointers
entity* player; // pointer to player entity
//Variables
var people_connected = 0; // number of people connected to server
var number_of_players = 0; // # of players in game
var latency; //latency
var bps; //Bytes per a second
//Strings
string mdl_guard = <guard.mdl>; //pointer to guard model
string str_people_connected; // number of people connected to server
string str_latency; // number of people connected to server
string str_temp; // temp string
string str_bytes; // temp string
string aemo = " "; //testing string
//Text/Fonts
font arial_font = "arial",1,12;
text astuff
{
layer = 25;
pos_x = 0;
pos_y = 140;
string = aemo;
font = arial_font;
flags = visible;
}
text txt_people_connected
{
pos_x = 0; pos_y = 55; layer = 15;
font arial_font; string str_people_connected;
}
text txt_latency
{
pos_x = 0; pos_y = 35; layer = 15;
font arial_font; string str_latency;
}
text txt_bytes
{
pos_x = 0; pos_y = 15; layer = 15;
font arial_font; string str_bytes;
}
//Panels/Bmaps
//--------------------------------------------------------------------
// HUD Functions
//--------------------------------------------------------------------
function display_info()
{
while(1)
{
latency = dplay_latency;
bps = dplay_bps;
str_cpy(str_people_connected, "People Connected: ");
str_for_num(str_temp, people_connected);
str_cat(str_people_connected, str_temp);
str_cpy(str_latency, "Latency: ");
str_for_num(str_temp, latency);
str_cat(str_latency, str_temp);
str_cpy(str_bytes, "BPS: ");
str_for_num(str_temp, bps);
str_cat(str_bytes, str_temp);
wait(1);
}
}
//--------------------------------------------------------------------
// Server functions
//--------------------------------------------------------------------
function check_server_disconnect()
{
while(1)
{
//server disconnected so quit client too
if(dplay_latency == 0 && dplay_bps == 0 && connection == 2)
{
exit;
}
wait(1);
}
}
function server_called()
{
//if new player connected
if((event_type == event_join) && (people_connected < 8))
{
sleep(0.5);
ifdef server;
people_connected += 1; //another person connected
send_var(people_connected); //send number of people connected
endif; //ifdef server
}
//if player disconnected
if(event_type == event_leave)
{
sleep(0.5);
ifdef server;
people_connected -= 1; // one less person connected to server
send_var(people_connected); // send number of people connected
endif;
}
}
on_server = server_called; // server called
//--------------------------------------------------------------------
// Movement functions
//--------------------------------------------------------------------
define run_force,skill5; // in these lines you define skill5 - skill6 with names. you need this because the engine could not use it without names in MP.
define turn_force,skill6;
define force_x,skill1;
define force_y,skill2;
define speed,skill3;
define movement_mode,skill4;
define mode_walking,1;
function client_movement()
{
var old_pan; var old_position; var dist[3]; var target_trace[3];
var old_runforce; var old_turnforce;
var cs_origin[3]; var cs_angle[3];
var reset_move;
while(1)
{
if(my)
{
if(key_w==1){my.run_force=1; }
if(key_s==1){my.run_force=-1;}
if((key_w==0)&&(key_s==0)){my.run_force=0;}
if(key_a==1){my.turn_force=1;}
if(key_d==1){my.turn_force=-1;}
if((key_a==0)&&(key_d==0)){my.turn_force=0;}
vec_set(target_trace,my.x);
target_trace.z -= 5000;
dist.z = -c_trace(my.x,target_trace, ignore_me + ignore_sprites + ignore_passable);
dist.x = my.run_force * 14 * time;
dist.y = 0;
//dist.z = 0;
vec_set(my.pan, old_pan); vec_set(my.x, old_position);
c_move(my,dist.x,nullvector, glide + ignore_passable);
my.pan += my.turn_force * 10 * time;
if(old_runforce != my.run_force){send_skill(my.run_force, 0);}
if(old_turnforce != my.turn_force){send_skill(my.turn_force, 0);}
old_runforce = my.run_force; old_turnforce = my.turn_force;
vec_set(old_pan, my.pan); vec_set(old_position, my.x);
if(reset_move < 35)
{
reset_move += 1;
vec_set(cs_origin.x, my.server_origin); vec_set(cs_angle.pan, my.server_angle);
vec_set(my.x, cs_origin.x); vec_set(my.pan, cs_angle.pan);
}
}
wait(1);
}
}
function server_movement()
{
var old_turn; var old_forward; var dist[3]; var target_trace[3];
while (1)
{
if(my)
{
if(key_w==1){my.run_force=1; }
if(key_s==1){my.run_force=-1;}
if((key_w==0)&&(key_s==0)){my.run_force=0;}
if(key_a==1){my.turn_force=1;}
if(key_d==1){my.turn_force=-1;}
if((key_a==0)&&(key_d==0)){my.turn_force=0;}
vec_set(target_trace,my.x);
target_trace.z -= 5000;
dist.z = -c_trace(my.x,target_trace, ignore_me + ignore_sprites + ignore_passable);
dist.x = my.run_force * 14 * time;
dist.y = 0;
//dist.z = 0;
c_move(my,dist.x,nullvector, glide + ignore_passable);
my.pan += my.turn_force * 10 * time;
}
wait(1);
}
}
function movement_smooth()
{
var rotate[3]; var s_angle[3]; var old_angle[3]; var new_angle[3]; var angle_direct; var oangle_direct; var pan_factor;
var calc_angle[3]; var move[3]; var move_old[3]; var xdirect; var move_factor;
while(1)
{
if(my != player)
{
vec_set(s_angle.pan, my.server_angle);
rotate.pan = ang(s_angle.pan - my.pan); my.pan += rotate.pan * 0.2 * time;
rotate.tilt = ang(s_angle.tilt - my.tilt); my.tilt += rotate.tilt * 0.2 * time;
rotate.roll = ang(s_angle.roll - my.roll); my.roll += rotate.roll * 0.2 * time;
oangle_direct = angle_direct;
if(old_angle.pan > s_angle.pan){angle_direct = 1;}
if(old_angle.pan < s_angle.pan){angle_direct = -1;}
if(angle_direct != oangle_direct){my.pan = s_angle.pan;}
pan_factor = dplay_entrate; if(dplay_entrate < 5){pan_factor /= 4.5;} if(dplay_entrate > 4){pan_factor /= 9;}
if(rotate.pan > 0.2) || (rotate.pan < -0.2){
if(angle_direct == 1){my.pan -= 16 * pan_factor * time;}
if(angle_direct != 1){my.pan += 16 * pan_factor * time;}
}
//str_for_num(aemo, pan_factor);
vec_set(old_angle.pan, my.server_angle);
vec_set(move.x, my.server_origin);
vec_set(temp.x, move.x); vec_sub(temp.x, my.x);
my.x += temp.x * 0.4 * time;
my.y += temp.y * 0.4 * time;
my.z += temp.z * 0.4 * time;
move_factor = dplay_entrate; if(dplay_entrate < 5){move_factor /= 2;} if(dplay_entrate > 4){move_factor /= 5;}
vec_set(move.x, my.server_origin); vec_sub(move.x, my.x); vec_to_angle(calc_angle.pan, move.x);
temp.x = 7*move_factor*time; temp.y = 0; temp.z = 0; vec_rotate(temp.x, calc_angle.pan); vec_add(my.x, temp.x);
//str_for_num(aemo, temp.x);
vec_set(move_old.pan, my.server_origin);
}
wait(1);
}
}
// -sv
// -cl
function player_events()
{
//client disconnected
if(EVENT_TYPE == EVENT_DISCONNECT){ent_remove(me);}
}
function local_functions()
{
if(my.client == 1)
{
movement_smooth();
wait(1);
}
if(my.client != 1)
{
movement_smooth();
wait(1);
}
}
function cs_move()
{
var old_pan; var old_position; var dist[3]; var target_trace[3];
while(1)
{
if(my)
{
vec_set(target_trace,my.x);
target_trace.z -= 5000;
dist.z = -c_trace(my.x,target_trace, ignore_me + ignore_sprites + ignore_passable);
dist.x = my.run_force * 14 * time;
dist.y = 0;
//dist.z = 0;
c_move(my,dist.x,nullvector, glide + ignore_passable);
my.pan += my.turn_force * 10 * time;
}
wait(1);
}
}
action player_move
{
my.enable_disconnect = on; // player can disconnect from session
my.event = player_events; // player events function
var power_x;
var power_y;
var dist[3];
var target_trace[3];
var anim;
var anim_dir;
my.speed = 3;
if(!player){wait(10);} wait(20); ent_sendnow(me); wait(20);
if(my.client == 1)
{
proc_client(my, client_movement);
proc_local(my,local_functions);
cs_move();
my.nosend_frame = on; my.nosend_alpha = on; my.nosend_ambient = on; my.nosend_color = on; my.nosend_light = on; my.nosend_uv = on;
my.nosend_origin = on; my.nosend_angles = on; my.nosend_flags = on; my.nosend_scale = on; my.nosend_skin = on; my.nosend_sound = on;
}
if(my.client != 1)
{
proc_local(my,local_functions);
server_movement();
my.nosend_frame = on; my.nosend_alpha = on; my.nosend_ambient = on; my.nosend_color = on; my.nosend_light = on; my.nosend_uv = on;
my.nosend_origin = on; my.nosend_angles = on; my.nosend_flags = on; my.nosend_scale = on; my.nosend_skin = on; my.nosend_sound = on;
}
while(1)
{
vec_set(my.server_angle, my.pan);
vec_set(my.server_origin, my.x);
send_skill(my.server_origin, send_all + send_vec + send_rate);
send_skill(my.server_angle, send_all + send_vec + send_rate);
wait(1);
}
}
/*
//if(move.x != move_old.x)||(move.y != move_old.y)||(move.z != move_old.z){
if(temp.x > 0)&&(xdirect != 1){vec_set(my.x, my.server_origin); xdirect = 1;} if(temp.x < 0)&&(xdirect != -1){vec_set(my.x, my.server_origin); xdirect = -1;}
if(xdirect == 1)
{
temp.x = 6*time; temp.y = 0; temp.z = 0; vec_rotate(temp.x, calc_angle.pan); vec_add(my.x, temp.x);
}
if(xdirect == -1)
{
temp.x = 6*move_factor*time; temp.y = 0; temp.z = 0; vec_rotate(temp.x, calc_angle.pan); vec_add(my.x, temp.x);
}*/
//--------------------------------------------------------------------
// Creation Functions
//--------------------------------------------------------------------
function create_player() //remember that the server is also a client, but if u dont use -sv or -cl it wont create
{
ifdef server;
while(connection== 0) {wait(1);} // wait until level loaded and connection set
endif;
ifdef client;
while(connection== 0) {wait(1);} // wait until level loaded and connection set
endif;
if(connection == 3)
{
people_connected = 1;
}
//if dedicated server skip these
if(connection != 1)
{
display_info();
//if not single player mode, display multiplayer information
if(connection)
{
txt_bytes.visible = on;
txt_latency.visible = on;
txt_people_connected.visible = on;
}
}
vec_set(temp.x, nullvector);
temp.x += random(200); temp.x -= random(200);
temp.y += random(200); temp.y -= random(200);
temp.z = -20;
player = ent_create(mdl_guard, temp.x, player_move);
check_server_disconnect();
wait(1);
}
Main Script
Code:
//---------------------------------------------------------------
//Multiplayer Test
//---------------------------------------------------------------
var video_mode = 4; //800*600 =7
var video_depth = 16; //32 bit
var video_screen=2; //fullscreen
var d3d_mipmapping = 2;
var d3d_triplebuffer = 1;
var d3d_alphadepth = 32;
var d3d_transform = on;
var d3d_lightres=off;
var max_particles=1400;
var sky_curve =0.5;
var clip_particles = 0.2;
include <networkmove.wdl>;
string level_str = <multi_test.wmb>;
//---------------------------------------------------------------
// The main() function
//---------------------------------------------------------------
function main()
{
bg_color.red = 0; bg_color.green = 0; bg_color.blue = 0;
level_load(level_str);
sleep(0.5);
dplay_smooth = 0;
dplay_entrate = 1;
create_player(); //this creates the player entity
}
Build a hollow cube. Place a static camera pointing at its origin. Script will create your model and you can move it. Before running "-cl -sv" on one comp, on other, "-cl". This is a client-side movement set-up, with basic smoothing on the clients of other ents.
This is mostly barebones stuff. It's not for advanced math people/great programmers - anyone can do it. I'm an artist foremost, but most anything can be learned given the time and effort. Click-together multiplayer will never be possible if you want to support 2 different genres of games. Infact, I now learned that a racing game uses a much different set-up than that fps multiplayer code above. Especially when it comes down to prediction. Since 3DGS is open-ended it wouldn't be wise to spend alot of time developing a click together multiplayer for only one genre. Afterall, given the amount of users here you can be very sure not everyones aiming at a particular genre.
