package edu.gatech.cs2340.trydent.sample.lasagna; import java.util.ArrayList; import java.util.List; import javafx.scene.control.Label; import javafx.scene.input.KeyCode; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import edu.gatech.cs2340.trydent.Audio; import edu.gatech.cs2340.trydent.ContinuousEvent; import edu.gatech.cs2340.trydent.GameObject; import edu.gatech.cs2340.trydent.Keyboard; import edu.gatech.cs2340.trydent.Time; import edu.gatech.cs2340.trydent.TrydentEngine; import edu.gatech.cs2340.trydent.math.Position; import edu.gatech.cs2340.trydent.math.Vector; /** * A lasagna game. * */ public class LasagnaExample extends ContinuousEvent { private static final int WIDTH = 500; private static final int HEIGHT = 500; private static final int CELLS = 30; private static final int BW = WIDTH / CELLS; private static final int BH = HEIGHT / CELLS; private static final String BG_MUSIC = "edu/gatech/cs2340/trydent/sample/song.mp3"; private static final double INITIAL_VELOCITY_FACTOR = 2.5; private static final int SNAKE_SIZE = 25; private GameObject player; private List<GameObject> doges1; private List<GameObject> doges2; private List<GameObject> snake; private List<GameObject> paddles; private double startTime; private double time1 = 14; private double time2 = 28; private double time3 = 42; private double time4 = 56; private double velocityFactor; private boolean dead; private boolean started; public static void main(String[] args) { TrydentEngine.setWindowSize(WIDTH, HEIGHT); TrydentEngine.setWindowTitle("Lasagna Game (Instructions: arrow keys, space, r)"); TrydentEngine.start(); new LasagnaExample(); } Label l; @Override public void onStart() { TrydentEngine.setBackgroundColor(Color.BLACK); doges1 = new ArrayList<>(); doges2 = new ArrayList<>(); snake = new ArrayList<>(); paddles = new ArrayList<>(); restart(); } private void restart() { doges1.forEach(doge -> doge.destroy()); doges1.clear(); doges2.forEach(doge -> doge.destroy()); doges2.clear(); snake.forEach(part -> part.destroy()); snake.clear(); paddles.forEach(paddle -> paddle.destroy()); paddles.clear(); if(player != null) { player.destroy(); } dead = false; started = false; velocityFactor = INITIAL_VELOCITY_FACTOR; player = new GameObject(new Rectangle(BW, BH, Color.GRAY)); player.setLocalPosition(new Position((WIDTH - BW) / 2, (HEIGHT - BH) / 2)); initDoges(player, doges1, 0, 4, Color.RED); } private void start() { startTime = Time.getRealTimeSinceStartup(); Audio.resumeAudio(); Audio.setMasterVolume(0.15); Audio.setMusic(getClass().getClassLoader().getResource(BG_MUSIC).toString()); started = true; } private void die() { dead = true; Audio.pauseAudio(); player.setFill(Color.WHITE); } @Override public void onUpdate() { if(dead) { if(Keyboard.isKeyDown(KeyCode.R)) { restart(); } return; } else if(!started) { if(Keyboard.isKeyDown(KeyCode.SPACE)) { start(); } return; } keyboardInput(); if(Time.getRealTimeSinceStartup() - startTime > time1 && doges2.size() == 0) { initDoges(player, doges2, Math.PI/8, 8, Color.BLUE); } else if(Time.getRealTimeSinceStartup() - startTime > time2 && snake.size() == 0) { initSnake(snake); } else if(Time.getRealTimeSinceStartup() - startTime > time3 && paddles.size() == 0) { initPaddles(player, paddles); } else if(Time.getRealTimeSinceStartup() - startTime > time4 && INITIAL_VELOCITY_FACTOR == velocityFactor) { velocityFactor *= 2; } dogeAI(player, doges1, velocityFactor); dogeAI(player, doges2, velocityFactor); snakeAI(player, snake); paddleAI(player, paddles); for(GameObject doge : doges1) { if(intersectBlock(player.getPosition(), doge.getPosition())) { die(); } } for(GameObject doge : doges2) { if(intersectBlock(player.getPosition(), doge.getPosition())) { die(); } } for(GameObject part : snake) { if(intersectBlock(player.getPosition(), part.getPosition())) { die(); } } if(paddleIntersect(paddles)) { die(); } } private void keyboardInput() { if(Keyboard.isKeyDown(KeyCode.UP)) { player.translate(0, -1); } if(Keyboard.isKeyDown(KeyCode.DOWN)) { player.translate(0, 1); } if(Keyboard.isKeyDown(KeyCode.LEFT)) { player.translate(-1, 0); } if(Keyboard.isKeyDown(KeyCode.RIGHT)) { player.translate(1, 0); } clampGameObject(player); } private static void initPaddles(GameObject player, List<GameObject> paddles) { paddles.add(new GameObject(new Rectangle(BW, 5 * BH, Color.GOLD))); paddles.add(new GameObject(new Rectangle(5 * BW, BH, Color.GOLD))); paddles.add(new GameObject(new Rectangle(BW, 5 * BH, Color.GOLD))); paddles.add(new GameObject(new Rectangle(5 * BW, BH, Color.GOLD))); paddleAI(player, paddles); } private static void initSnake(List<GameObject> snake) { for(int i = 0; i < SNAKE_SIZE; i++) { Color color = i == 0 ? Color.LIGHTGREEN : Color.DARKGREEN; GameObject part = new GameObject(new Rectangle(BW, BH, color)); part.setPosition(new Position((WIDTH - BW) / 2, -BW * (i + 2))); snake.add(part); } } private static void initDoges(GameObject player, List<GameObject> doges, double initialTheta, int num, Color color) { double radius = num * Math.sqrt(BW * BW + BH * BH); Position center = player.getPosition(); for(int i = 0; i < num; i++) { double theta = i * 2.0 * Math.PI / num + initialTheta; GameObject doge = new GameObject(new Rectangle(BW, BH, color)); doge.setPosition(new Position( center.getX() - radius * Math.cos(theta), center.getY() - radius * Math.sin(theta))); doge.addFeature(new Vector(Math.cos(theta), Math.sin(theta)).rotate90()); doges.add(doge); } } private static void paddleAI(GameObject player, List<GameObject> paddles) { if(!paddles.isEmpty()) { Position center = player.getPosition(); paddles.get(0).setPosition(new Position(WIDTH - 3 * BW, center.getY() - 2 * BH)); paddles.get(1).setPosition(new Position(center.getX() - 2 * BW, 2 * BW)); paddles.get(2).setPosition(new Position(2 * BW, center.getY() - 2 * BH)); paddles.get(3).setPosition(new Position(center.getX() - 2 * BW, HEIGHT - 3 * BW)); } } private boolean paddleIntersect(List<GameObject> paddles) { if(paddles.isEmpty()) return false; Position playerPosition = player.getPosition(); return intersect(playerPosition, paddles.get(0).getPosition(), BW, 5 * BH) || intersect(playerPosition, paddles.get(1).getPosition(), 5 * BW, BH) || intersect(playerPosition, paddles.get(2).getPosition(), BW, 5 * BH) || intersect(playerPosition, paddles.get(3).getPosition(), 5 * BW, BH); } private static void snakeAI(GameObject player, List<GameObject> snake) { double snakeVelocity = 1.0; if(!snake.isEmpty()) { GameObject head = snake.get(0); Vector toPlayer = new Vector(head.getPosition(), player.getPosition()); toPlayer.scale(snakeVelocity/toPlayer.magnitude()); head.translate(toPlayer); for(int i = 1; i < snake.size(); i++) { GameObject prev = snake.get(i - 1); GameObject curr = snake.get(i); Vector toPrev = new Vector(curr.getPosition(), prev.getPosition()); toPrev.scale(snakeVelocity / toPrev.magnitude() / Math.sqrt(Math.sqrt(i))); curr.translate(toPrev); } } } private static void dogeAI(GameObject player, List<GameObject> doges, double velocityFactor) { double weightGoal = 1.0 / 50.0; double weightCurrent = 1.0 / 1.0; double weightOther = 1.0 / 1.0 / doges.size(); double velocity = velocityFactor / doges.size(); Position playerPosition = player.getPosition(); for(int i = 0; i < doges.size(); i++) { GameObject doge = doges.get(i); Position dogePosition = doge.getPosition(); Vector dogeVelocity = doge.getFeature(Vector.class); dogeVelocity.scale(weightCurrent / dogeVelocity.magnitude()); Vector toPlayer = new Vector(dogePosition, playerPosition); toPlayer.scale(weightGoal / toPlayer.magnitude()); dogeVelocity.add(toPlayer); for(int j = 0; j < doges.size(); j++) { if(i != j) { GameObject other = doges.get(j); Vector fromOther = new Vector(other.getPosition(), dogePosition); fromOther.scale(weightOther / fromOther.magnitudeSquared()); dogeVelocity.add(fromOther); } } dogeVelocity.scale(velocity / dogeVelocity.magnitude()); doge.translate(dogeVelocity); } } private static boolean intersectBlock(Position a, Position b) { return intersect(a, b, BW, BH); } private static boolean intersect(Position a, Position b, double width, double height) { return Math.min(a.getX() + BW, b.getX() + width) > Math.max(a.getX(), b.getX()) && Math.min(a.getY() + BH, b.getY() + height) > Math.max(a.getY(), b.getY()); } private static void clampGameObject(GameObject obj) { Position objPosition = obj.getPosition(); if(objPosition.getX() < 0) { objPosition.setX(0); } else if(objPosition.getX() > WIDTH - BW) { objPosition.setX(WIDTH - BW); } if(objPosition.getY() < 0) { objPosition.setY(0); } else if(objPosition.getY() > HEIGHT - BH) { objPosition.setY(HEIGHT - BH); } obj.setPosition(objPosition); } }