Movendo meu sprite no XNA usando classes

7

Ei, eu sou um novato nessa brincadeira de programação e isso é realmente me frustrando. Estou tentando mover uma cobra em todas as direções enquanto estiver usando aulas. Criei um vetor2 para velocidade e tentei criar um método que mova a cobra dentro da classe da cobra.

Agora estou confuso e não sei o que fazer a seguir.

Aprecio qualquer ajuda. Obrigado: D

Isto é o que eu fiz em termos do método ...

  public Vector2 direction()
        {
                Vector2 inputDirection = Vector2.Zero;

                if (Keyboard.GetState().IsKeyDown(Keys.Left)) inputDirection.X -= -1;
                if (Keyboard.GetState().IsKeyDown(Keys.Right)) inputDirection.X += 1;
                if (Keyboard.GetState().IsKeyDown(Keys.Up)) inputDirection.Y -= -1;
                if (Keyboard.GetState().IsKeyDown(Keys.Down)) inputDirection.Y += 1;

                return inputDirection * snakeSpeed;

        }

Aprecio qualquer ajuda. Obrigado: D

EDIT:
Bem, deixe-me esclarecer tudo. Estou fazendo um pequeno jogo básico para uma tarefa. O jogo é semelhante ao antigo jogo de cobra nos antigos telefones Nokia. Eu criei uma classe de cobra (mesmo que eu não tenha certeza se isso é necessário, porque eu só vou ter um sprite em movimento dentro do jogo). Depois de escrever o código acima (na classe snake), o jogo correu sem erros, mas não consegui mover a imagem :(

EDIT2: Muito obrigado pelas respostas de todos !!


fonte
Desculpas pela citação incorreta do meu código: /
Parece uma abordagem viável, mas não vejo uma pergunta real aqui. Você está perguntando como usar o resultado da função "direção" para realmente mover um objeto?
Acho que se você postar o código que realmente usa a saída desse método de direção, poderemos ajudar. Eu acho que o erro está em como você está atualizando a posição do sprite.
Michael Coleman
Fazer voto positivo e aceitar respostas é outra maneira, a maneira da GD de agradecer aos colegas desenvolvedores que o ajudaram a alcançar seu objetivo. =)
Será Marcouiller

Respostas:

2

Embora eu também seja um novato no desenvolvimento de jogos, minha aposta é que você esteja sempre reinicializando sua inputDirectionvariável Vector2.Zero.

Eu não sei muito sobre desenvolvimento de jogos, mas quanto à programação orientada a objetos, isso é outra coisa! Aqui está o que eu vim depois de ler o seu comentário sobre as aulas.

public class Snake {
    private Texture2D _snake; // Represents your snake's sprite.
    private Vector2 _snakePos; // Field that determines your snake's position.
    private Vector2 _snakeSpeed = new Vector2(10.0f, 10.0f); // Field that determines the number of pixels your snake will move at once while moving.

    public Snake(Vector2 initialPosition) {
        _snakePos = initialPosition;
    }

    public void MoveDown() {
        _snakePos.Y += _snakeSpeed.Y;
    }

    public void MoveLeft() {
        _snakePos.X -= _snakeSpeed.X;
    }

    public void MoveRight() {
        _snakePos.X += _snakeSpeed.Y;
    }

    public void MoveUp() {
        _snakePos.Y -= _snakeSpeed.Y;
    }
}

public class Game Game1 {
    private Snake _snake = new Snake();

    protected override void Update(GameTime gameTime) {
        Keys[] keys = Keyboard.GetState().GetPressedKeys();

        if (keys != null && keys.Length > 0)
            switch (keys[0]) {
                case Keys.Escape:
                    Exit();
                    break;
                case Keys.Down:
                    _snake.MoveDown();
                    break;
                case Keys.Left:
                    _snake.MoveLeft();
                    break;
                case Keys.Right:
                    _snake.MoveRight();
                    break;
                case Keys.Up:
                    _snake.MoveUp();
                    break;
                default:
                    break;
            }
    }
}

Espero que isso ajude, e estar na direção certa para uma solução viável! =)

