//Oppgavetekst: Lag et spill. import java.util.ArrayList; import java.util.Scanner; import java.util.Random; import java.io.Reader; import java.io.InputStreamReader; class Util { public static int randInt(int min, int max) { return (int)(Math.random() * (max - min) + min); } public static int randInt(int min, int max, int skip) { int i; do { i = randInt(min, max); } while (i != skip); return i; } public static void exit() { try { exec("stty sane entities) {} public void move() { pos.x += vel.x; pos.y += vel.y; } public void die() { dead = true; } public boolean collidesWith(Entity e) { if (dead || e.dead) return false; if (this == e) return false; return (pos.intX() == e.pos.intX() && pos.intY() == e.pos.intY()); } public String identify() { return identify("entity"); } public String identify(String name) { return "Entity "+img+" "+name+" at "+pos.x+", "+pos.y; } } class Player extends Entity { private boolean onGround; private static double speedOnGround = 1; private static double speedInAir = 0.3; private static double jumpSpeed = 2; private int shootCounter = 0; private int shootTimeout = 10; public Player(double x, double y, Arena a) { super(x, y, a); img = " "; color = "47"; onGround = false; } @Override public String identify() { return identify("player"); } public boolean shouldDieFromEnemy() { return true; } @Override public void die() { img = (char)27+"[37;41m#"+(char)27+"[0m"; arena.draw(); super.die(); System.out.println("You died!"); Util.exit(); } @Override public void update(ArrayList entities) { //Are we standing on anything? onGround = false; for (Entity e: entities) { if (e == this) continue; //For whether we're on ground or not, //we're only interested in blocks if (e instanceof Block && !onGround) { //We don't want to be stuck on ground if we're currently rising if (vel.y <= -0.5) continue; //Checking whether we collide on the X axis is simple if (e.pos.intX() != pos.intX()) continue; //Checking whether we collide on the Y axis is harder if ((e.pos.intY() == pos.intY() + 1) || ((e.pos.y <= pos.y + vel.y + 1) && (e.pos.y > pos.y))) { onGround = true; pos.y = e.pos.intY() - 1; vel.y = 0; } //Die if we touch an enemy. } else if (shouldDieFromEnemy() && e instanceof Enemy) { if (collidesWith(e)) { die(); } //Die if we touch a bullet } else if (e instanceof Bullet) { if (e.collidesWith(this)) { die(); } } } //Decrement shoot counter if (shootCounter > 0) shootCounter -= 1; //Die if we fall through the arena floor if (pos.y > arena.dimensions.y) die(); //Fall if not on ground if (!onGround) vel.y += 0.2; //Bounce off walls if (pos.intX() + vel.intX() < 0) { pos.x = 0; vel.x = -vel.x; } else if (pos.intX() + vel.intX() >= arena.dimensions.x) { pos.x = arena.dimensions.x - 1; vel.x = -vel.x; } //Turn velocity back to 0 over time vel.x *= 0.8; vel.y *= 0.9; } public void jump() { if (onGround) vel.y -= jumpSpeed; } public void moveLeft() { if (onGround) vel.x -= speedOnGround; else vel.x -= speedInAir; } public void moveRight() { if (onGround) vel.x += speedOnGround; else vel.x += speedInAir; } public void moveDown() { if (onGround) pos.y += 1; else vel.y += 0.4; } public void shoot() { if (shootCounter > 0) return; shootCounter = shootTimeout; Bullet b1 = new Bullet(pos.x, pos.y, -2, 0, this); Bullet b2 = new Bullet(pos.x - 1, pos.y, -2, 0, this); Bullet b3 = new Bullet(pos.x, pos.y, 2, 0, this); Bullet b4 = new Bullet(pos.x + 1, pos.y, 2, 0, this); arena.addEntity(b1); arena.addEntity(b2); arena.addEntity(b3); arena.addEntity(b4); } } class Enemy extends Player { private static double speedOnGround = 0.5; private enum Direction { LEFT, RIGHT } private Direction direction; public Enemy(double x, double y, Arena a) { super(x, y, a); img = " "; color = "41"; //Randomly start walking in a direction if (Util.randInt(0, 1) == 0) direction = Direction.LEFT; else direction = Direction.RIGHT; } @Override public String identify() { return identify("enemy"); } @Override public boolean shouldDieFromEnemy() { return false; } @Override public void die() { dead = true; } @Override public void update(ArrayList entities) { //Randomly decide to change direction if (Util.randInt(0, 7) == 0) { if (direction == Direction.LEFT) direction = Direction.RIGHT; else direction = Direction.LEFT; } //Randomly decide to jump if (Util.randInt(0, 23) == 0) { jump(); } //Randomly shoot if (Util.randInt(0, 20) == 0) { shoot(); } //Change direction if we get too close to the wall if (direction == Direction.LEFT && pos.x - 5 < 0) direction = Direction.RIGHT; else if (direction == Direction.RIGHT && pos.x + 5 > arena.dimensions.x) direction = Direction.LEFT; switch (direction) { case LEFT: moveLeft(); break; case RIGHT: moveRight(); break; } super.update(entities); } } class Bullet extends Entity { public Entity origin; public String originalImg; public String originalColor; private boolean dieNext = false; public Bullet(double x, double y, double vx, double vy, Entity o) { super(x, y, o.arena); originalImg = "*"; originalColor = o.color.replace("4", "3")+";1"; img = originalImg; color = originalColor; vel.x = vx; vel.y = vy; origin = o; } @Override public String identify() { return identify("bullet (origin: "+origin.identify()+")"); } @Override public void update(ArrayList entities) { if (dieNext) { die(); return; } Entity collision = null; for (Entity e: entities) { if (e.collidesWith(this)) collision = e; //The bullet should die the next tick if it hits anything if (e != this && !(e instanceof Bullet) && collidesWith(e)) { dieNext = true; } } //If the bullet has hit anything, we want it to look like what it hit if (collision != null) { img = collision.img; color = collision.color; } else { img = originalImg; color = originalColor; } } @Override public boolean collidesWith(Entity e) { if (e == origin) return false; else return super.collidesWith(e); } } class Block extends Entity { public Block(int x, int y, Arena a) { super(x, y, a); img = " "; color = "42"; } @Override public String identify() { return identify("block"); } } class Arena { public Vec2 dimensions; public ArrayList entities; private final String ANSI_CLS = "\u001b[2J"; private final String ANSI_HOME = "\u001b[H"; public Arena(int width, int height) { dimensions = new Vec2(width, height); entities = new ArrayList(); } public void addEntity(Entity e) { entities.add(e); } public void update() { //Move entities for (int i = entities.size() - 1; i >= 0; --i) { Entity e = entities.get(i); if (e.dead) { entities.remove(i); } else { e.move(); } } //Update entities boolean enemiesLeft = false; for (int i = entities.size() - 1; i >= 0; --i) { Entity e = entities.get(i); e.update(entities); if (e instanceof Enemy) enemiesLeft = true; } if (!enemiesLeft) { System.out.println("No enemies left! You win!"); Util.exit(); } } public void draw() { String str = "\r\n\r\n\r\n"; //Create draw list String[][] drawList = new String[dimensions.intX()][dimensions.intY()]; for (Entity e: entities) { if (!e.dead && e.pos.x >= 0 && e.pos.intX() < dimensions.intX() && e.pos.y >= 0 && e.pos.intY() < dimensions.intY()) { drawList[e.pos.intX()][e.pos.intY()] = (char)27+"["+e.color+"m"+e.img+(char)27+"[0m"; } } //Create the horizontal line at the top and bottom of the arena String horLine = ""; for (int i = 0; i < dimensions.x; ++i) { horLine += "-"; } //Append horizontal line to top str += " "+horLine+"\r\n"; //Draw entities for (int y = 0; y < dimensions.y; ++y) { str += "|"; for (int x = 0; x < dimensions.x; ++x) { String img = drawList[x][y]; if (img == null) str += " "; else str += img; } str += "|\r\n"; } //Append horizontal line to bottom str += " "+horLine+"\r\n"; //Print the drawn arena //System.out.print(ANSI_CLS + ANSI_HOME + str); System.out.print(str); } public void generateWorld() { //Create a floor for the player to stand o for (int i = 0; i < dimensions.intX(); ++i) { Block b = new Block(i, dimensions.intY() - 3, this); addEntity(b); } int prevX = dimensions.intX() / 2; int prevY = dimensions.intY() - 3; //We want to spawn enemies and such after the terrain ArrayList toAdd = new ArrayList(); //Generate the random terrain while (prevY > 0) { //Create a random coordinate for the next platform int nextX = Util.randInt( prevX - (int)(dimensions.x / 3), prevX + (int)(dimensions.x / 3) ); int nextY = Util.randInt( prevY + 1, prevY - 3 ); //platforms should have random width int width = Util.randInt(3, 12); //We don't want to make platforms outside of the arena if (nextX < 0) nextX = 0; else if (nextX >= (int)dimensions.x - width) nextX = (int)dimensions.x - 1 - width; //Add the platform block for (int i = 0; i < width; ++i) { Block b = new Block(nextX + i, nextY, this); addEntity(b); } //Randomly decide to spawn an enemy on top if (Util.randInt(0, 3) == 0) { Enemy e = new Enemy(nextX, nextY - 1, this); toAdd.add(e); } prevX = nextX; prevY = nextY; } //Now that terrain is created, add enemies and such for (Entity e: toAdd) { addEntity(e); } } } class MinOppgave2 { private static Arena arena; static int[] KEY_EXIT = {3}; static int[] KEY_ENTER = {13}; static int[] KEY_LEFT = {27, 91, 68}; static int[] KEY_RIGHT = {27, 91, 67}; static int[] KEY_UP = {27, 91, 65}; static int[] KEY_DOWN = {27, 91, 66}; static int[] keyLog = new int[3]; static Player player; public static void main(String[] args) throws Exception { Scanner s = new Scanner(System.in); //Get arena dimensions System.out.println("Insert arena width\r"); int width = s.nextInt(); System.out.println("Insert arena height\r"); int height = s.nextInt(); //Show controls System.out.println(" ------------------------------- "); System.out.println("| Controls: |"); System.out.println("| ctrl+C: Exit |"); System.out.println("| Left/Right: Move left/right |"); System.out.println("| Up: Jump |"); System.out.println("| Down: Descend |"); System.out.println("| Enter: Shoot |"); System.out.println(" ------------------------------- "); s.nextLine(); s.nextLine(); System.out.println("Generating world..."); //Unix specific hackc to set the terminal to raw mode Util.exec("stty raw