demo/pong/game_server.c

See examples/demo/pong

/*
* ZentriOS SDK LICENSE AGREEMENT | Zentri.com, 2015.
*
* Use of source code and/or libraries contained in the ZentriOS SDK is
* subject to the Zentri Operating System SDK license agreement and
* applicable open source license agreements.
*
*/
#include "common.h"
/*************************************************************************************************/
void game_server_process_packet(const link_packet_t *packet)
{
const game_state_t current_state = game_context.state;
//DEBUG_APP("RX pckt: %d", packet->type);
switch(current_state)
{
case STATE_SYNCHRONIZING:
if(packet->type == TYPE_SYNC && game_context.substate == 1)
{
DEBUG_APP("Received sync packet");
reset_score();
start_game(NULL);
}
break;
case STATE_GAME_RUNNING:
if(packet->type == TYPE_PAD_POSITION)
{
game_context.client.position = packet->payload.pad_position.position;
update_game_event_handler(NULL);
}
break;
default:
break;
}
}
/*************************************************************************************************/
void game_server_disconnected(void)
{
zn_event_unregister(start_game, NULL);
zn_event_unregister(update_game_event_handler, NULL);
}
/*************************************************************************************************/
void game_server_update_pad_position(uint8_t position)
{
game_context.server.position = position;
update_game_event_handler(NULL);
}
/*************************************************************************************************/
static void start_game(void *arg)
{
DEBUG_APP("Starting game");
initialize_game_state();
game_update_state(STATE_GAME_RUNNING);
zn_event_issue(update_game_event_handler, NULL, 0);
}
/*************************************************************************************************/
static void update_game_event_handler(void *arg)
{
update_ball();
if(game_context.state == STATE_GAME_RUNNING)
{
link_packet_t packet =
{
.type = TYPE_UPDATE_GAME,
.payload.update_game.ball.x = game_context.ball.x,
.payload.update_game.ball.y = (PIXWH-1) - game_context.ball.y,
.payload.update_game.position.server = game_context.server.position,
.payload.update_game.position.client = game_context.client.position,
};
DEBUG_APP("Game state:");
DEBUG_APP(" ball: %u, %u", game_context.ball.x, game_context.ball.y);
DEBUG_APP(" pos: %u, %u", game_context.server.position, game_context.client.position);
link_send_packet(&packet);
display_update_display();
zn_event_register_timed(update_game_event_handler, NULL, game_context.update_interval, 0);
}
}
/*************************************************************************************************/
static void update_ball(void)
{
zos_bool_t reversed_direction = ZOS_FALSE;
const uint32_t now = zn_rtos_get_time();
if((now - game_context.update_timestamp) < game_context.update_interval)
{
return;
}
game_context.update_timestamp = now;
if(game_context.ball.moving_left)
{
--game_context.ball.x;
}
else
{
++game_context.ball.x;
}
if(game_context.ball.x == 0)
{
game_context.ball.moving_left = ZOS_FALSE;
}
else if (game_context.ball.x == (PIXWH-1))
{
game_context.ball.moving_left = ZOS_TRUE;
}
if(game_context.ball.moving_up)
{
--game_context.ball.y;
}
else
{
++game_context.ball.y;
}
#ifdef SERVER_DEBUG_ENABLED
game_context.client.position = MIN(game_context.ball.x, PIXWH-game_context.settings->pad_size);
#endif
if(game_context.ball.y == 1 &&
game_context.ball.x >= game_context.client.position && game_context.ball.x < game_context.client.position + game_context.settings->pad_size)
{
game_context.ball.moving_up = ZOS_FALSE;
reversed_direction = ZOS_TRUE;
}
else if(game_context.ball.y == (PIXWH-2) &&
game_context.ball.x >= game_context.server.position && game_context.ball.x < game_context.server.position + game_context.settings->pad_size)
{
game_context.ball.moving_up = ZOS_TRUE;
reversed_direction = ZOS_TRUE;
}
else if(game_context.ball.y == 0)
{
game_over(ZOS_FALSE);
}
else if (game_context.ball.y == (PIXWH-1))
{
game_over(ZOS_TRUE);
}
if(reversed_direction)
{
game_context.update_interval = MAX(game_context.settings->min_update_interval, (signed)(game_context.update_interval - (uint16_t)game_context.settings->speed_update));
DEBUG_APP("New update interval: %u", game_context.update_interval);
}
}
/*************************************************************************************************/
static void game_over(zos_bool_t client_won)
{
DEBUG_APP("Game over, client won: %u", client_won);
game_context.client_won = client_won;
if(client_won)
{
++game_context.client.score;
}
else
{
++game_context.server.score;
}
game_update_state(STATE_SHOWING_SCORE);
link_packet_t packet =
{
.type = TYPE_GAMEOVER,
.payload.gameover.server_score = game_context.server.score,
.payload.gameover.client_score = game_context.client.score,
.payload.gameover.client_won = client_won,
};
link_send_packet(&packet);
if(!(game_context.client.score >= game_context.settings->max_score ||
game_context.server.score >= game_context.settings->max_score))
{
zn_event_register_timed(start_game, NULL, 6000, 0);
}
}
/*************************************************************************************************/
static void initialize_game_state(void)
{
uint32_t rand;
zn_get_random_buffer(&rand, sizeof(uint32_t));
game_context.ball.moving_up = !game_context.client_won;
game_context.ball.moving_left = ((rand & 0x02) > 0);
game_context.ball.x = MIN(MAX((rand >> 2) & 0x7, 1), (PIXWH-2));
game_context.ball.y = game_context.ball.moving_up ? (PIXWH-2) : 1;
game_context.client.position = (PIXWH - game_context.settings->pad_size) / 2;
game_context.server.position = (PIXWH - game_context.settings->pad_size) / 2;
game_context.update_interval = game_context.settings->update_interval;
game_update_button_sensitivity();
}
/*************************************************************************************************/
static void reset_score(void)
{
game_context.server.score = 0;
game_context.client.score = 0;
}