Will Marcouiller
fonte
Esta parece ser uma maneira longa e cansativa de usar alguns botões ... mas o que eu sei, lol. Na verdade, eu não tenho nenhuma idéia do que estou fazendo em termos de classes :(.
2
De fato, esta é a sua Snakeclasse que deve estar ciente de sua velocidade e direção. Além disso, este é o jogo que está recebendo as entradas do usuário. Então, no meu entendimento, você tem que fazer o know cobra que direção ele deve ir ao lado, ou seja, eu acredito que você deve ter, dentro de sua Snakeclasse, quatro métodos: MoveDown(), MoveLeft(),MoveRight() e MoveUp(). É a cobra que sabe o que fazer para se mover de um jeito ou de outro e, como também conhece sua velocidade, deve se mover de acordo. Então, em sua Gameclasse, instancie sua cobra e insira as instruções através de seus métodos!
Will Marcouiller
11
Por favor, veja minha resposta editada, pois incluí uma Snakeclasse possível que expõe quatro Movemétodos. A cobra não precisa saber qual tecla foi pressionada; seu jogo deve obter as teclas. Então, é o seu jogo que diz à sua cobra para onde ir, dependendo das teclas que foram pressionadas pelo jogador. Em seguida, seu jogo informa sua _snakeinstância para etc. MoveLeft, MoveDowndependendo das teclas que você pressionou. Avise-me se isso ajudar! E sinta-se à vontade para comentar sobre coisas que você não trabalha mais, terei prazer em ajudar o máximo que puder.
Will Marcouiller
Muito obrigado, é exatamente isso que eu estava procurando em termos de resposta. Você se chamou de novato, mas mostrou o contrário :). Eu sou literalmente péssimo nesse jazz de codificação. Minha confusão é ao usar classes para tudo (o que provavelmente é essencial).
11
Imo, Head First C # é um livro interessante para obter uma boa cartilha orientada a objetos e, na verdade, produzir resultados visíveis o tempo todo.
Oskar Duveborn
2

Eu uso um código como esse para mover meus sprites, ele tende a funcionar muito bem para mim e também usa "GameTime" para garantir que o movimento seja consistente entre as taxas de quadros.

// Sprite Protecteds
Vector2 direction;
Vector2 position;
float speed;

// Sprite Code
void Update(GameTime time, KeyboardState kb)
{
    // reset to zero for no keys pressed
    direction = Vector2.Zero;

    if (Keyboard.GetState().IsKeyDown(Keys.Left)) direction.X = -1;
    if (Keyboard.GetState().IsKeyDown(Keys.Right)) direction.X = 1;
    if (Keyboard.GetState().IsKeyDown(Keys.Up)) direction.Y = -1;
    if (Keyboard.GetState().IsKeyDown(Keys.Down)) direction.Y = 1;

    position += direction * speed * time. Milliseconds;
}

// Game "Update" method (not sure of exact code here)
sprite.Update(gameTime, Keyboard.GetState());

Obviamente, convém fornecer mais parâmetros ao sprite durante o processo de atualização, para que você possa ter a velocidade ou outras coisas também.

Nate
fonte
3
Deve haver adesivos vermelhos gigantes em todo tutorial XNA para informar as pessoas sobre o uso do GameTime para modificar todos os eventos quadro a quadro que você deseja atualizar a uma taxa constante em tempo real para fornecer uma experiência consistente ao jogador, independentemente do hardware .
Bill
@ Bill: Meus sentimentos exatamente.
Michael Coleman
2

Esta questão precisa de mais lambdas.

Observe que isso é de um WIP, então há alguns recursos não utilizados e implícitos, mas não implementados. Onde você vê o () =>add yourinputDirection.X -= -1; . Sei que isso é para um Gamepad e você está usando um teclado, mas o princípio de agrupamento, ou pelo menos a noção do mapa de ação, ainda se aplica.

Provavelmente é um exagero, mas muita diversão!

Função de instalação que mapeia os controles:

public void SetController(MyGamePad controller)
{
    controller.ClearActions();

    controller.BindAction(Buttons.Start, ButtonGroup.FullyExclusive, () => sine.play());

    controller.BindAction(Buttons.A,
        ButtonGroup.FaceButtons, () => showText("A!"));
    controller.BindAction(Buttons.A | Buttons.B,
        ButtonGroup.FaceButtons, () => showText("A and B!"));
    controller.BindAction(Buttons.B,
        ButtonGroup.FaceButtons, () => showText("B"));
    controller.BindAction(Buttons.B | Buttons.Y,
        ButtonGroup.FaceButtons, () => showText("B and Y!"));
    controller.BindAction(Buttons.Y,
        ButtonGroup.FaceButtons, () => showText("Y!"));
    controller.BindAction(Buttons.Y | Buttons.X,
        ButtonGroup.FaceButtons, () => showText("Y and X!"));
    controller.BindAction(Buttons.X,
        ButtonGroup.FaceButtons, () => showText("X!"));
    controller.BindAction(Buttons.X | Buttons.A,
        ButtonGroup.FaceButtons, () => showText("X n A, I made a funny!"));
    controller.BindAction(0x0,
        ButtonGroup.FaceButtons, () => showText("Nothing on the face buttons."));

    controller.BindAction(0x0,
        ButtonGroup.ShoulderButtons, () => showText("No shoulder buttons"));
    controller.BindAction(Buttons.LeftShoulder,
        ButtonGroup.ShoulderButtons, () => showText("Left shoulder button!"));
    controller.BindAction(Buttons.RightShoulder,
        ButtonGroup.ShoulderButtons, () => showText("Right shoulder button!"));

    controller.BindAction(0x0,
        ButtonGroup.DirectionalPad, () => showText("Nothin' on the dpad!"));
    controller.BindAction(Buttons.DPadUp,
        ButtonGroup.DirectionalPad, () => showText("DPAD UP!"));
    controller.BindAction(Buttons.DPadDown,
        ButtonGroup.DirectionalPad, () => showText("DPAD DOWN!"));
}

O componente do jogo que faz o trabalho (instancia 1 por jogador):

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using System.Collections.Generic;

namespace MyGame
{
    [Flags]
    public enum ButtonGroup
    {
        NonExclusive            = 0x00,
        FaceButtons             = 0x01,
        DirectionalPad          = 0x02,
        ShoulderButtons         = 0x04,
        LeftSide                = 0x08,
        RightSide               = 0x10,
        FullyExclusive          = 0xFF,
    }

    class MyGamePad : GameComponent
    {
        private Buttons FaceButtons;
        private Buttons DirectionalButtons;
        private Buttons ShoulderButtons;
        private Buttons LeftSideButtons;
        private Buttons RightSideButtons;
        private Buttons AllButtons;

        private PlayerIndex playerIndex;
        private Dictionary<KeyValuePair<Buttons, ButtonGroup>, Action> actionMap = new Dictionary<KeyValuePair<Buttons, ButtonGroup>, Action>();

        public InstrumentPad(Game game, PlayerIndex playerIndex) : base(game)
        {
            this.playerIndex = playerIndex;
        }

        public void ClearActions()
        {
            actionMap.Clear();
        }

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            updateButtons();

            foreach (KeyValuePair<Buttons, ButtonGroup> pair in actionMap.Keys)
            {
                switch (pair.Value)
                {
                    case ButtonGroup.DirectionalPad:
                        if (DirectionalButtons == pair.Key)
                            actionMap[pair].Invoke();
                        break;
                    case ButtonGroup.FaceButtons:
                        if (FaceButtons == pair.Key)
                            actionMap[pair].Invoke();
                        break;
                    case ButtonGroup.ShoulderButtons:
                        if (ShoulderButtons == pair.Key)
                            actionMap[pair].Invoke();
                        break;
                    case ButtonGroup.LeftSide:
                        if (LeftSideButtons == pair.Key)
                            actionMap[pair].Invoke();
                        break;
                    case ButtonGroup.RightSide:
                        if (RightSideButtons == pair.Key)
                            actionMap[pair].Invoke();
                        break;
                    case ButtonGroup.FullyExclusive:
                        if (AllButtons == pair.Key)
                            actionMap[pair].Invoke();
                        break;
                    case ButtonGroup.NonExclusive:
                        if ((AllButtons & pair.Key) == pair.Key)
                            actionMap[pair].Invoke();
                        break;
                }
            }
        }

        public void BindAction(Buttons buttonCombo, ButtonGroup buttonGrouping, Action action)
        {
            KeyValuePair<Buttons, ButtonGroup> pair = new KeyValuePair<Buttons, ButtonGroup>(buttonCombo, buttonGrouping);
            if (!actionMap.ContainsKey(pair))
                actionMap.Add(pair, action);
            else
                actionMap[pair] = action;
        }

