两个物体都在移动,而不是 2d 游戏中的一个

Both objects are moving instead of just one in 2d game

我正在制作 java 二维游戏库,使用 JSFML 作为基础。

最近发现一个大问题。 我在游戏中的所有对象都在扩展抽象 class GameObject,其中包含对象的位置、速度、大小和名称等内容。

所有加载的对象都存储在 Game class 实例中,该实例处理游戏。

现在的问题是:每当玩家移动时,它所带的所有东西也会移动。

例如,如果我用 w、a、s、d 键移动玩家,它不仅会移动玩家,还会移动地板。

以下是用户角度的代码:

public static void main(String[] args) {
    GameSettings settings = new GameSettings("Testing window!", 800, 600);
    Game game = Game.Create(settings);

    GameObject floor = game.LoadObject(new Floor("Floor", new Vector2(400 - 500, 500), new Vector2(500, 16)));
    GameObject player = game.LoadObject(new Player("Player", new Vector2(400 - 16, 300 - 16), new Vector2(32, 32)));

    game.Start();
}

这是球员和地板 classes:

public class Player extends GameObject {

    public float speed = 7.5f;

    public Player(String name, Vector2 position, Vector2 size) {
        super(name, position, size);
    }

    @Override
    public void Start() {
        this.canGoOutsideOfWindow = false;
        this.allowCollision = true;
        this.allowGravity = true;
    }

    @Override
    public void TickUpdate() {
        if (GameInput.IsKeyPressed(Keyboard.Key.D)) {
            this.velocity.x = speed;
        }
        if (GameInput.IsKeyPressed(Keyboard.Key.A)) {
            this.velocity.x = -speed;
        }
        if (GameInput.IsKeyPressed(Keyboard.Key.W)) {
            this.velocity.y = -speed;
        }
        if (GameInput.IsKeyPressed(Keyboard.Key.S)) {
            this.velocity.y = speed;
        }
    }
}
public class Floor extends GameObject {
    public Floor(String name, Vector2 position, Vector2 size) {
        super(name, position, size);
    }

    @Override
    public void Start() {
        allowCollision = true;
        allowFriction = false;
        canGoOutsideOfWindow = false;
    }
}

这是游戏 class:

public class Game {

    // Instance variable for game class, because i don't want more instances of it, only one.
    private static Game i;

    // Variable to store game configuration
    private GameSettings settings;

    // Just some private variables, I don't know.
    private boolean started = false;
    private int framesPerSecond;
    private ArrayList<GameObject> objects = new ArrayList<GameObject>();

    // Constructor for creating game only private.
    private Game(GameSettings settings) {
        GameOutput.SendInfo("Creating game instance with settings " + settings + "...");

        this.settings = settings;

        GameOutput.SendInfo("Game instance created!");
    }

    // Beginning of string of methods after start.
    public void Start() {

        if (!started) {
            GameOutput.SendInfo("Starting the game...");

            for (GameObject o : objects)
                o.Start();

            GameOutput.SendInfo("Game started, and running...");
            InitWindow();
        } else {
            GameOutput.SendError("Your code is trying to start the game, but game is already started!");
        }
    }

    // Beginning of string of methods before stopping
    public void Stop() {
        if (GameWindow.Get().isOpen()) {
            GameOutput.SendInfo("Stopping game...");

            for (GameObject o : objects)
                o.Stop();

            GameWindow.Get().close();

            GameOutput.SendInfo("Game closed!");
            System.exit(69);
        } else {
            GameOutput.SendError("Your code is trying to stop the game, but game is already closed!");
        }
    }

    // Beginning of string of methods after frame update.
    private void FrameUpdate() {
        GameWindow w = GameWindow.Get();

        for (Event e : w.pollEvents()) {
            if (e.type == Event.Type.CLOSED) {
                Stop();
            }
        }
        CheckForInputs();

        for (GameObject o : objects)
            o.FrameUpdate();
    }

    // Just method for checking inputs every frame.
    private void CheckForInputs() {
        GameWindow w = GameWindow.Get();

        if (GameInput.IsKeyPressed(Keyboard.Key.ESCAPE))
            Stop();

        for (Event e : w.pollEvents()) {
            if (e.type == Event.Type.KEY_PRESSED) {
                for (GameObject o : objects)
                    o.KeyPressed(e.asKeyEvent());
            }
            if (e.type == Event.Type.KEY_RELEASED) {
                for (GameObject o : objects)
                    o.KeyReleased(e.asKeyEvent());
            }
        }
    }

