
BANZAI!!!1one
Discussion and ranting about the development of a game as a final-year school project. Followed by discussion and ranting about other stuff now that school is over.
float4 outputColor = float4(0, 0, 0, 0);
for(int i = 0; i < GlobalLightCount; i++)
{
float LightFactor = dot( GlobalLights[i].Vector, input.WorldNormal );
float4 color = GlobalLights[i].Color * LightFactor;
outputColor += color;
}
outputColor.a = 1;
return saturate( outputColor ) * tex2D( DiffuseSampler, input.TextureCoord );
float3 lightVector = GlobalLights[7].Vector - input.WorldPosition;
float lightDist = length( GlobalLights[7].Vector - input.WorldPosition );
float3 directionToLight = lightVector / lightDist;
// falloff light intensity linearly between alpha*radius and radius
float baseIntensity = 1 - saturate( lightDist / GlobalLights[0].Radius );
float diffuseIntensity = saturate( dot( directionToLight, input.WorldNormal ) );
outputColor += GlobalLights[7].Color * baseIntensity * diffuseIntensity;
outputColor.a = 1;
return saturate( outputColor ) * tex2D( DiffuseSampler, input.TextureCoord );
There is a bit of hairyness here however. The client needs to know stuff like what graphics to use to display the game. If you remember my earlier entry on multiplayer, XNA allows a game session to have properties, in the form of integers, associated with it. By associating a particular play scenario with a number the client can find out what to load immidiately by checking the properties of the session he's joining.
The whole sequence of joining an active game goes like this
Wait... there's no state data sent yet. In fact, if nothing else were sent the player would see nothing except for some background scenery. The magic occurs in the object the server creates to track the data sent to the client.
Each client tracking object has a list of game entities which matter to the clients. The tracking object allows the server to know stuff like whether the client has been informed that the entity exists (or has ceased to exist) and if any state updates are pending. The server sends entity creation data first, updates second and entity destruction data last. The server can also check for certain combinations (e.g. neither creation nor destruction have been sent but both are pending) to save on bandwidth. In the case of the previous example the server would give up on sending either to the client since creation and destruction effectively cancel eachother out.
State updates are a little more complicated than creation and destruction of entities. These are managed by a class called StateItemCollection. StateItems are objects which describe stuff like an entity's position, movement, damage and so on. When some significant change occurs, say the player suddenly accelerates, the associated StateItem flags that interested players should be notified of the change. The client tracking object queries each entity's StateItemCollection for this flag. If any StateItem's flag is set then the server queues up an update for the client. Once the server has queued the update for all relavent players it clears the flag.
There are a couple advantages to using this flagging method. One is that I can allow the server to choose which players receive the state updates. This allows for the server to throttle itself if it's sending too much data, or to skip sending state data that isn't relavent to a particular player. Other advantages lie in the ability to compensate for lag and in merging updates by having later updates replace earlier updates if neither have been sent.
I'll leave you with this screenshot of one (poorly lit) player shooting grey bullets. Notice I have some (glitched) lighting working now :)