Skip to content

Commit

Permalink
Game loop
Browse files Browse the repository at this point in the history
  • Loading branch information
jjohannes committed Jan 15, 2024
1 parent 0ebd5bf commit 75eec6c
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 46 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci-build.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: "CI Build"

on: [ push, pull_request ]
on: [ push ]

jobs:
check:
Expand Down
3 changes: 0 additions & 3 deletions .oj/patch/non-modules.properties
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,3 @@ spring.boot.starter.tomcat=org.springframework.boot:spring-boot-starter-tomcat

jul.to.slf4j=!org.slf4j:jul-to-slf4j
jakarta.annotation=!org.apache.tomcat:tomcat-annotations-api

#FIXME workaround for https://github.com/gradlex-org/extra-java-module-info/pull/94
java.xml=!org.springframework.boot:spring-boot-dependencies
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package software.onepiece.javarcade.engine;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class GameLoop {

private ScheduledExecutorService exec;
private GameState gameState;


public void run(GameState gameState) {
this.gameState = gameState;
exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(this::update, 0, 20, TimeUnit.MILLISECONDS);
}

private void update() {
if (gameState.isUp()) {
gameState.getPlayer().moveUp(gameState.state, gameState.inhabitants);
}
if (gameState.isDown()) {
gameState.getPlayer().moveDown(gameState.state, gameState.inhabitants);
}
if (gameState.isLeft()) {
gameState.getPlayer().moveLeft(gameState.state, gameState.inhabitants);
}
if (gameState.isRight()) {
gameState.getPlayer().moveRight(gameState.state, gameState.inhabitants);
}
}

public void stop() {
exec.shutdown();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package software.onepiece.javarcade.engine;

import software.onepiece.javarcade.model.Inhabitant;
import software.onepiece.javarcade.model.Spot;

import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class GameState {

private boolean up;
private boolean down;
private boolean left;
private boolean right;

private Spot player;
public final Map<Character, Inhabitant> inhabitants = new LinkedHashMap<>();
public final List<Spot> state = new LinkedList<>();

public boolean isUp() {
return up;
}

public void setUp(boolean up) {
this.up = up;
}

public boolean isDown() {
return down;
}

public void setDown(boolean down) {
this.down = down;
}

public boolean isLeft() {
return left;
}

public void setLeft(boolean left) {
this.left = left;
}

public boolean isRight() {
return right;
}

public void setRight(boolean right) {
this.right = right;
}

public Spot getPlayer() {
return player;
}

public void setPlayer(Spot player) {
this.player = player;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import com.fasterxml.jackson.jakarta.rs.json.annotation.JSONP;
import jakarta.activation.CommandObject;
import jakarta.activation.DataHandler;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
Expand All @@ -13,21 +13,20 @@
import javafx.stage.Stage;
import org.example.lib.Lib;
import org.slf4j.LoggerFactory;
import software.onepiece.javarcade.engine.GameLoop;
import software.onepiece.javarcade.engine.GameState;
import software.onepiece.javarcade.model.Inhabitant;
import software.onepiece.javarcade.model.Level;
import software.onepiece.javarcade.model.Spot;

import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;

import static java.util.Objects.requireNonNull;
import static software.onepiece.javarcade.model.Spot.MATRIX_HEIGHT;
import static software.onepiece.javarcade.model.Spot.MATRIX_WIDTH;
import static software.onepiece.javarcade.model.Spot.PRECISION;

public class Main extends Application {
// Services:
Expand Down Expand Up @@ -57,49 +56,63 @@ public static void main(String[] args) {
private static final int WIDTH = SCALE * (GAME_WIDTH + CELL_WIDTH * 2);
private static final int HEIGHT = SCALE * GAME_HEIGHT;

private final Map<Character, Inhabitant> inhabitants = new LinkedHashMap<>();
private final List<Spot> state = new LinkedList<>();
private Spot player;

private final GameState gameState = new GameState();

@Override
public void start(Stage stage) {
Canvas canvas = new Canvas(WIDTH, HEIGHT);
GraphicsContext ctx = canvas.getGraphicsContext2D();
ctx.setImageSmoothing(false);

ServiceLoader.load(Inhabitant.class).forEach(inhabitant -> inhabitants.put(inhabitant.getRef(), inhabitant));
ServiceLoader.load(Inhabitant.class).forEach(inhabitant -> gameState.inhabitants.put(inhabitant.getRef(), inhabitant));
ServiceLoader.load(Level.class).forEach(level -> level.render().forEach(spot -> {
Inhabitant inhabitant = inhabitants.get(spot.getInhabitantRef());
Inhabitant inhabitant = gameState.inhabitants.get(spot.getInhabitantRef());
images.put(spot.getInhabitantRef(), imageFor(inhabitant.getImage()));
if (inhabitant.controllable()) {
player = spot;
state.addLast(spot);
gameState.setPlayer(spot);
gameState.state.addLast(spot);
} else {
state.addFirst(spot);
gameState.state.addFirst(spot);
}
}));

draw(ctx);

StackPane pane = new StackPane(canvas);
Scene scene = new Scene(pane, WIDTH, HEIGHT);

scene.setOnKeyPressed(e -> {
switch (e.getCode()) {
case UP -> player.moveUp(state, inhabitants);
case DOWN -> player.moveDown(state, inhabitants);
case LEFT -> player.moveLeft(state, inhabitants);
case RIGHT -> player.moveRight(state, inhabitants);
case UP -> gameState.setUp(true);
case DOWN -> gameState.setDown(true);
case LEFT -> gameState.setLeft(true);
case RIGHT -> gameState.setRight(true);
case X -> System.out.println("Boom!");
}
draw(ctx);
});
scene.setOnKeyReleased(e -> {
switch (e.getCode()) {
case UP -> gameState.setUp(false);
case DOWN -> gameState.setDown(false);
case LEFT -> gameState.setLeft(false);
case RIGHT -> gameState.setRight(false);
case X -> System.out.println("Boom!");
}
});


new Label("L1");
stage.setTitle("JavArcade");
stage.setScene(scene);
stage.show();
stage.setResizable(false);

new GameLoop().run(gameState);
new AnimationTimer() {
@Override
public void handle(long now) {
draw(ctx);
}
}.start();
}


Expand All @@ -111,10 +124,10 @@ private void draw(GraphicsContext ctx) {
ctx.clearRect(CELL_WIDTH * SCALE, 0, WIDTH, HEIGHT);

for (int y = 0; y < MATRIX_HEIGHT; y++) {
drawSprite(leftWall, 0, y, ctx);
drawSprite(rightWall, 1 + MATRIX_WIDTH, y, ctx);
drawSprite(leftWall, 0, y * PRECISION, ctx);
drawSprite(rightWall, (1 + MATRIX_WIDTH) * PRECISION, y * PRECISION, ctx);
}
state.forEach(s -> drawSprite(images.get(s.getInhabitantRef()), s.getX() + 1, s.getY(), ctx));
gameState.state.forEach(s -> drawSprite(images.get(s.getInhabitantRef()), s.getX() + PRECISION, s.getY(), ctx));
}

private Image imageFor(InputStream stream) {
Expand All @@ -128,7 +141,10 @@ private void drawSprite(Image img, int x, int y, GraphicsContext ctx) {
if (img == null) {
return;
}
ctx.drawImage(img, x * CELL_WIDTH * SCALE, y * CELL_HEIGHT * SCALE, CELL_WIDTH * SCALE, CELL_HEIGHT * SCALE);
ctx.drawImage(img,
(x * CELL_WIDTH * SCALE) * 1f / PRECISION,
(y * CELL_HEIGHT * SCALE) * 1f / PRECISION,
CELL_WIDTH * SCALE, CELL_HEIGHT * SCALE);
}

@JSONP
Expand Down
38 changes: 21 additions & 17 deletions model/src/main/java/software/onepiece/javarcade/model/Spot.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import java.util.Map;

public class Spot {
public static final int PRECISION = 1000;

public static final int MATRIX_WIDTH = 14;
public static final int MATRIX_HEIGHT = 14;

Expand All @@ -12,16 +14,18 @@ public class Spot {
private int x;
private int y;

private int speed = 150;

public Spot(char inhabitantRef, int x, int y) {
this.inhabitantRef = inhabitantRef;
this.x = x;
this.y = y;
this.x = PRECISION * x;
this.y = PRECISION * y;
}

public Spot(char inhabitantRef, int posInStream) {
this.inhabitantRef = inhabitantRef;
this.y = posInStream / MATRIX_HEIGHT;
this.x = posInStream - y * MATRIX_WIDTH;
this(inhabitantRef,
posInStream - (posInStream / MATRIX_HEIGHT) * MATRIX_WIDTH,
posInStream / MATRIX_WIDTH);
}

public char getInhabitantRef() {
Expand All @@ -37,40 +41,40 @@ public int getY() {
}

public void moveRight(List<Spot> state, Map<Character, Inhabitant> inhabitants) {
if (state.stream().anyMatch(s -> s.getX() == x + 1 && s.getY() == y && inhabitants.get(s.getInhabitantRef()).blocks())) {
if (state.stream().anyMatch(s -> s.getX()/PRECISION == x/PRECISION + 1 && s.getY()/PRECISION == y/PRECISION && inhabitants.get(s.getInhabitantRef()).blocks())) {
return;
}
x++;
if (x >= MATRIX_WIDTH) {
x = MATRIX_WIDTH - 1;
x += speed;
if (x >= (MATRIX_WIDTH - 1) * PRECISION) {
x = (MATRIX_WIDTH - 1) * PRECISION;
}
}

public void moveLeft(List<Spot> state, Map<Character, Inhabitant> inhabitants) {
if (state.stream().anyMatch(s -> s.getX() == x - 1 && s.getY() == y && inhabitants.get(s.getInhabitantRef()).blocks())) {
if (state.stream().anyMatch(s -> s.getX()/PRECISION == x/PRECISION - 1 && s.getY()/PRECISION == y/PRECISION && inhabitants.get(s.getInhabitantRef()).blocks())) {
return;
}
x--;
x -= speed;
if (x < 0) {
x = 0;
}
}

public void moveDown(List<Spot> state, Map<Character, Inhabitant> inhabitants) {
if (state.stream().anyMatch(s -> s.getX() == x && s.getY() == y + 1 && inhabitants.get(s.getInhabitantRef()).blocks())) {
if (state.stream().anyMatch(s -> s.getX()/PRECISION == x/PRECISION && s.getY()/PRECISION == y/PRECISION + 1 && inhabitants.get(s.getInhabitantRef()).blocks())) {
return;
}
y++;
if (y >= MATRIX_HEIGHT) {
y = MATRIX_HEIGHT - 1;
y += speed;
if (y >= (MATRIX_HEIGHT - 1) * PRECISION) {
y = (MATRIX_HEIGHT - 1) * PRECISION;
}
}

public void moveUp(List<Spot> state, Map<Character, Inhabitant> inhabitants) {
if (state.stream().anyMatch(s -> s.getX() == x && s.getY() == y - 1 && inhabitants.get(s.getInhabitantRef()).blocks())) {
if (state.stream().anyMatch(s -> s.getX()/PRECISION == x/PRECISION && s.getY()/PRECISION == y/PRECISION - 1 && inhabitants.get(s.getInhabitantRef()).blocks())) {
return;
}
y--;
y -= speed;
if (y < 0) {
y = 0;
}
Expand Down
2 changes: 1 addition & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ pluginManagement {
repositories.maven { url = 'https://plugins.gradle.org/m2' }
repositories.maven { url = 'https://gradle.onepiece.software:1443/releases' }
}
plugins { id 'software.onepiece.j' version '0.0.15' }
plugins { id 'software.onepiece.j' version '0.0.16' }

0 comments on commit 75eec6c

Please sign in to comment.