Este artigo foi traduzido por máquina.

Going locais

Jogos na chave de Zune

Mike Calligaro

Conteúdo

Homem, que C É duplo
Anatomia de um jogo
Sprites em Pixie poeira
De nomes de ativos e chaves de cores
Até Gotta mover jogar
Sprite em uma caixa
Bing Bang explosão
Avançadas de desenho
O REST É o backup para você

Meu filho, que é foi tocando Xbox desde que ele foi três, começou mostrando um interesse em programação — especificamente escrever jogos.Isso solicitado-me para baixar o XNA Game Studio e mergulhar em-me, você sabe, de modo que eu poderia ensiná-lo.Que você sempre desejo escrever Minhas própria jogos tinha nada para fazer com ele.Na verdade.

XNA Game Studio 3.0 adicionado a capacidade de gravar jogos para Zune, que significa que o Zune é agora uma plataforma de desenvolvimento móvel.Portanto, é bom, er, jogo para um artigo going locais.Se você já é um desenvolvedor XNA, pode ser examinar alguns conceitos que já entendeu.Mas, se você for como eu, um programador que defensores sobre mas relativamente novo no desenvolvimento de jogos, continue lendo.

Homem, que C É duplo

Para a maioria dos minha carreira de ano quinze na Microsoft, eu estive um desenvolvedor de sistemas e os drivers.Meu idioma de escolha e necessidade foi um bones de bare bastante C++.Raramente recebo usar tempos de execução como MFC e o Microsoft .NET Framework.Até recentemente, eu não foi possível tenha mesmo digitado STL exerceu muito menos dele.

Isso é meu trabalho de dia.Mas meu tempo desativado adoro jogar em torno com C#.Principalmente escrevo aplicativos pouco para meus dispositivos Windows Mobile e ocasionalmente para meu PC.C++ não tratar me incorretamente como muitos desenvolvedores nativos, mas ainda recebo um pouco giddy Quando escrevo em C#.Você pode obter muitas feita com poucas linhas de código.Eu blasfemar, C# é muito divertido que devem fazer uma substância controlled.

Em diversão categoria, XNA Game Studio é como C# em steroids.A equipe sobre lá fez um trabalho incrível facilitando o desenvolvimento de jogos.A estrutura é simples, a disco rígida coisas amplamente é tratada para você e que elas já lançadas uma tonelada de amostras destinados a ensinar a você os vários aspectos do desenvolvimento de jogos.

Iniciar em creators.xna.com.Dali você pode baixar o XNA Game Studio 3.0 livre.Se você já usa um dos incarnations vários do Visual Studio 2008, o XNA Game Studio será integrar com ele.Se você não tiver o Visual Studio 2008, não se preocupe.XNA Game Studio também funciona com o livre Visual C# Express Edition.(Em outras palavras, embora eu mencione o Visual Studio, você pode substituir Visual C# Express Edition se você estiver usando.)

O site creators.xna.com também está cheio de excelentes informações para ajudá-lo indo.Clique no link instrução na parte superior da página para localizar guias do Iniciante, exemplos e como fazer do.O "guia do Iniciante para jogos 2D" está especialmente boa, como a documentação que obtém instalada com o XNA Game Studio.Em alguns casos, a documentação de instalação tem informações que não esteja na Web.No visual studio, você pode acessar essa documentação, selecionando Ajuda | conteúdo e configurando o filtro para XNA Game Studio 3.0.

XNA Game Studio permite que você escrever um código de base e implantá-lo para Xbox, PC e Zune.Tudo o aqui funcionará em todas as plataformas de três.Os downloads gratuitos são tudo o que você precisa desenvolver para PC ou Zune, mas o desenvolvimento de Xbox requer um Premium que custa uma taxa anual.

Anatomia de um jogo

Depois que você tem XNA Game Studio 3.0 instalado, você pode criar um jogo de Hello World para Zune selecionando arquivo | New | Project.Em seguida, selecione Visual C# | XNA Game Studio 3.0 e clique em jogo Zune (3.0).Enquanto o programa que isso gera não diz realmente Hello World, ele procure a entrada, pintar o segundo plano azul e sair sob demanda.

