我正在制作 java 2d 游戏库,使用 JSFML 作为基础。
最近发现了一个大问题。我在游戏中的所有对象都在扩展抽象类GameObject
,其中包含对象的位置、速度、大小和名称等内容。
所有加载的对象都存储在Game
处理游戏的类实例中。
现在的问题是:每次玩家移动时,随之而来的一切都会移动。
例如,如果我用 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();
}
以下是球员和场地课程:
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;
}
}
这是游戏类:
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
这是我已经尝试过的:
- 我尝试检查渲染一段代码,但没有任何问题。
- 我还删除了半个库只是为了尽可能简化事情,但即使它很简单,一切都应该正常工作,仍然......什么都没有。
在这一点上,我完全被卡住了,我不知道该怎么办。