Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I want to program a dolphin that jumps and rotates like a real dolphin. Jumping is not the problem, but I don't know how to make the rotation. At the moment, my dolphin rotates a little weird. But I want that it rotates like a real dolphin does.

How can I improve the rotation?

public class Game1 : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    Texture2D image, water;
    float Gravity = 5.0F;
    float Acceleration = 20.0F;
    Vector2 Position = new Vector2(1200,720);
    Vector2 Velocity;
    float rotation = 0;
    SpriteEffects flip;
    Vector2 Speed = new Vector2(0, 0);

    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
        graphics.PreferredBackBufferWidth = 1280;
        graphics.PreferredBackBufferHeight = 720;
    }

    protected override void Initialize()
    {
        base.Initialize();
    }

    protected override void LoadContent()
    {   
        spriteBatch = new SpriteBatch(GraphicsDevice);
        image = Content.Load<Texture2D>("cartoondolphin");
        water = Content.Load<Texture2D>("background");
        flip = SpriteEffects.None;
    }

    protected override void Update(GameTime gameTime)
    {
        float VelocityX = 0f;
        float VelocityY = 0f;

        float time = (float)gameTime.ElapsedGameTime.TotalSeconds;
        KeyboardState kbState = Keyboard.GetState();
        if(kbState.IsKeyDown(Keys.Left)) 
        {
            rotation = 0;
            flip = SpriteEffects.None;
            VelocityX += -5f;
        } 

        if(kbState.IsKeyDown(Keys.Right)) 
        {
            rotation = 0;
            flip = SpriteEffects.FlipHorizontally;
            VelocityX += 5f;
        } 

        // jump if the dolphin is under water
        if(Position.Y >= 670)
        {
            if (kbState.IsKeyDown(Keys.A))
            {     
                if (flip == SpriteEffects.None)
                { 
                  rotation += 0.01f;
                  VelocityY += 40f;
                }
                else
                { 
                  rotation -= 0.01f;
                  VelocityY += 40f;
                }
            }
        } 
        else 
        {
            if (flip == SpriteEffects.None)
            {
              rotation -= 0.01f;
              VelocityY += -10f;
            }
            else
            {
              rotation += 0.01f;
              VelocityY += -10f;
            }
        }

        float deltaY = 0;
        float deltaX = 0;

        deltaY = Gravity * (float)gameTime.ElapsedGameTime.TotalSeconds;

        deltaX += VelocityX * (float)gameTime.ElapsedGameTime.TotalSeconds * Acceleration;
        deltaY += -VelocityY * (float)gameTime.ElapsedGameTime.TotalSeconds * Acceleration;

        Speed = new Vector2(Speed.X + deltaX, Speed.Y + deltaY);
        Position += Speed * (float)gameTime.ElapsedGameTime.TotalSeconds;
        Velocity.X = 0;

        if (Position.Y + image.Height/2 > graphics.PreferredBackBufferHeight)
            Position.Y = graphics.PreferredBackBufferHeight - image.Height/2;

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);
        spriteBatch.Begin();
        spriteBatch.Draw(water, new Rectangle(0, graphics.PreferredBackBufferHeight -100, graphics.PreferredBackBufferWidth, 100), Color.White);
        spriteBatch.Draw(image, Position, null, Color.White, rotation, new Vector2(image.Width / 2, image.Height / 2), 1, flip, 1);
        spriteBatch.End();           

        base.Draw(gameTime);
    }
}

The code now works almost perfectly. I introduced the bool variable direction and made some tests with the angle. Jumping works now as it should. But I couldn't change two things:

1)At the beginning(you can see it in the video), the dolphin always looks up. I want that it looks at the right side, if possible. I tried to change the rotation but it didn't worked.