Se você estiver esperando algo muito complicado, você está para uma surpresa agradável.Seus valores de infra-estrutura de jogo inteira a aproximadamente vinte linhas de código se espalhar mais seis funções.Aqui está uma descrição dessas funções.

O construtor é apenas um construtor de objeto de C# variedade padrão, o ambiente.Trate-o mesmo como faria com qualquer um.

Inicialização é chamada após a conclusão de seu construtor.Ele permite que você faça mais inicialização, especialmente para tarefas envolvendo o sistema de elementos gráficos.

LoadContent é chamado após a inicialização e é onde você carregar a imagens e sons.

UnloadContent é chamado ao sair do jogo e permite que você descarregar seu conteúdo.Mas, desde que o descarregamento da maioria das imagens e sons é tratado para você, você geralmente não precisa fazer nada aqui.

Atualização provavelmente é o local onde o desenvolvimento de jogos difere mais de desenvolvimento de aplicativo normal.Em vez de um loop de mensagem, jogos regularmente pesquisar suas entradas, calcular o que fazer com ele e desenhe o resultado desses cálculos.A maioria dos que ocorre na atualização, portanto, isso é onde a maior parte do seu código será live.

Desenhar é chamado após cada atualização e é onde você desenhar as imagens.

É isso.Mesmo que o programa seja muito curto, ele é iniciado, pinta a tela azul, lê a entrada e será encerrado quando você clicar no botão Voltar.O que é isso?Foi você acha que desenvolvimento de jogos pode ser difícil?Não com o XNA Game Studio.

Sprites em Pixie poeira

Que era fácil, mas não faz um plano de fundo azul que sai de um jogo atraente.Você precisa imagens reais se você tiver um jogo.Felizmente, a colocação de imagens na tela não difícil.

Em um minuto vou para mostrar o código, mas primeiro você precisa carregar uma imagem em seu projeto.No Visual Studio, você deve ter uma janela denominada Solution Explorer (se você não fizer isso, você pode encontrá-lo no menu Exibir).Clique com o botão no Solution Explorer, direito no conteúdo e selecione Add | Existing Item.Daqui é possível apontar-em qualquer arquivo de imagem .bmp, .jpg, .png, .TGA ou .DDS.

Vamos supor que você tiver uma imagem de uma pessoa chamado player.jpg e que você adicionou-lo para conteúdo.a Figura 1 mostra o código para exibir essa imagem na tela.

Figura 1 exibição de uma imagem

// Add these member variables
Texture2D texture;
Vector2 position;

// Add this line to the constructor
position = new Vector2(100, 100);

// Add this line to LoadContent()
texture = Content.Load<Texture2D>("player");

// And add these lines to Draw();
spriteBatch.Begin();
spriteBatch.Draw(texture, position, Color.White);
// (Draw the rest of your sprites)
spriteBatch.End();

Antes de eu explicar essas linhas, vamos falar jargão.XNA Game Studio iniciado como um sistema de desenvolvimento para o Xbox.Como tal, ele é todos baseia em gráficos 3D.Jogos 2D (e, como o Zune não tem um processador 3D, você precisará fazer jogos 2D) estão jogos 3D, na verdade, onde tudo é realmente fino.Portanto, você verá termos 3D sprinkled ao redor de seu código.Por exemplo, enquanto sprite é o termo normal de uma imagem em um jogo 2D, a textura de palavra proveniente jogos 3D.Como diz como XNA Game Studio está interessado, sprites são realmente finos retângulos 3D com texturas mapeados para eles.

A função Content.Load usa um nome de ativos, que por padrão é o nome de arquivo sem a extensão.Desde que eu carregado uma imagem denominada player.jpg, eu passado a seqüência de caracteres "Player" para Content.Load.Na função LoadContent, você verá que já há uma linha que aloca um SpriteBatch.Todos os desenho é feito com este SpriteBatch.Na função de desenho, você informar o SpriteBatch que você está prestes a começar, desenhar todos os sprites e, em seguida, informe-terminar.

A variável de membro de posição é uma estrutura de vetor que contém o x e o local de y onde você deseja que o sprite para serem desenhados.No exemplo, usei local de pixel (100, 100).A cor é uma tonalidade que é possível adicionar a seus sprites.Usar o em branco deixa a imagem inalterada.

Portanto, para obter uma imagem na tela, você apenas necessários para carregar a textura e informe o lote sprite desenhá-la.A primeira imagem basicamente tem quatro linhas de código, e cada um subseqüente tem mais de dois.

De nomes de ativos e chaves de cores

Felizmente, neste momento você está vendo sua imagem do jogador na tela e pensando que isso não é tão difícil.Mas talvez não estiver totalmente satisfeito.Se você não gostar que seu código precisa usar o nome de arquivo da imagem?E, mais importante, e se a imagem que você carregou for retangular, mas o player não é?Como você pode desenhar apenas o player e não o plano de fundo?

Para responder a ambas essas perguntas, você precisará examinar as propriedades da imagem que você carregou.Volte para o Solution Explorer e clique com o botão direito do mouse no arquivo (no meu exemplo, player.jpg).Selecione Propriedades.Um painel de propriedades será exibido abaixo do Solution Explorer, oferecendo uma grande quantidade de informações úteis.Examine primeiro nome do ativo.Esse é o nome que você passou para Content.Load.Se você quiser torná-lo de algo diferente do nome do arquivo, alterá-la aqui.

Agora expanda processador conteúdo clicando no pouco + para a esquerda do nome.A propriedade que você se preocupa com aqui é a cor de chave de cores.Qualquer pixel cuja a cor correspondente à chave cores serão transparente.Isso é como você capturar uma imagem retangular e extrair o plano de fundo.Portanto, para eliminar plano do sprite de fundo, alterar sua cor ou alterar a cor chave configuração para que eles correspondam à.A configuração padrão para valores de vermelho, verde, azul e alfa de 255, 0, 255, 255, que é magenta.

Até Gotta mover jogar

Certamente um sprite único em um plano de fundo azul não será a próxima coisa grande no jogo.No mínimo, você precisa que o usuário seja capaz de mover esse sprite alguma forma.E, para fazer isso, você precisa saber o que o usuário quer fazer.Se você tiver examinamos a função de atualização no seu programa, você provavelmente já terá uma idéia como fazer isso.O código padrão lê a entrada do e termina se a tecla voltar é pressionada.Infelizmente, tipo de monopolized a entrada não existe.Vamos alterar itens um pouco para permitir que você use a entrada bem.

Eis o que é atualmente exibido:

if (GamePad.GetState(PlayerIndex.One).Buttons.Back == 
    ButtonState.Pressed)
    this.Exit();

Sugiro alterá-lo para se parecer com isso:

GamePadState input = 
    GamePad.GetState(PlayerIndex.One);
if (input.Buttons.Back == ButtonState.Pressed)
    this.Exit();

Agora você pode usar a variável de entrada para examinar a entrada do usuário.Observe que a entrada é um GamePadState.Considere entrada do Zune como um gamepad com Xbox que está faltando alguns dos botões.a Figura 2 fornece a lista completa dos mapeamentos para os botões do Zune.

A Figura 2 Zune botão mapeamentos
Botão Mapeamento
Fazer backup GamePadState.Buttons.Back
Executar/pausar GamePadState.Buttons.B
Centro de DPad GamePadState.Buttons.A
DPad bordas GamePadState.DPad
Deslizar on the ZunePad GamePadState.Thumbsticks.Left
Clicar na ZunePad GamePadState.Buttons.LeftShoulder

Tudo bem, vamos tornar o player mover.O código na Figura 3 aborda tanto DPad ZunePad entrada, de modo que ele irá trabalhar em qualquer Zune.(O Zunes original não têm a funcionalidade de ZunePad.)

A Figura 3 suporte movimento

// add these lines to Update()
const int c_speedScalar = 100;
Vector2 speed = Vector2.Zero;

speed.X = input.ThumbSticks.Left.X * c_speedScalar;
speed.Y = input.ThumbSticks.Left.Y * c_speedScalar * -1;

if (input.DPad.Left == ButtonState.Pressed)
    speed.X -= c_speedScalar;
else if (input.DPad.Right == ButtonState.Pressed)
    speed.Y += c_speedScalar;

if (input.DPad.Up == ButtonState.Pressed)
    speed.Y -= c_speedScalar;