        private void updateButtons()
        {
            GamePadState padState = GamePad.GetState(playerIndex);
            LeftSideButtons = 0x0;
            RightSideButtons = 0x0;

            FaceButtons = 0x0;
            if (padState.Buttons.A == ButtonState.Pressed)
                FaceButtons |= Buttons.A;
            if (padState.Buttons.B == ButtonState.Pressed)
                FaceButtons |= Buttons.B;
            if (padState.Buttons.X == ButtonState.Pressed)
                FaceButtons |= Buttons.X;
            if (padState.Buttons.Y == ButtonState.Pressed)
                FaceButtons |= Buttons.Y;

            RightSideButtons |= FaceButtons;

            DirectionalButtons = 0x0;
            if (padState.DPad.Up == ButtonState.Pressed)
                DirectionalButtons |= Buttons.DPadUp;
            if (padState.DPad.Down == ButtonState.Pressed)
                DirectionalButtons |= Buttons.DPadDown;
            if (padState.DPad.Left == ButtonState.Pressed)
                DirectionalButtons |= Buttons.DPadLeft;
            if (padState.DPad.Right == ButtonState.Pressed)
                DirectionalButtons |= Buttons.DPadRight;

            LeftSideButtons |= DirectionalButtons;

            ShoulderButtons = 0x0;
            if (padState.Buttons.LeftShoulder == ButtonState.Pressed)
            {
                ShoulderButtons |= Buttons.LeftShoulder;
                LeftSideButtons |= Buttons.LeftShoulder;
            }
            if (padState.Buttons.RightShoulder == ButtonState.Pressed)
            {
                ShoulderButtons |= Buttons.RightShoulder;
                RightSideButtons |= Buttons.RightShoulder;
            }

            AllButtons = LeftSideButtons | RightSideButtons;

            if (padState.Buttons.Start == ButtonState.Pressed)
                AllButtons |= Buttons.Start;
            if (padState.Buttons.Back == ButtonState.Pressed)
                AllButtons |= Buttons.Back;
        }
    }
}
michael.bartnett
fonte
1

Agora estou confuso e não sei o que fazer a seguir.

Isso significa que seu código não está fazendo o que você pensa que deveria estar fazendo ou você tem algum recurso que precisa implementar que não sabe ou deseja conselhos sobre qual recurso implementar a seguir?

De qualquer jeito...

if (Keyboard.GetState().IsKeyDown(Keys.Left)) inputDirection.X -= -1;
if (Keyboard.GetState().IsKeyDown(Keys.Right)) inputDirection.X += 1;

Você não deseja subtrair um negativo para uma direção e adicionar um positivo na outra. Esses dois avaliam a mesma coisa.

Tetrad
fonte
Bem, deixe-me esclarecer tudo. Estou fazendo um pequeno jogo básico para uma tarefa. O jogo é semelhante ao antigo jogo de cobra nos antigos telefones Nokia. Eu criei uma classe de cobra (mesmo que eu não tenha certeza se isso é necessário, porque eu só vou ter um sprite em movimento dentro do jogo). Depois de escrever o código acima (na classe snake), o jogo correu sem erros, mas na verdade não consegui mover a imagem :(
11
@ Tom, você deve colocar o esclarecimento na própria pergunta.
Tétrada
1

Veja como estou fazendo isso em um dos meus jogos no Windows Phone. Lembre-se de que fiz algumas simplificações em nome do exemplo. No meu jogo, os inimigos seguem um conjunto de waypoints ao longo de um caminho.

No Updatemétodo dentro da minha Enemy.csclasse, eu avalio Enemy.Waypoints.Peek() - Enemy.Position(normalizado) para determinar em qual direção o inimigo deve estar se movendo.

this.Direction = this.Waypoints.Peek() - this.Position;
this.Direction.Normalize();

Depois, calculo a velocidade (direção + velocidade) para o quadro atual usando a direção.

this.Velocity = Vector2.Multiply(this.Direction, Settings.Speed * this.Speed);

Finalmente, ajusto a posição atual do inimigo.

// Adjust the position according to the velocity.
this.Position += this.Velocity;

Isso ajuda a entender a matemática envolvida, mas é assim que você pode mover um objeto.

Ed Altorfer
fonte