|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641 |
- //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 </dev/tty");
- } catch (Exception e) {
- //No need to catch the exception; we'll just exit anyways
- } finally {
- System.exit(0);
- }
- }
-
- public static void exec(String str) throws Exception {
- String[] cmd = {"/bin/sh", "-c", str};
- Runtime.getRuntime().exec(cmd).waitFor();
- }
- }
-
- class Vec2 {
- public double x;
- public double y;
-
- public Vec2(double vx, double vy) {
- x = vx;
- y = vy;
- }
-
- //It's sometimes useful to get the X and Y value as
- //rounded integers
- public int intX() {
- return (int)Math.round(x);
- }
- public int intY() {
- return (int)Math.round(y);
- }
- }
-
- class Entity {
- public String img;
- public String color;
- public Vec2 pos;
- public Vec2 vel;
- public Arena arena;
- public boolean dead;
- public Entity origin; //For entities which are spawned by other entities
-
- public Entity(double x, double y, Arena a) {
- pos = new Vec2(x, y);
- vel = new Vec2(0, 0);
- arena = a;
- dead = false;
- }
-
- public void update(ArrayList<Entity> 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<Entity> 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<Entity> 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<Entity> 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<Entity> 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<Entity>();
- }
-
- 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<Entity> toAdd = new ArrayList<Entity>();
-
- //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 </dev/tty");
-
- //Initiate arena and generate the world
- arena = new Arena(width, height);
- arena.generateWorld();
-
- //Create our player
- player = new Player(width / 2, height - 5, arena);
- arena.addEntity(player);
-
- //Game loop
- arena.update();
- arena.draw();
- Reader r = new InputStreamReader(System.in);
- while (true) {
- logKey(r.read());
-
- if (wasKeyPressed(KEY_EXIT)) {
- Util.exit();
- } else if (wasKeyPressed(KEY_LEFT)) {
- player.moveLeft();
- } else if (wasKeyPressed(KEY_RIGHT)) {
- player.moveRight();
- } else if (wasKeyPressed(KEY_UP)) {
- player.jump();
- } else if (wasKeyPressed(KEY_ENTER)) {
- player.shoot();
- } else if (wasKeyPressed(KEY_DOWN)) {
- player.moveDown();
- } else {
- //Don't do anything if an unbound key was pressed;
- //just redraw the a rena to get rid of garbage characters
- arena.draw();
- continue;
- }
-
- arena.update();
- arena.draw();
- }
- }
-
- private static void logKey(int c) {
- for (int i = 0; i < keyLog.length - 1; ++i) {
- keyLog[i] = keyLog[i + 1];
- }
- keyLog[keyLog.length - 1] = c;
- }
-
- private static boolean wasKeyPressed(int[] key) {
- int offset = (keyLog.length - key.length);
- for (int i = offset; i < keyLog.length; ++i) {
- if (key[i - offset] != keyLog[i])
- return false;
- }
- return true;
- }
- }
|