diff --git a/src/main/java/com/openeggbert/core/OpenEggbertApp.java b/src/main/java/com/openeggbert/core/OpenEggbertApp.java new file mode 100644 index 0000000..47501a7 --- /dev/null +++ b/src/main/java/com/openeggbert/core/OpenEggbertApp.java @@ -0,0 +1,391 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// Open Eggbert: Free recreation of the computer game Speedy Eggbert. +// Copyright (C) 2024 the original author or authors. +// +// This program is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation, either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see +// or write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +/////////////////////////////////////////////////////////////////////////////////////////////// +package com.openeggbert.core; + +import com.almasb.fxgl.app.ApplicationMode; +import com.almasb.fxgl.app.GameApplication; +import com.almasb.fxgl.app.GameSettings; +import com.almasb.fxgl.core.collection.PropertyMap; +import com.almasb.fxgl.dsl.FXGL; +import com.almasb.fxgl.entity.Entity; +import javafx.scene.input.KeyCode; +import javafx.scene.paint.Color; +import javafx.scene.text.Text; +import java.util.Map; + +import static com.almasb.fxgl.dsl.FXGL.*; +import com.almasb.fxgl.entity.components.CollidableComponent; +import com.almasb.fxgl.physics.CollisionHandler; +import com.openeggbert.entity.common.EntityType; +import java.io.File; +import java.util.function.BiFunction; +import java.util.function.Supplier; +import javafx.geometry.Rectangle2D; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.StackPane; +import javafx.scene.shape.Circle; +import javafx.util.Duration; + +/** + * @author Robert Vokac + * @since 0.0.0 + */ +public class OpenEggbertApp extends GameApplication { + + private Entity player; + private Entity coin; + + @Override + protected void initSettings(GameSettings settings) { + settings.setWidth(640); + settings.setHeight(480); + settings.setTitle("Open Eggbert"); + settings.setVersion("0.0.0-SNAPSHOT"); + settings.setApplicationMode(ApplicationMode.DEVELOPER); + } + private static int r = 0; + + @Override + protected void initInput() { + int width = Companion.getAppWidth(); + int height = Companion.getAppHeight(); + PropertyMap state = FXGL.getWorldProperties(); +// if(state.keys().contains("x")) { +// int x = state.getInt("x"); +// int y = state.getInt("y"); + + onKey(KeyCode.RIGHT, () -> { + checkXAndMovePlayerIfNeeded(); + player.translateX(move); // move right 5 pixels + inc("pixelsMoved", +move); + inc("x", +move); + r++; + System.out.println("Pressed RIGHT " + r); + lastPress = System.nanoTime(); + if (lastStart == 0) { + lastStart = lastPress; + } else { + if (move < 20) { + move = move + 4; + } + if ((lastPress - lastStart) > 5000000000l) { +// move = 5; + lastStart = 0; + } + } + + }); + + onKey(KeyCode.LEFT, () -> { + checkXAndMovePlayerIfNeeded(); + player.translateX(-move); // move left 5 pixels + inc("pixelsMoved", -move); + inc("x", -move); + lastPress = System.nanoTime(); + if (lastStart == 0) { + lastStart = lastPress; + } else { + if (move < 20) { + move++; + } + if ((lastPress - lastStart) > 5000000000l) { +// move = 5; + lastStart = 0; + } + } + }); + + onKey(KeyCode.UP, () -> { + checkYAndMovePlayerIfNeeded(); + player.translateY(-move); // move up 5 pixels + inc("pixelsMoved", +move); + inc("y", -move); + lastPress = System.nanoTime(); + if (lastStart == 0) { + lastStart = lastPress; + } else { + if (move < 20) { + move++; + } + if ((lastPress - lastStart) > 5000000000l) { +// move = 5; + lastStart = 0; + } + } + }); + + onKey(KeyCode.DOWN, () -> { + checkYAndMovePlayerIfNeeded(); + player.translateY(move); // move down 5 pixels + inc("pixelsMoved", -move); + inc("y", +move); + lastPress = System.nanoTime(); + if (lastStart == 0) { + lastStart = lastPress; + } else { + if (move < 20) { + move++; + } + if ((lastPress - lastStart) > 5000000000l) { +// move = 5; + lastStart = 0; + } + } + }); + } + private static int move = 5; + private static long lastPress = 0l; + private static long lastStart = 0l; + + private void checkXAndMovePlayerIfNeeded() { + double diff = player.getX() - coinX; + if (diff < 300 && diff > 0) { + move = 10; + + coin.translateX((diff < 0 ? 1 : (-1)) * randomNumberSource.apply(2, 8)); + coinX = coin.getX(); + if (coinX < 20) { + coin.setX(620); + } + if (coinX > 620) { + coin.setX(20); + } + } + + if (player != null && player.getX() < 0) { + player.setX(620); + inc("x", (int) (620 + (-player.getX()))); + } + if (player != null && player.getX() > 640) { + player.setX(20); + inc("x", (int) (20 - player.getX())); + } + } + + private void checkYAndMovePlayerIfNeeded() { + double diff = player.getY() - coinY; + + if (diff < 300 && diff > 0) { + move = 10; + coin.translateY((diff < 0 ? 1 : (-1)) * randomNumberSource.apply(2, 8)); + coinY = coin.getY(); + + if (coinY < 20) { + coin.setY(460); + } + if (coinY > 460) { + coin.setY(20); + } + } + + if (player != null && player.getY() < 0) { + player.setY(460); + inc("y", (int) (460 + (-player.getY()))); + } + if (player != null && player.getY() > 480) { + player.setY(20); + inc("y", (int) (20 - player.getY())); + } + + } + + @Override + protected void initGameVars(Map vars) { + vars.put("pixelsMoved", 0); + vars.put("x", 0); + vars.put("y", 0); + vars.put("coins", 0); + vars.put("seconds", 0); + getGameTimer().runAtInterval(() -> { + inc("seconds", +1); + }, Duration.seconds(1)); + + getGameTimer().runAtInterval(() -> { + if (coin != null && coin.isActive()) { + + double translateX = (Math.random() > 0.5 ? 1 : (-1)) * randomNumberSource.apply(2, 10); + double newX = coinX + translateX; + if (newX < 10) { + translateX = 20;newX = coinX + translateX; + } + if (newX > 460) { + translateX = -20;newX = coinX + translateX; + } + coinX = newX; + coin.translateX(translateX); + + + double translateY = (Math.random() > 0.5 ? 1 : (-1)) * randomNumberSource.apply(2, 10); + double newY = coinY + translateY; + if (newY < 10) { + translateY = 20;newY = coinY + translateY; + } + if (newY > 630) { + translateX = -20;newY = coinY + translateY; + } + coinY = newY; + coin.translateY((Math.random() > 0.5 ? 1 : (-1)) + randomNumberSource.apply(2, 10)); + } + }, Duration.millis(20)); + } + + private BiFunction randomNumberSource = (min, max) -> (min + ((int) (Math.random() * (max < min ? min : (max - min))))); + + private static double currentX, currentY, coinX, coinY; + + @Override + protected void initGame() { + int rectancleSide = 10 + ((int) (Math.random() * 40d)); + Supplier randomByteSupplier = () -> (randomNumberSource.apply(0, 255)); + + PropertyMap state = FXGL.getWorldProperties(); + + final double x = Math.random() * 600; + final double y = Math.random() * 400; + state.setValue("x", (int) x); + state.setValue("y", ((int) y)); + + ImageView blupiView = createBlupiView(); + + player = entityBuilder() + .type(EntityType.PLAYER) + .at(x, y) + // .viewWithBBox(new Rectangle(rectancleSide, rectancleSide, Color.rgb( + // randomByteSupplier.get(), + // randomByteSupplier.get(), + // randomByteSupplier.get() + // ))) + .viewWithBBox(blupiView) + // .viewWithBBox("brick.png") + .with(new CollidableComponent(true)) + .buildAndAttach(); + + spawnNewCoin(); + + } + + private Circle createCoin() { + int value = random(1, 5); + final Circle circle = new Circle(15, 15, 15 + value, Color.YELLOW); + final Text text = new Text(String.valueOf(value)); + final StackPane stack = new StackPane(); + stack.getProperties().put("coinValue", value); + circle.getProperties().put("coinValue", value); + stack.getChildren().addAll(circle, text); + return circle; + } + + @Override + protected void initPhysics() { + getPhysicsWorld().addCollisionHandler(new CollisionHandler(EntityType.PLAYER, EntityType.COIN) { + + // order of types is the same as passed into the constructor + @Override + protected void onCollisionBegin(Entity player, Entity coin) { + coin.removeFromWorld(); + inc("coins", +coin.getProperties().getInt("coinValue")); + move = 5; + spawnNewCoin(); + } + }); + } + + @Override + protected void initUI() { + Text textPixels = new Text(); + textPixels.setTranslateX(50); + textPixels.setTranslateY(100); + textPixels.textProperty().bind(getWorldProperties().intProperty("pixelsMoved").asString()); + + Text x = new Text(); + x.setTranslateX(150); + x.setTranslateY(100); + x.textProperty().bind(getWorldProperties().intProperty("x").asString()); + + Text y = new Text(); + y.setTranslateX(250); + y.setTranslateY(100); + y.textProperty().bind(getWorldProperties().intProperty("y").asString()); + + Text coins = new Text(); + coins.setTranslateX(350); + coins.setTranslateY(100); + coins.textProperty().bind(getWorldProperties().intProperty("coins").asString()); + + Text seconds = new Text(); + seconds.setTranslateX(450); + seconds.setTranslateY(100); + seconds.textProperty().bind(getWorldProperties().intProperty("seconds").asString()); + + getGameScene().addUINode(textPixels); + getGameScene().addUINode(x); + getGameScene().addUINode(y); + getGameScene().addUINode(coins); + getGameScene().addUINode(seconds); + + var brickTexture = getAssetLoader().loadTexture("brick.png"); + brickTexture.setTranslateX(50); + brickTexture.setTranslateY(450); + + getGameScene().addUINode(brickTexture); + } + + public static void main(String[] args) { + + launch(args); + } + + private void spawnNewCoin() { + final Circle coinCircle = createCoin(); + int coinValue = (int) coinCircle.getProperties().get("coinValue"); + final Integer x = randomNumberSource.apply(40, 600); + final Integer y = randomNumberSource.apply(40, 400); + coinX = x; + coinY = y; + Entity newCoin = entityBuilder() + .type(EntityType.COIN) + .at(x, y) + .viewWithBBox(coinCircle) + // .viewWithBBox(createBlupiView()) + .with("coinValue", coinValue) + .with(new CollidableComponent(true)) + .buildAndAttach(); + coin = newCoin; + PropertyMap state = FXGL.getWorldProperties(); + + getGameTimer().runOnceAfter(() -> { + if (newCoin.isActive()) { + newCoin.removeFromWorld(); + spawnNewCoin(); + inc("coins", -coinValue); + } + }, Duration.seconds(randomNumberSource.apply(5, 15))); + } + + private ImageView createBlupiView() { + final String im = new File("/home/robertvokac/Desktop/speedy_eggbert/speedy_eggbert_I/IMAGE08/blupi000.blp").toURI().toString(); + Image image = new Image(im, false); + ImageView result = new ImageView(image); + result.setViewport(new Rectangle2D(165, 118, 30, 47)); + return result; + } + +}