0
\$\begingroup\$

I dont know why but my jump method does not work. My character can only jump on one single object. The other obstacle haven't any influence on the player. I really don't see my mistake

     foreach (RectangleShape obstacles in MoveAtObjectList)
               {
                   MainPlayer.Move(deltaTime, obstacles);
               }

               foreach (RectangleShape obstacles in JumpAtObjectList)
               {
                   MainPlayer.Jump(deltaTime, obstacles);
                   break;
               }

               Draw();

               Window.Display();
           }
       }
   }
}

This was part of my main Class, where i call the jump method within a foreach loop. Here in my Payer class I tried to write the jump function.

using SFML.Graphics;
using SFML.System;
using SFML.Window;

namespace Pong3final
{
    class Player : RectangleShape
    {

        float CollisionDistance = 0.5f;

        float PlayerSpeed = 50;
        float JumpSpeed = 100;
        float FallSpeed = 100;
        float JumpTimer;

        bool JumpBool = false;
        bool Fall = true;

public  void Jump(float deltaTime, RectangleShape collisionObject)
        {

            if (Keyboard.IsKeyPressed(Keyboard.Key.Space) && !Fall && CheckCollision(this, collisionObject))
            {
                JumpBool = true;
            }

            //Player is jumping
            if (JumpBool)
            {
                JumpTimer += deltaTime;

                this.Position -= new Vector2f(0, JumpSpeed) * deltaTime;

                if (JumpTimer > 0.5f)
                {
                    JumpBool = false;
                    Fall = true;
                    JumpTimer = 0;
                }
            }

            //Player is falling when he doesnt touch anything and he isnt jumping
            else if (!CheckCollision(this, collisionObject))
            {
                Fall = true;
            }

            //Player is falling
            if (!JumpBool && !CheckCollision(this, collisionObject) && Fall)
            {
                this.Position += new Vector2f(0, FallSpeed) * deltaTime;

                if (CheckCollision(this, collisionObject)) //Player stops falling because of a collision with an object
                {
                    Fall = false;
                }
            }
        }


        public void Move(float deltaTime, RectangleShape collisionObject)
        {
            {
                Vector2f MovePlayerPosition = Position;

                if ((Keyboard.IsKeyPressed(Keyboard.Key.Left) || Keyboard.IsKeyPressed(Keyboard.Key.A)))
                {

                    MovePlayerPosition -= new Vector2f(PlayerSpeed, 0) * deltaTime;

                    FloatRect collisionOverlap;

                    if (CheckCollision(this, collisionObject, out collisionOverlap))
                    {
                       MovePlayerPosition = MovePlayerPosition + new Vector2f(collisionOverlap.Width + CollisionDistance, 0);
                    }    
                }

                if (Keyboard.IsKeyPressed(Keyboard.Key.Right) || Keyboard.IsKeyPressed(Keyboard.Key.D))
                {

                    MovePlayerPosition += new Vector2f(PlayerSpeed, 0) * deltaTime;

                    FloatRect collisionOverlap;

                    if (CheckCollision(this, collisionObject, out collisionOverlap))
                    {
                       MovePlayerPosition = MovePlayerPosition - new Vector2f(collisionOverlap.Width + CollisionDistance, 0);
                    }                  
                }

                Position = MovePlayerPosition;
            }
        }


        public static bool CheckCollision(RectangleShape obj1, RectangleShape obj2, out FloatRect overlap)
        {
            FloatRect obj1Collider = obj1.GetGlobalBounds();
            FloatRect obj2Collider = obj2.GetGlobalBounds();

            //Nur die rechte, linke und obere Seite kollidiert
            if (obj1Collider.Intersects(obj2Collider, out overlap))
            {
                return true;
            }
            overlap = new FloatRect();
            return false;
        }

        public static bool CheckCollision(RectangleShape obj1, RectangleShape obj2)
        {
            FloatRect obj1Collider = obj1.GetGlobalBounds();
            FloatRect obj2Collider = obj2.GetGlobalBounds();

            return obj1Collider.Intersects(obj2Collider);
        }
    }
}
\$\endgroup\$
7
  • \$\begingroup\$ Do you think I should try an other approach to let my player jump. I just need a hint! \$\endgroup\$ – MoonyTown Apr 1 '20 at 9:33
  • \$\begingroup\$ You need to rephrase this question as an actual problem you are having, so that people answering know where to look. Please re-title it and clarify the question you are asking in the body text. \$\endgroup\$ – Natalo77 Apr 1 '20 at 10:30
  • \$\begingroup\$ The first code section doesn't make any sense to me. I would guess from context that it's your main loop. But you make the player move once for each obstacle in the game? And after each time you move it, you again make the player jump once for each obstacle? So if you have 3 obstacles, you make the player move 3 times and then make the player jump 9 times? Why?!? \$\endgroup\$ – Philipp Apr 1 '20 at 10:46
  • 1
    \$\begingroup\$ Actually, should the break in the second foreach not cancel the whole foreach? I mean there is no condition and it stops after the first jump. \$\endgroup\$ – Zibelas Apr 1 '20 at 11:24
  • \$\begingroup\$ @Zibelas: that looks like a potential answer that would fit the symptom described in the question. \$\endgroup\$ – DMGregory Apr 1 '20 at 11:52
3
\$\begingroup\$

You have at least one obvious error at hand.

foreach (RectangleShape obstacles in JumpAtObjectList)
{
      MainPlayer.Jump(deltaTime, obstacles);
      break;
}

break tells the foreach loop to exit and since there is no condition, it will always exactly run one time for the first obstacles in JumpAtObjectList. What you probably wanted is to check if the obstacles (better naming would be obstacle since it is only one at a time) is the correct one, execute your MainPlayer.jump and break afterwards.

Next I'm almost sure that your move method is wrong as well. You are calling it once for each object and each time you move your player, but what you want is to only move him once.

I refactored it a bit for easier reading and probably this should fix as well your jumping issue. Since you are not moving if you don't press the key (no auto move), you only need to call it when you press the key compared to your jump method (where you can fall as well). Better naming would be handleVerticalMovement. I kept your code as close as you wrote it with just placing the loops where they should belong.

Main loop

if ((Keyboard.IsKeyPressed(Keyboard.Key.Left) || Keyboard.IsKeyPressed(Keyboard.Key.A))) {
       MainPlayer.Move(deltaTime, MoveAtObjectList, -1);
}
if (Keyboard.IsKeyPressed(Keyboard.Key.Right) || Keyboard.IsKeyPressed(Keyboard.Key.D)) {
       MainPlayer.Move(deltaTime, MoveAtObjectList, 1);                                             
}
MainPlayer.Jump(deltaTime, JumpAtObjectList);
Draw();        
Window.Display();

New move

public void Move(float deltaTime, List MoveAtObjectList, int direction){
    bool hitSomething = false;
    foreach (RectangleShape obstacles in MoveAtObjectList) {
        if (CheckCollision(this, collisionObject, out collisionOverlap)) {
            hitSomething = true;
            this.Position += new Vector2f(collisionOverlap.Width + CollisionDistance, 0) * direction;
            break; //hitting one thing is enough
        }
    }
    if (!hitSomething) {
        this.Position -= new Vector2f(PlayerSpeed, 0) * deltaTime * direction;
    }                  
} 

Adjusted jump

public  void Jump(float deltaTime, List JumpAtObjectList) {
    bool hitSomething = false;
    foreach (RectangleShape collisionObject in JumpAtObjectList) {
        if (CheckCollision(this, collisionObject)) { 
            hitSomething = true;
            Fall = false; //you can't if you hit something
            break;
        }
    }            
    if (Keyboard.IsKeyPressed(Keyboard.Key.Space) && !Fall && hitSomething) {
        JumpBool = true;
    }
    if (JumpBool) {
        JumpTimer += deltaTime;
        this.Position -= new Vector2f(0, JumpSpeed) * deltaTime;
        if (JumpTimer > 0.5f) {
            JumpBool = false;
            Fall = true;
            JumpTimer = 0;
        }
    } else if (!hitSomething) {     
        Fall = true;
    }
    if (!JumpBool && !hitSomething && Fall) {
        this.Position += new Vector2f(0, FallSpeed) * deltaTime;                
    }
}
\$\endgroup\$
4
  • \$\begingroup\$ I think the "Move" method might just be misleadingly named. From OP's comments, it sounds like it's actually "Check if there are collisions with this obstacle that block your move" not "Perform a move with this obstacle" \$\endgroup\$ – DMGregory Apr 1 '20 at 12:18
  • 1
    \$\begingroup\$ @DMGregory I read it like, check if key is pressed, if yes add some movement to player and reduce it if you hit something but still once for each of the objects in the MoveAtObjectList (which could be 1 or 100)) \$\endgroup\$ – Zibelas Apr 1 '20 at 12:21
  • \$\begingroup\$ Ok thanks for all your helps DMGregory and Zibelas I will adjust my code. Is there anything else I should note? \$\endgroup\$ – MoonyTown Apr 2 '20 at 13:19
  • \$\begingroup\$ If it works for you, mark the question is answered with the green tick. If you have further questions, modify your question with new information what is not working (what you are expecting, what error you get, how you get the error) \$\endgroup\$ – Zibelas Apr 2 '20 at 18:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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