Creating custom “player-objects”

For players you could create a custom post type, like so

function my_player_cpt() {
  $labels = array(
    'name'                  => _x( 'Players', 'Post type general name', 'textdomain' ),
    'singular_name'         => _x( 'Player', 'Post type singular name', 'textdomain' ),
  );  
  $args = array(
    'labels'             => $labels,
    'public'             => true,
    'taxonomies'         => array('game')
    'supports'           => array( 
      'title', // player name
      'thumbnail', // player image
      'excerpt' // player role
    ),
  );
  register_post_type( 'player', $args );
}
add_action('init', 'my_player_cpt');

The excerpt field could be used to save the player role. Other option could be a custom meta field.

And games could probably be custom taxonomy,

function my_game_taxonomy() {
  $args = array(
    'label'        => __( 'Game', 'textdomain' ),
    'public'       => true,
  );   
  register_taxonomy( 'game', 'player', $args );
}
add_action('init', 'my_game_taxonomy');

To have the post type and taxonomy theme independent you should put the above code into a custom plugin. That way the content stays visible in the WP admin even if you ever change your theme.

Then in your theme directory create a taxonomy-game.php template and add your roster page code to it. Simple loop example below.

<?php 
// taxonomy-game.php
get_header();

if (have_posts()) : ?>

    <?php while (have_posts()) : the_post(); ?>
    <article class="player">
        <?php the_post_thumbnail( 'thumbnail' ); ?>

      <h2><?php the_title(); ?></h2>

      <span><?php the_excerpt(); ?></span>
    </article>
    <?php endwhile; ?>

        <?php // Navigation ?>

    <?php else : ?>

        <?php // No Posts Found ?>

<?php 
endif; 

get_footer();
?>