1

I'm making java 2d game library, using JSFML as base.

Lately I found a big problem. All of my objects in game, are extending abstract class GameObject, that contains stuff like position, velocity, size and name of object.

All loaded objects are stored in Game class instance, that handlers the game.

Now the problem is: Every time player moves, everything with it moves too.

For example, if I move player with w, a, s, d keys, it won't move only player, but the floor moves too.

Here's code from user's perspective:

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();
}

Here are player and floor 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;
    }
}

Here's the game 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;
    }
}

Entire code is on GitHub if you need more information: https://github.com/FilipeeX/GamerLibrary

Here's what I already tried:

  • I tried checking rendering piece of code, but there's nothing wrong.
  • I also removed half a library just to simplify things as much as possible, but even if it's simple, everything should be working normally, still.. nothing.

At this point, I'm completely stuck I don't know what to do.

Federico klez Culloca
  • 26,308
  • 17
  • 56
  • 95
FilipeeX
  • 13
  • 2
  • Please trim your code to make it easier to find your problem. Follow these guidelines to create a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). – Community Sep 01 '21 at 09:48

1 Answers1

0

When you are constructing GameObject instances, you are initializing all of the velocity fields to the static public field, Vector2.zero. So every instance of a GameObject will have a velocity field that references the same static object (i.e. Vector2.zero).

Thus any change to one instance's velocity will affect every other GameObject instance's velocity in the same way.

Scrubbie
  • 1,360
  • 1
  • 11
  • 25