2)The second thing is a little bit strange. If I change the direction from left to right or right to left, the dolphin is rotated in the wrong direction during a short moment. How can I fix that? I made a new video: http://www.myvideo.de/watch/8881567

    public class Game1 : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    Texture2D image, water;
    float Gravity = 5.0F;
    float Acceleration = 20.0F;
    Vector2 Position = new Vector2(1200,720);
    Vector2 Velocity;
    float rotation = 0;
    SpriteEffects flip;
    Vector2 Speed = new Vector2(0, 0);
    bool direction = false;
    Vector2 prevPos;

    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
        graphics.PreferredBackBufferWidth = 1280;
        graphics.PreferredBackBufferHeight = 720;
    }

    protected override void Initialize()
    {
        base.Initialize();
    }

    protected override void LoadContent()
    {   
        spriteBatch = new SpriteBatch(GraphicsDevice);
        image = Content.Load<Texture2D>("cartoondolphin");
        water = Content.Load<Texture2D>("background");
        flip = SpriteEffects.None;
    }

    protected override void Update(GameTime gameTime)
    {
        float VelocityX = 0f;
        float VelocityY = 0f;

        float time = (float)gameTime.ElapsedGameTime.TotalSeconds;
        KeyboardState kbState = Keyboard.GetState();
        if(kbState.IsKeyDown(Keys.Left)) 
        {
            flip = SpriteEffects.FlipHorizontally;
            VelocityX += -5f;
            direction = false;
        } 

        if(kbState.IsKeyDown(Keys.Right)) 
        {
            flip = SpriteEffects.None;
            VelocityX += 5f;
            direction = true;
        }

        if (direction == false)
             {
          rotation = -((float)Math.Atan2(Position.X - prevPos.X, Position.Y - prevPos.Y) + MathHelper.PiOver2);
          prevPos = Position;
             }
        if (direction == true)
        {
            rotation = -((float)Math.Atan2(Position.X - prevPos.X, Position.Y - prevPos.Y) + MathHelper.Pi + MathHelper.PiOver2);
            prevPos = Position;
        }

        // jump if the dolphin is under water
        if(Position.Y >= 670)
        {
            if (kbState.IsKeyDown(Keys.A))
            {     
                if (flip == SpriteEffects.None)
                { 
                  VelocityY += 40f;
                }
                else
                { 
                  VelocityY += 40f;
                }
            }
        } 
        else 
        {
            if (flip == SpriteEffects.None)
            {
              VelocityY += -10f;
            }
            else
            {
              VelocityY += -10f;
            }
        }

        float deltaY = 0;
        float deltaX = 0;

        deltaY = Gravity * (float)gameTime.ElapsedGameTime.TotalSeconds;

        deltaX += VelocityX * (float)gameTime.ElapsedGameTime.TotalSeconds * Acceleration;
        deltaY += -VelocityY * (float)gameTime.ElapsedGameTime.TotalSeconds * Acceleration;

        Speed = new Vector2(Speed.X + deltaX, Speed.Y + deltaY);

        Position += Speed * (float)gameTime.ElapsedGameTime.TotalSeconds;

        Velocity.X = 0;         

        if (Position.Y + image.Height/2 > graphics.PreferredBackBufferHeight)
            Position.Y = graphics.PreferredBackBufferHeight - image.Height/2;

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);
        spriteBatch.Begin();
        spriteBatch.Draw(water, new Rectangle(0, graphics.PreferredBackBufferHeight -100, graphics.PreferredBackBufferWidth, 100), Color.White);
        spriteBatch.Draw(image, Position, null, Color.White, rotation, new Vector2(image.Width / 2, image.Height / 2), 1, flip, 1);
        spriteBatch.End();           

        base.Draw(gameTime);
    }
}
share|improve this question
3  
While I'm sure "rotates a little weird" is clear to everyone else, I'm a bit slow. Can you explain to me what's happening like I'm 5? I love pictures and animated pictures are da-bomb. –  Byte56 Dec 8 '12 at 16:56
1  
@Byte56 please go easy on newbies. You might scare them off otherwise. –  ashes999 Dec 8 '12 at 17:17
    
Well it was intended to be joking, so I was going easy. –  Byte56 Dec 8 '12 at 17:27
1  
The first part of the movement(jumping) is different than the second part. Ascending looks different than descending. But I want that ascending and descending look equal. I don't know how to fix that. –  Johnny Dec 8 '12 at 19:23
1  
I edited my code and made a new video. In addition, it almost works perfectly. My new video: myvideo.de/watch/8881567 –  Johnny Dec 11 '12 at 21:08
show 6 more comments

1 Answer

up vote 22 down vote accepted

Intuition

A jumping dolphin's rotation is related to the direction it's moving.

dolphin trajectories

The blue is water.
The dots are dolphin positions at each time tick.
The arrows are the direction the dolphin is rotated to face.

That bottom one is a radioactive dolphin with gravity powers.

Implementation

You could get the same effect with something like this:

function dolphin.onPositionChange ()
    dolphin.sprite.rotation = directionFromTo(dolphin.prevPos, dolphin.pos)
    prevPos = pos
end

That's only illustrative pseudocode of course. Here's what it does in English:

Every time the dolphin's position changes
    The angle from its previous position to new position becomes its rotation
    The current position is saved as the old one, for use again next step

Finding the direction from point A to point B is a little bit of geometry. XNA might have a function that does this for you. If it does, use that!

Theory

If it doesn't (or if you just want to understand what's going on), here's the geometry for you:

geometry calculation of angle given opposite and adjacent

Love2D (my favourite game framework) doesn't have a function to calculate the direction from point to point. Here's how I made one:

-- Vector direction
-- Angle in radians, clockwise from up i.e. straight up is 0, right is
-- pi/2, down is pi, etc.
function directionFromTo(a,b)
    return math.atan2( (b.x - a.x) , (b.y - a.y) )
end

-- Test; should print 135
a = {x = 0, y = 0}
b = {x = 1, y = -1}
print( directionFromTo(a,b) / math.pi*180) -- (division to convert to degrees)
share|improve this answer
    
Could you please explain how to use your code? I want that the dolphin jumps like in the first picture. –  Johnny Dec 10 '12 at 10:48
    
I've added all the nitty-gritty details. :) –  Anko Dec 10 '12 at 11:32
    
I still have trouble with the code. Look at my answer. –  Johnny Dec 10 '12 at 14:58
    
I edited my question with additional information and code. –  Johnny Dec 10 '12 at 21:19
1  
+1 for your very complete answer. It shows a lot of effort. –  petervaz Dec 11 '12 at 12:35
show 1 more comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.