4 Replies - 953 Views - Last Post: 26 August 2017 - 01:37 AM

#1 Shaddoll Beast  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 01-March 17

How to call Draw separately from Update?

Posted 01 March 2017 - 05:08 PM

Hi,
after playing an Emerald Mine-like game for years I decided to start making my own with several new ideas and new graphics.
Well, actually I'm in struggle with the timing for Update() and Draw() method. I took many hours to get the needed knowledge in C#, but I'm not really familiar with the XNA (MonoGame)-Framework so I hope you can help me that I haven't to give it up before really starting.

Emerald Mine is a table-based 2D-game. So the level design is an int[,]-Array of tiles, each tile with 48px height and width. the game-elements in this tiles are working all synchron to each other. There is a "movingTime", let's say every 200 milliseconds, when affected game elements changes their position in the array. e.g. when there a boulder is falling, it falls the same speed like the player or an enemy moves around. when the player does a keyboard-input, so he has to move exactly the 48px on the screen to the next tile.
After some experimental work, it seems the best way having the Update()-Method be called just every 200milliseconds (thats the time when doing a mew move, checking if touching an enemy, etc), so i used "this.TargetElapsedTime = new TimeSpan(0, 0, 0, 0, 200);" for this.
But with this a problem appears: I have to call the Draw()-Method more often than Update(), because the animation-frames should be updated in an smaller interval to have a smooth animation while moving from one tile to next and not just hopping to it. Is that possible somehow?
Don't be confused about the method-names - to will keep overview about my code it's easier for me to use german names. For you I commented on the important lines what they mean. In the "Spieler" (Player)-Class I've given the moving-methods an for-loop that let the animation-sprite slowly move up to the new player-position. But it's still drawn once at Update()-Time and I need it between the Update()-times..
Is there an easy way to handle it?

Here's my code so far:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;

namespace Game1
{
    public class Game1 : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Spieler spieler = new Spieler(1, 1);
        private AnimatedSprite spieler_LinksLaufen;	//sprites for moving up/down/left/right/standing
        private AnimatedSprite spieler_RechtsLaufen;
        private AnimatedSprite spieler_ObenLaufen;
        private AnimatedSprite spieler_UntenLaufen;
        private AnimatedSprite spieler_StehenBleiben;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            this.TargetElapsedTime = new TimeSpan(0, 0, 0, 0, 200);
            this.IsFixedTimeStep = true;                              

            graphics.PreferredBackBufferHeight = 768;
            graphics.PreferredBackBufferWidth = 1366;
        }

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

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            Texture2D spieler_nachLinks = Content.Load<Texture2D>("Rockford-v3-bewegungNachLinks");	// loading sprites for moving directions and standing
            Texture2D spieler_nachRechts = Content.Load<Texture2D>("Rockford-v3-bewegungNachRechts");
            Texture2D spieler_nachOben = Content.Load<Texture2D>("Rockford-v3-bewegungNachOben");
            Texture2D spieler_nachUnten = Content.Load<Texture2D>("Rockford-v3-bewegungNachUnten");
            Texture2D spieler_Stehen = Content.Load<Texture2D>("Rockford-v3-Stehen");

            spieler_LinksLaufen = new AnimatedSprite(spieler_nachLinks, 1, 4, 5);			// animated sprites for moving directions and standing
            spieler_RechtsLaufen = new AnimatedSprite(spieler_nachRechts, 1, 4, 5);
            spieler_ObenLaufen = new AnimatedSprite(spieler_nachOben, 1, 4, 5);
            spieler_UntenLaufen = new AnimatedSprite(spieler_nachUnten, 1, 4, 5);
            spieler_StehenBleiben = new AnimatedSprite(spieler_Stehen, 1, 1, 5);
        }

        protected override void UnloadContent()
        {
            
        }


        protected override void Update(GameTime gameTime)
        {

            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();

            // Own logic starting here

            // Doing a move //

            if (Keyboard.GetState().IsKeyDown(Keys.Left))
            {
                spieler.InBewegungLinks = true;
                spieler.NachLinksBewegen();
            }

            else if (Keyboard.GetState().IsKeyDown(Keys.Right))
            {
                spieler.InBewegungRechts = true;
                spieler.NachRechtsBewegen();
            }

            else if (Keyboard.GetState().IsKeyDown(Keys.Up))
            {
                spieler.InBewegungOben = true;
                spieler.NachObenBewegen();
            }

            else if (Keyboard.GetState().IsKeyDown(Keys.Down))
            {
                spieler.InBewegungUnten = true;
                spieler.NachUntenBewegen();
            }
            else
            {
                spieler.InBewegungLinks = false;
                spieler.InBewegungRechts = false;
                spieler.InBewegungOben = false;
                spieler.InBewegungUnten = false;
                spieler.NichtInBewegung = true;
            }

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {

                GraphicsDevice.Clear(Color.Black);

                if (spieler.InBewegungLinks)  // call animated sprite when moving left
                {
                    spieler_LinksLaufen.currentFrameDelay--;
                    spieler_LinksLaufen.Draw(spriteBatch, new Vector2(spieler.spritePosX, spieler.spritePosY));
                    spieler_LinksLaufen.Update();
                }

                else if (spieler.InBewegungRechts) // call animated sprite when moving right
                {
                    spieler_RechtsLaufen.currentFrameDelay--;
                    spieler_RechtsLaufen.Draw(spriteBatch, new Vector2(spieler.spritePosX, spieler.spritePosY));
                    spieler_RechtsLaufen.Update();
                }

                else if (spieler.InBewegungOben) // call animated sprite when moving up
                {
                    spieler_ObenLaufen.currentFrameDelay--;
                    spieler_ObenLaufen.Draw(spriteBatch, new Vector2(spieler.spritePosX, spieler.spritePosY));
                    spieler_ObenLaufen.Update();
                }

                else if (spieler.InBewegungUnten)  // call animated sprite when moving down
                {
                    spieler_UntenLaufen.currentFrameDelay--;
                    spieler_UntenLaufen.Draw(spriteBatch, new Vector2(spieler.spritePosX, spieler.spritePosY));
                    spieler_UntenLaufen.Update();
                }
                else if (spieler.NichtInBewegung)  // call animated sprite when not moving
                {
                    spieler_StehenBleiben.currentFrameDelay--;
                    spieler_StehenBleiben.Draw(spriteBatch, new Vector2(spieler.spritePosX, spieler.spritePosY));
                    spieler_StehenBleiben.Update();
                }
            }
    }
}




the player-class:

class Spieler 
    {
        public bool amLeben = true;

        public Spieler(int posX, int posY)
        {
            this.PosX = posX;
            this.PosY = posY;
            spritePosX = posX;
            spritePosY = posY;
        }

	// moving methods


        public void NachLinksBewegen()	// left
        {
            PosX -= 1;
            for (int i = 0; i < 24; i++)
            {
                spritePosX -= 2;
            }
        }

        public void NachRechtsBewegen()  // right
        {
            PosX += 1;
            for (int i = 0; i < 24; i++)
            {
                spritePosX += 2;
            }
        }

        public void NachObenBewegen()	// up
        {
            PosY -= 1;
            for (int i = 0; i < 24; i++)
            {
                spritePosY -= 2;
            }
        }

        public void NachUntenBewegen()   /down
        {
            PosY += 1;
            for (int i = 0; i < 24; i++)
            {
                spritePosY += 2;
            }
        }




And at last for completitionthe the animated sprite-class that shouldn't be relevantant for the problem:

namespace Game1
{
    public class AnimatedSprite
    {
        public Texture2D Texture { get; set; }

        public int Rows { get; set; }
        public int Columns { get; set; }
        public int currentFrame;
        public int totalFrames;
        private int frameDelay;
        public int currentFrameDelay;

        public AnimatedSprite(Texture2D texture, int rows, int columns, int frameDelay)
        {
            Texture = texture;
            Rows = rows;
            Columns = columns;
            currentFrame = 0;
            totalFrames = rows * columns;
            this.frameDelay = frameDelay;

        }

        public void Update()
        {
            if (currentFrameDelay <= 0)
            {
                currentFrame++;
                currentFrameDelay = frameDelay;

                if (currentFrame == totalFrames)
                    currentFrame = 0;
            }
        }

        public void Draw(SpriteBatch spriteBatch, Vector2 location)
        {
            int width = Texture.Width / Columns;
            int height = Texture.Height / Rows;
            int row = (int)((float)currentFrame / (float)Columns);
            int column = currentFrame % Columns;

            Rectangle sourceRectangle = new Rectangle(width * column, height * row, width, height);
            Rectangle destinationRectangle = new Rectangle((int)location.X, (int)location.Y, width, height);

            spriteBatch.Begin();
            spriteBatch.Draw(Texture, destinationRectangle, sourceRectangle, Color.White);
            spriteBatch.End();
        }

    }
}




Is This A Good Question/Topic? 0
  • +

Replies To: How to call Draw separately from Update?

#2 BBeck  Icon User is offline

  • Here to help.
  • member icon


Reputation: 792
  • View blog
  • Posts: 1,886
  • Joined: 24-April 12

Re: How to call Draw separately from Update?

Posted 02 March 2017 - 04:31 AM

You may want to consider using GameTime instead. You can get the time since the last Update() and multiply that by something that changes to get it to update the correct amount each frame. Or, you could use it with some sort of conditional state so that things only occur at a regular interval. Then Draw() should be allowed to do whatever it needs to do.
Was This Post Helpful? 0
  • +
  • -

#3 Shaddoll Beast  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 01-March 17

Re: How to call Draw separately from Update?

Posted 02 March 2017 - 07:32 AM

View PostBBeck, on 02 March 2017 - 04:31 AM, said:

You may want to consider using GameTime instead. You can get the time since the last Update() and multiply that by something that changes to get it to update the correct amount each frame. Or, you could use it with some sort of conditional state so that things only occur at a regular interval. Then Draw() should be allowed to do whatever it needs to do.


Hi BBeck,
thanks for you quick response. I hope I understood you right so far to let the game itself permanently update as usual and use another variable for ingame-detections.
But obviously I still understand the timer and/or Update()-working wrong.
According to your hint I did set back TargetElapsedTime to standard and used a delta-variable to keep track when exactely 200milliseconds are over.
But that detection doesn't work - even if I ease the interval to more than just that special millisecond.
So movingTime never gets true and the animation is shown smoothly, but the sprite doesn't ever change its position.
Can you give me a short example please?

protected override void Update(GameTime gameTime)
        {
            float delta = gameTime.ElapsedGameTime.Milliseconds;

            if (delta == 200)
                movingTime = true;
            else movingTime = false;

                if (Keyboard.GetState().IsKeyDown(Keys.Left))
                {
                    spieler.InBewegungLinks = true;
                    spieler.NachLinksBewegen(movingTime);
                }



player-class:

        public void NachLinksBewegen(bool movingTime)	// moving left
        {
            if (movingTime)
            {
                PosX -= 1;
                for (int i = 0; i < 24; i++)
                {
                    spritePosX -= 2;
                }
            }
        }


Was This Post Helpful? 0
  • +
  • -

#4 modi123_1  Icon User is offline

  • Suitor #2
  • member icon



Reputation: 13400
  • View blog
  • Posts: 53,478
  • Joined: 12-June 08

Re: How to call Draw separately from Update?

Posted 02 March 2017 - 07:41 AM

I would highly advocate not trying to break the update/draw game loop. You can work your animation in the common pipeline with little issues outside of some tweaking of timing and animation.

http://www.dreaminco...nimated-sprite/
https://www.youtube....h?v=tNdDRfxW87k
Was This Post Helpful? 1
  • +
  • -

#5 Shaddoll Beast  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 01-March 17

Re: How to call Draw separately from Update?

Posted 26 August 2017 - 01:37 AM

Thank you for all your hints! I paused the last months working with XNA, but after checking out how the framework exactly works these tips helped a lot to have a solid working game logic.

Maybe i can show you first visual results in a fortnights time.

Bye,
Ruben
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1