简体   繁体   English

C#-我的碰撞代码不会导致播放器停止在其音轨中

[英]C# - My Collision code won't result in the player stopping in his tracks

I have been working on a C# & SFML remake of one of my LWJGL engines. 我一直在研究我的LWJGL引擎之一的C#和SFML重制。 So far it's going great, but, when I tried to copy/convert over my collision code, things didn't go so well. 到目前为止,一切都很好,但是,当我尝试复制/转换碰撞代码时,事情进展得并不顺利。

Here's my code for the player/entity class, bounding box, and the game code. 这是我的玩家/实体类,边界框和游戏代码。

Entity: 实体:

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SFML.Graphics;
using SFML.System;
using SFML.Window;

namespace FastSrc_CS.Core
{
    public class FSEntity
    {
        public Vector2f Position, Size;
        public Color EColor;

        public RectangleShape sprite;

        public BoundingBox Bounds;

        public bool canMove;
        public float VelX, VelY;

        public FSEntity()
        {

        }

        public virtual void Init(Vector2f pos, Vector2f size, Color color)
        {
            Position = pos;
            Size = size;
            EColor = color;

            sprite = new RectangleShape();
            sprite.FillColor = EColor;
            sprite.Position = Position;
            sprite.Size = Size;
            //sprite.Origin = new Vector2f(size.X / 2, size.Y / 2);

            Bounds = new BoundingBox(Position, Size);
        }

        public void SetVelX(float x)
        {
            VelX = x;
        }

        public void SetVelY(float x)
        {
            VelY = x;
        }

        public Vector2f GetOrigin()
        {
            return new Vector2f(Size.X / 2, Size.Y / 2);
        }

        public virtual void Update()
        {

        }

        public void UpdatePos()
        {
            Position.X += VelX;
            Position.Y += VelY;
            sprite.Position = Position;
            Bounds.UpdateBounds(Position, Size);
        }

        public virtual void Render(RenderWindow w)
        {
            w.Draw(sprite);
        }
    }
}

Player: 玩家:

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SFML.Graphics;
using SFML.System;
using SFML.Window;

namespace FastSrc_CS
{
    class Player : Core.FSEntity
    {
        public float speed = 6f;

        public override void Init(Vector2f pos, Vector2f size, Color color)
        {
            canMove = true;
            base.Init(pos, size, color);
        }

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

            Movement();

            Position.X += VelX;
            Position.Y += VelY;
            sprite.Position = Position;
            Bounds.UpdateBounds(Position, Size);
        }

        public void Movement()
        {
            if (Keyboard.IsKeyPressed(Keyboard.Key.A) && canMove == true)
            {
                SetVelX(-speed);
                SetVelY(0);
            }
            else if (Keyboard.IsKeyPressed(Keyboard.Key.D) && canMove == true)
            {
                SetVelX(speed);
                SetVelY(0);
            }
            else if (Keyboard.IsKeyPressed(Keyboard.Key.W) && canMove == true)
            {
                SetVelY(-speed);
                SetVelX(0);
            }
            else if (Keyboard.IsKeyPressed(Keyboard.Key.S) && canMove == true)
            {
                SetVelY(speed);
                SetVelX(0);
            }
            else
            {
                SetVelX(0);
                SetVelY(0);
            }
        }

        public override void Render(RenderWindow w)
        {
            base.Render(w);
        }
    }
}

Bounding Box: 边界框:

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SFML.Graphics;
using SFML.System;
using SFML.Window;

namespace FastSrc_CS.Core
{
    public class BoundingBox
    {
        public FloatRect Rectangle;

        public BoundingBox(Vector2f pos, Vector2f size)
        {
            Rectangle = new FloatRect(pos, size);
        }

        public bool Collide(BoundingBox b)
        {
            bool col = false;

            if (this.Rectangle.Intersects(b.Rectangle))
            {
                col = true;
            }
            else
            {
                col = false;
            }

            return col;
        }

        public void UpdateBounds(Vector2f pos, Vector2f size)
        {
            Rectangle.Width = size.X;
            Rectangle.Height = size.Y;
            Rectangle.Left = pos.X;
            Rectangle.Top = pos.Y;
        }
    }
}

Game: 游戏:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FastSrc_CS.Core;
using SFML.Graphics;
using SFML.System;
using SFML.Window;