    // Beginning of string of methods after frame render.
    private void FrameRender() {
        GameWindow w = GameWindow.Get();
        w.clear(new Color(30, 30, 30, 255));

        for (GameObject o : objects) {
            if (!o.canGoOutsideOfWindow)
                o.position = new Vector2(GameMath.Clamp(o.position.x, 0, GameWindow.Get().getSize().x - o.size.x), GameMath.Clamp(o.position.y, 0, GameWindow.Get().getSize().y - o.size.y));
            RectangleShape r = new RectangleShape();
            r.setSize(new Vector2f(o.size.x, o.size.y));
            r.setPosition(o.position.x, o.position.y);
            r.setFillColor(Color.WHITE);
            GameWindow.Get().draw(r);

            o.FrameRender();
        }

        w.display();
    }

    // Beginning of string of methods after tick update.
    private void TickUpdate() {
        for (GameObject o : objects) {
            Vector2 nextPosition = new Vector2(o.position.x + o.velocity.x, o.position.y + o.velocity.y);
            o.position = nextPosition;

            if (o.allowFriction) {
                if (o.velocity.x >= o.frictionAmount)
                    o.velocity.x -= o.frictionAmount;
                else if (o.velocity.x < o.frictionAmount && o.velocity.x > -o.frictionAmount)
                    o.velocity.x = 0;
                if (o.velocity.y >= o.frictionAmount)
                    o.velocity.y -= o.frictionAmount;
                else if (o.velocity.y < o.frictionAmount && o.velocity.y > -o.frictionAmount)
                    o.velocity.y = 0;

                if (o.velocity.x <= -o.frictionAmount)
                    o.velocity.x += o.frictionAmount;
                else if (o.velocity.x > o.frictionAmount && o.velocity.x < o.frictionAmount)
                    o.velocity.x = 0;
                if (o.velocity.y <= -o.frictionAmount)
                    o.velocity.y += o.frictionAmount;
                else if (o.velocity.y > o.frictionAmount && o.velocity.y < o.frictionAmount)
                    o.velocity.y = 0;
            }

            o.TickUpdate();
        }
    }

    // Starting the game window.
    private void InitWindow() {
        GameOutput.SendInfo("Initializing window...");

        GameWindow w = GameWindow.Create();
        w.create(new VideoMode(settings.windowWidth, settings.windowHeight), settings.windowTitle);
        GameOutput.SendInfo("Window initilized!");

        InitLoop();
    }

    // Starting game loop.
    private void InitLoop() {
        GameOutput.SendInfo("Initializing game loop...");

        long lastTime = System.nanoTime();
        double amountOfTicks = settings.ticksPerSecond;
        double ns = 1000000000 / amountOfTicks;
        double delta = 0;
        long timer = System.currentTimeMillis();
        int frames = 0;

        GameOutput.SendInfo("Game loop initialized!");

        while (GameWindow.Get().isOpen()) {
            long now = System.nanoTime();
            delta += (now - lastTime) / ns;
            lastTime = now;
            while (delta >= 1) {
                TickUpdate();
                delta--;
            }
            if (GameWindow.Get().isOpen()) {
                GameTime.deltaTime = (float) delta;
                FrameRender();
                FrameUpdate();
            }
            frames++;
            if (System.currentTimeMillis() - timer > 1000) {
                timer += 1000;
                framesPerSecond = frames;
                frames = 0;
            }
        }
            }

    // Only method for loading objects to game.
    public GameObject LoadObject(GameObject object) {
        GameOutput.SendInfo("Loading object " + object + " to the game...");

        objects.add(object);
        object.active = true;

        GameOutput.SendInfo("Loaded object " + object + " to the game!");
        return object;
    }

    // Only method for getting loaded object from game.
    public GameObject GetLoadedObject(String name) {
        GameObject result = null;

        for (GameObject o : objects)
            if (o.name.equalsIgnoreCase(name))
                result = o;

        return result;
    }

    // Public method for getting object list.
    public List<GameObject> GetLoadedObjects() {
        return objects;
    }

    // Only method for unloading objects to game.
    public void UnLoadObject(GameObject object) {
        GameOutput.SendInfo("UnLoading object " + object + " from the game...");

        objects.remove(object);
        object.active = false;

        GameOutput.SendInfo("UnLoaded object " + object + " from the game!");
    }

    // Publicly only method for creating instance if not created.
    public static Game Create(GameSettings settings) {
        if (i == null)
            i = new Game(settings);
        return i;
    }

    // Publicly only method for getting instance.
    public static Game Get() {
        return i;
    }
}

如果您需要更多信息,请查看完整代码 GitHub:https://github.com/FilipeeX/GamerLibrary

这是我已经尝试过的方法:

至此,我完全陷入了困境,我不知道该怎么办。

当您构造 GameObject 实例时,您会将所有速度场初始化为静态 public 场,Vector2.zero。因此,GameObject 的每个实例都将有一个引用相同静态对象的速度场(即 Vector2.zero)。

因此,对一个实例速度的任何更改都会以相同的方式影响所有其他 GameObject 实例的速度。