else if (input.DPad.Down == ButtonState.Pressed)
    speed.Y += c_speedScalar;

position += speed * (float)gameTime.ElapsedGameTime.TotalSeconds;

Lembre-se de que a rotina de desenho é desenho o player no local especificado pela variável de membro de posição. Portanto, para mover o sprite, tudo o que você precisa fazer é atualizar esse local.

A parte realmente sofisticada aqui é a última linha em que você alterar a posição. O Xbox possui recursos gráficos mais fortes que o Zune, portanto, sua rotina de atualização é chamada com mais freqüência. Em outras palavras, ele tem um framerate superior. Isso significa que você precisa fazer a movimentação ser independente da framerate. Para fazer isso, use a entrada para calcular uma velocidade, não uma posição. Converta a velocidade em uma posição multiplicando pelo período de tempo decorrido desde a última chamada para atualização.

Sprite em uma caixa

Qualquer pessoa pode mover. O truque é saber quando parar.

Se o jogo for a ser interessantes, em seguida, você precisará saber quando um sprite coincide com outro. Termo do desenvolvedor de jogo sofisticada para que isso é a detecção de colisão e a maneira mais simples para fazer a detecção de colisão no XNA Game Studio é usar um objeto chamado um BoundingBox. Basicamente, você quebra caixas invisíveis ao redor dos objetos e, em seguida, verificar se qualquer uma dessas caixas interseção entre si.

Além do jogo atual sendo menor interessantes, o maior problema é que o sprite pode mover fora da tela. Vamos corrigir isso. Sempre que o sprite acerta uma borda, verifique ele voltar para o local (100, 100).

Primeiro, você terá uma caixa delimitadora para a tela:

// Add this member variable
BoundingBox bbScreen;

// Add these lines to Initialize() 
Vector3 min = new Vector3(0, 0, 0);
Vector3 max = new Vector3(graphics.GraphicsDevice.Viewport.Width,
    graphics.GraphicsDevice.Viewport.Height, 0);
bbScreen = new BoundingBox(min, max);

Há um pouco de mágica aqui, mas não é muito complicada mágica. A estrutura de Hello World lhe oferece uma variável de membro chamada elementos gráficos que contém a largura e altura da tela do jogo. Você pode definir o canto superior esquerdo da caixa delimitadora para o canto superior esquerdo da tela e o canto inferior direito da caixa delimitadora para o canto inferior direito da tela. BoundingBoxes requerem vetores 3D, portanto, defina as coordenadas de z como 0.

Agora vamos criar uma caixa para o sprite, assim:

// Add these lines to Update() after 
// the position has been calculated.
Vector3 min = 
    new Vector3((int)position.X, (int)position.Y, 0);
Vector3 max = 
    new Vector3((int)position.X + texture.Width - 1,
    (int)position.Y + texture.Height - 1, 0);
BoundingBox bb = new BoundingBox(min, max);

Finalmente, vamos ver se o sprite totalmente está contido em tela. Caso contrário, ele deve ter atingido uma borda. Adicione essas linhas diretamente abaixo aqueles adicionados anteriormente:

ContainmentType ct = bbScreen.Contains(bb);
if (ct != ContainmentType.Contains)
    position = new Vector2(100, 100);

Agora o sprite irá pular novamente para (100, 100) sempre que ele atinge a borda da tela. Você, claro, provavelmente faça algo mais inteligente, como interromper ou empene para o outro lado.

Colidindo com a borda da tela é um pouco diferente da colidindo com outro objeto. A situação normal é que você está dentro de tela, mas você está fora de outros objetos. Portanto, para verificar se há um conflito com a borda da tela, você deseja ver se caixa a tela contém você. Mas se você quiser verificar se há um conflito com outro objeto, você deseja ver se a caixa desse objeto cruza com você. Para esse fim, o objeto de BoundingBox tem uma função de membro Intersects. Interceptar retorna um Booleano que é true quando as duas caixas de interseção. Use Intersects se você quiser verificar se dois sprites visitas uns aos outros.

Bing Bang explosão

Agora você está uma tecnologia fora de gravar seus próprios jogos. Você pode desenhar imagens, mova-os em resposta a entrada do usuário e agir sobre eles em execução para uns aos outros. Como este é um jogo, provavelmente você precisa de uma colisão sprite para terminar em um detalhamento enorme. Você já sabe como desenhar o detalhamento, mas não ser satisfatória, na verdade, a menos que você rattle muito alto-falantes do player. Felizmente, a reprodução de sons é ainda mais fácil de desenho de sprites.

Primeiro, você precisará adicionar um som a seu projeto. O processo aqui é semelhante a adicionar uma imagem. Vá para o Solution Explorer, clique com o botão direito do mouse no conteúdo e escolha Add | Existing Item. Dali você pode escolher um arquivo .wav, .wma,. mp3 ou .xap. Além disso, como o arquivo de imagem, se você desejar um nome de ativos diferentes que o nome do arquivo, você pode alterá-lo nas propriedades.

Agora vamos executar esse som. Esse código pressupõe que o arquivo que você carregou estava explode.wav:

// Add this member variable
SoundEffect sndBoom;

// Add these lines to LoadContent()
ContentManager contentManager = 
    new ContentManager(Services, "Content");
sndBoom = 
    contentManager.Load<SoundEffect>("explode");

// Add these lines to Update()
if (input.Buttons.B == ButtonState.Pressed)
    sndBoom.Play();

A chamada contentManager.Load é semelhante à função usada ao carregar textura do seu sprite. Em seguida, como você ver, quando você deseja ouvir o som, você simplesmente executá-lo. Observe que, como escrito, esse código irá tentar reproduzir um som novo cada quadro enquanto o botão de B é pressionado. Dependendo o comprimento do som, isso pode resultar em muitas cópias dele execução e o jogo emitir uma exceção. Você deve se protege contra que executando apenas uma vez por pressionamento de botão. A maneira clássica para fazer isso é armazenar o estado da entrada anterior e funcionar apenas quando o estado alterado.

Avançadas de desenho

Você já tem as ferramentas básicas que necessárias para criar seus próprios jogos. Sugiro que você levar algum tempo para jogar com essas ferramentas e obter confortável-los. Quando você estiver pronto para obter mais informações, você pode ler esta seção para obter uma breve introdução aos idéias avançadas. Os documentos de ajuda para essas funções dará a você tudo o que você precisa saber para usá-los.

Primeiro, vamos falar sobre a ordem Z. Como o código no momento significa, se dois sprites estiverem sobrepostas, aquele que é desenhada última terminarão na parte superior. Esse é o tipo de uma dificuldade. Um método muito melhor é dar a cada sprite uma variável que indica a ordem em que ele deveria ser desenhado. Para fazer isso, você precisará usar versões mais complicadas do spriteBatch.Begin e spriteBatch.Draw, assim:

spriteBatch.Begin(
    SpriteBlendMode.AlphaBlend, 
    SpriteSortMode.BackToFront, 
    SaveStateMode.None);
spriteBatch.Draw(texture, position, 
    null, Color.White, 0, Vector2.Zero, 
    1.0F, SpriteEffects.None, zOrder);

Dedique algum tempo com a documentação do SpriteBatch e testar. Essas funções são um pouco complicadas, mas eles também são muito poderosos. Por exemplo, se você desejar alterar os tamanhos dos seus sprites, você pode usar um retângulo em vez de um vetor para a posição. Se os limites de retângulo forem diferentes de tamanho a textura, XNA Game Studio serão redimensionados-lo para você automaticamente. Se sua textura tiver várias imagens que você deseja circular entre, você pode passar em um retângulo de origem que especifica qual parte a textura para desenhar.

Se você desejar um sprite translúcido, altere o valor alfa da cor que você passar para desenhar:

Color trans = new Color(
    Color.White.R, Color.White.G, 
    Color.White.B, 128);

Trans de passagem para desenhar em vez de Color.White e o sprite seria metade translúcida.

Finalmente, eis alguns bons código que você pode usar para girar a tela de retrato para modo paisagem:

// Add this member variable
Matrix matTransform;

// Add these lines to the constructor
matTransform = Matrix.Identity;
matTransform *= 
    Matrix.CreateRotationZ(MathHelper.ToRadians(90));
matTransform *= 
    Matrix.CreateTranslation(240, 0, 0);

// In Draw() change spriteBatch.Begin to this
spriteBatch.Begin(SpriteBlendMode.AlphaBlend, 
    SpriteSortMode.BackToFront, SaveStateMode.None, 
    matTransform);

O REST É o backup para você

O código completo para o meu exemplo é mostrado na Figura 4 e ele deve obtenha você mover. Se você executar aground, o site creators.xna.com está repleto de exemplos que mostram a você como fazer todos os tipos de coisas de desenvolvimento de jogos hermética, por pixel delimitadora caixas para modelos de física.

A Figura 4 A simples Zune jogo

public class Game1 : Microsoft.Xna.Framework.Game {
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    Matrix matTransform;
    Texture2D texture;
    SoundEffect sndBoom;
    BoundingBox bbScreen;
    Vector2 position;

    public Game1() {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
        position = new Vector2(100, 100);
        matTransform = Matrix.Identity;
        // Uncomment these lines to do Landscape Mode
        //matTransform *= Matrix.CreateRotationZ(          MathHelper. ToRadians(90));
        //matTransform *= Matrix.CreateTranslation(240, 0, 0);
    }

    protected override void Initialize() {
        Vector3 min = new Vector3(0, 0, 0);
        Vector3 max = 
            new Vector3(
            graphics.GraphicsDevice.Viewport.Width, 
            graphics.GraphicsDevice.Viewport.Height, 0);
        bbScreen = new BoundingBox(min, max);
        base.Initialize();
    }

    protected override void LoadContent() {
        spriteBatch = new SpriteBatch(GraphicsDevice);
        texture = Content.Load<Texture2D>("player");
        ContentManager contentManager = 
            new ContentManager(Services, @"Content\Audio");
        sndBoom = contentManager.Load<SoundEffect>("explode");
    }

    protected override void UnloadContent() {
    }

    protected override void Update(GameTime gameTime) {
        GamePadState input = GamePad.GetState(PlayerIndex.One);
        if (input.Buttons.Back == ButtonState.Pressed)
            this.Exit();

        if (input.Buttons.B == ButtonState.Pressed)
            sndBoom.Play();

        const int c_speedScalar = 100;
        Vector2 speed = Vector2.Zero;

        speed.X = input.ThumbSticks.Left.X * c_speedScalar;
        speed.Y = input.ThumbSticks.Left.Y * c_speedScalar * -1;

        if (input.DPad.Left == ButtonState.Pressed)
            speed.X -= c_speedScalar;
        else if (input.DPad.Right == ButtonState.Pressed)
            speed.X += c_speedScalar;

        if (input.DPad.Up == ButtonState.Pressed)
            speed.Y -= c_speedScalar;
        else if (input.DPad.Down == ButtonState.Pressed)
            speed.Y += c_speedScalar;

        position += speed * (float)gameTime.ElapsedGameTime.TotalSeconds;

        Vector3 min = new Vector3((int)position.X, (int)position.Y, 0);
        Vector3 max = new Vector3((int)position.X + 
            texture.Width - 1, (int)position.Y + texture.Height - 1, 0);
        BoundingBox bb = new BoundingBox(min, max);

        ContainmentType ct = bbScreen.Contains(bb);
        if (ct != ContainmentType.Contains)
            position = new Vector2(100, 100);

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime) {
        GraphicsDevice.Clear(Color.CornflowerBlue);
        spriteBatch.Begin(SpriteBlendMode.AlphaBlend, 
            SpriteSortMode.BackToFront, SaveStateMode.None, matTransform);
        spriteBatch.Draw(texture, position, null, Color.White, 
            0, Vector2.Zero, 1.0F, SpriteEffects.None, 0.5F);
        spriteBatch.End();

        base.Draw(gameTime);
    }
}

Espero que você encontrar o desenvolvimento de jogos XNA em C# para ser quanto como eu. Talvez algo que você escrever tornará a próxima coisa grande em jogos... Se o meu filho não se a ela. Feliz de codificação.

Envie suas dúvidas e comentários paragoplaces@Microsoft.com.

Mike Calligaro é um chefe de desenvolvimento sênior com a equipe de Windows Mobile da Microsoft e um colaborador o blog da equipe Windows Mobile, que você pode ver na blogs.msdn.com/WindowsMobile.