namespace FastSrc_CS
{
    public class Game : FSGame
    {
        Player p = new Player();
        Wall w = new Wall();

        public override void Init()
        {
            p.Init(new Vector2f(400, 300), new Vector2f(32, 32), Color.Red);
            w.Init(new Vector2f(100, 100), new Vector2f(32, 32), Color.Blue);

            Entities.Add(p);
            Entities.Add(w);
        }

        public override void Update()
        {
            Console.WriteLine(p.Position.X);

            //COLLISION CODE FOR WALLS
            if (p.Bounds.Collide(w.Bounds))
            {
                //Right Collision
                if (p.VelX > 0)
                {
                    Console.WriteLine("Right Collision");
                    p.canMove = false;
                    p.Position.X = w.Position.X - 32;
                    p.SetVelX(0);
                }
                else if (p.VelX < 0)
                {
                    Console.WriteLine("Left Collision");
                    p.canMove = false;
                    p.Position.X = w.Position.X + 32;
                    p.SetVelX(0);
                }

                if (p.VelX == 0)
                {
                    p.canMove = true;
                }
            }

            Entities.ForEach(k => k.Update());
        }

        public override void Render(RenderWindow w)
        {
            Entities.ForEach(k => k.Render(w));
        }
    }
}

The issue lies within the "game" class in this region: 问题出在该区域的“游戏”类之内:

        //COLLISION CODE FOR WALLS
        if (p.Bounds.Collide(w.Bounds))
        {
            //Right Collision
            if (p.VelX > 0)
            {
                Console.WriteLine("Right Collision");
                p.canMove = false;
                p.Position.X = w.Position.X - 32;
                p.SetVelX(0);
            }
            else if (p.VelX < 0)
            {
                Console.WriteLine("Left Collision");
                p.canMove = false;
                p.Position.X = w.Position.X + 32;
                p.SetVelX(0);
            }

            if (p.VelX == 0)
            {
                p.canMove = true;
            }
        }

When I run this, the player will stop moving, but he will be slightly implanted into the wall. 当我执行此操作时,播放器将停止移动,但会稍微植入墙壁。 I know what you're thinking, "move the if statement that make p.canMove = true outside of the collision's if statement." 我知道您在想什么,“将使p.canMove = true的if语句p.canMove = true冲突的if语句之外。” I have tried this, and it results in the player bouncing back-and-forth with the cube. 我已经尝试过了,它导致播放器与立方体来回弹跳。 I have tried different methods to the point where I thought about leaving this code out. 我尝试过不同的方法,以至于我考虑将这段代码省去。 I decided to revert back to Stack Overflow to see if someone could help me out. 我决定退回到Stack Overflow,看看是否有人可以帮助我。 Thanks in advance. 提前致谢。

I don't think the problem with your code is your engine at all - given the result and, after scanning the code, it seems to be fine. 我认为代码根本不是您的引擎-给定结果,并且在扫描代码后,这似乎还不错。 Since your player clips into the wall, the hard-coded value of 32 for both your player and your wall, chances are, is incorrect. 由于播放器夹在墙上,因此播放器和墙壁的硬编码值32都是不正确的。 Try this: 尝试这个:

        if (p.VelX > 0)
        {
            Console.WriteLine("Right Collision");
            p.canMove = false;
            //move the right of our player to the left of the wall by setting
            //his x to the wall's x minus his width.
            p.Position.X = w.Position.X - p.Size.Width;
            p.SetVelX(0);
        }
        else if (p.VelX < 0)
        {
            Console.WriteLine("Left Collision");
            p.canMove = false;
            //Move the left of our player to the right of the wall, or
            //the wall's x plus the wall's width
            p.Position.X = w.Position.X + w.Size.Width;
            p.SetVelX(0);
         }

I hope this helped. 希望对您有所帮助。

EDIT 编辑

Actually, I think I found another problem. 实际上,我认为我发现了另一个问题。 When you change the player's position after moving his X after collision detection, you forget to call the UpdatePos() method. 当在检测到碰撞后移动其X后更改玩家的位置时,您忘记调用UpdatePos()方法。 Thus, you are moving his position but not his actual rectangle, which may be causing an error. 因此,您移动的是他的位置,而不是实际的矩形,这可能会导致错误。 Rather, after you move his x, immediately call UpdatePos() 而是,在移动他的x之后,立即调用UpdatePos()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM