diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..0193f04 Binary files /dev/null and b/.DS_Store differ diff --git a/assets/Sprite-0001.ase b/assets/Sprite-0001.ase new file mode 100644 index 0000000..533020a Binary files /dev/null and b/assets/Sprite-0001.ase differ diff --git a/assets/Sprite-0001.png b/assets/Sprite-0001.png new file mode 100644 index 0000000..cfe6194 Binary files /dev/null and b/assets/Sprite-0001.png differ diff --git a/assets/Sprite-0002.ase b/assets/Sprite-0002.ase new file mode 100644 index 0000000..3123978 Binary files /dev/null and b/assets/Sprite-0002.ase differ diff --git a/assets/Sprite-bob.png b/assets/Sprite-bob.png new file mode 100644 index 0000000..b2fd12c Binary files /dev/null and b/assets/Sprite-bob.png differ diff --git a/assets/Sprite-robi.png b/assets/Sprite-robi.png new file mode 100644 index 0000000..c6474f1 Binary files /dev/null and b/assets/Sprite-robi.png differ diff --git a/assets/Sprite-robiwithbob.png b/assets/Sprite-robiwithbob.png new file mode 100644 index 0000000..85f49c2 Binary files /dev/null and b/assets/Sprite-robiwithbob.png differ diff --git a/assets/Sprite-saege.png b/assets/Sprite-saege.png new file mode 100644 index 0000000..019212a Binary files /dev/null and b/assets/Sprite-saege.png differ diff --git a/assets/idle_motor.mp3 b/assets/idle_motor.mp3 new file mode 100644 index 0000000..810e129 Binary files /dev/null and b/assets/idle_motor.mp3 differ diff --git a/assets/main_music.wav b/assets/main_music.wav new file mode 100644 index 0000000..d45242e Binary files /dev/null and b/assets/main_music.wav differ diff --git a/assets/mixkit-atv-engine-motor-hum-1553.mp3 b/assets/mixkit-atv-engine-motor-hum-1553.mp3 new file mode 100644 index 0000000..37bfa34 Binary files /dev/null and b/assets/mixkit-atv-engine-motor-hum-1553.mp3 differ diff --git a/collect.pde b/collect.pde new file mode 100644 index 0000000..0b3a58a --- /dev/null +++ b/collect.pde @@ -0,0 +1,39 @@ +// Tarek +class Collectable { + float cwidth, cheight; + boolean is_attached = false; + PVector pos = new PVector(); + + Collectable(float xpos, float ypos, float cw, float ch) { + pos.x = xpos; + pos.y = ypos; + cwidth = cw; + cheight = ch; + } +} + +class Saw extends Collectable { + + Saw(float x, float y, float cw, float ch) { + super(x, y, cw, ch); + } + + void drawSaw() { + if (!is_attached) { + image(saw_sprite, pos.x, pos.y); + } + } +} + +class Bob extends Collectable { + + Bob(float x, float y, float cw, float ch) { + super(x, y, cw, ch); + } + + void drawBob() { + if (!is_attached) { + image(bob_sprite, pos.x, pos.y); + } + } +} diff --git a/files.pde b/files.pde new file mode 100644 index 0000000..07b0024 --- /dev/null +++ b/files.pde @@ -0,0 +1,33 @@ +// Marla +class Files { + + boolean checkSaveFile(String filepath) { + return new File(dataPath(filepath)).exists(); + } + + void loadJson(String jsonfile) { + // if (!checkSaveFile(jsonfile)) { + try { + JSONArray values = loadJSONArray(jsonfile); + + stats_menu.best_game_time = values.getInt(0); + stats_menu.trees_sawed = values.getInt(1); + stats_menu.game_time = values.getInt(2); + println("Savefile found"); + + } catch (Exception e) { + println("Savefile not found"); + } + } + + JSONArray json; + void savetofile(String filename) { + json = new JSONArray(); + + json.setInt(0, stats_menu.best_game_time); + json.setInt(1, stats_menu.trees_sawed); + json.setInt(2, millis() + stats_menu.game_time); + saveJSONArray(json,"./saves/" + filename + ".json"); + } + +} diff --git a/keys.pde b/keys.pde new file mode 100644 index 0000000..d8abbc4 --- /dev/null +++ b/keys.pde @@ -0,0 +1,46 @@ +boolean NORTH, SOUTH, ROTATEL, ROTATER; + +// Julia, Max +void keyPressed() { + if (key == CODED) { + if(keyCode == UP) { + NORTH = true; + if(!idle_motor.isPlaying()) idle_motor.play(); + } else if (keyCode == DOWN) { + SOUTH = true; + } else if (keyCode == LEFT) { + ROTATEL = true; + } else if (keyCode == RIGHT) { + ROTATER = true; + } + } else if (key == 's') { // SAW + if (ship_zero.hasSaw) { + Log target_log = logs[ship_zero.nextLog]; + if(checkDistance(target_log, ship_zero) < 40) { + target_log.sawed = true; + stats_menu.trees_sawed = stats_menu.trees_sawed + 1; + } + } + // Marla + // Pause menu + } else if (keyCode == ESC){ + key = 0; + if (isgame) { + isgame = false; + ispause = true; + } + } +} + +// Julia +void keyReleased() { + if(keyCode == UP) {NORTH = false; } + else if (keyCode == DOWN) SOUTH = false; + else if (keyCode == LEFT) {ROTATEL = false; } + else if (keyCode == RIGHT) {ROTATER = false; } +} + +boolean mouse_released = false; +void mouseReleased() { + mouse_released = true; +} diff --git a/level.pde b/level.pde new file mode 100644 index 0000000..f0e977a --- /dev/null +++ b/level.pde @@ -0,0 +1,17 @@ +// Julia, Max + +// Outside wall +Log[] walls = {new Log(-30, 275, 40, 275, false, true), new Log(-30, 600, 40, 275, false, true)}; + +void create_level(int logcount) { + logs = new Log[logcount]; + randomSeed((int)random(0, 30)); + for (int i = 1; i < logs.length; i++) { + logs[i] = new Log((int) random(20, width), (int) random(0, height), 20, 60 + random(0, 40), true, false); + } + // 2nd slide entry + logs[0] = new Log(-15, 325, 10, 50, false, true); + + // debug log + logs[1] = new Log(-300, 100, 20, 100, true, false); +} diff --git a/logs.pde b/logs.pde new file mode 100644 index 0000000..a4600ea --- /dev/null +++ b/logs.pde @@ -0,0 +1,58 @@ +class Log { + float x, y, logwidth, logheight; + boolean sawed = false; + boolean is_tree = false; + boolean is_wall = false; + float a = 0; + boolean render_log = true; + + color logcolor; + color strokecolor = logcolor; + + Log (float xpos, float ypos, float logw, float logh, boolean ist, boolean isw) { + x = xpos; + y = ypos; + logwidth = logw; + logheight = logh; + is_tree = ist; + is_wall = isw; + //draw(); + } + + // Tarek + void drawLog(int logtext) { + if (sawed) { + logcolor = color(128, 88, 60); + if (a > -90) a = a - 1; + if (a == -90) render_log = false; + } else if (is_wall) { + logcolor = color(0, 0, 0); + } else { + logcolor = color(133, 79, 51); + } + + if (render_log) { + pushMatrix(); + translate(x, y); + rotate(radians(a)); + stroke(strokecolor); // Set stroke color for the log + strokeWeight(1); // Set stroke weight for the log + fill(logcolor); // Set fill color for the log + rect(0, 0, logwidth, -logheight); // Draw the log as a rectangle + // text(logtext, x, y); + strokeWeight(1); + stroke(0); + + // Bush + if(is_tree) { + color bushes = color(107, 117, 48); + fill(bushes); + ellipse(0 + logwidth/2, 0 - logheight, 170*0.3, 160*0.3); + } + + popMatrix(); + } + + + } +} diff --git a/menu.pde b/menu.pde new file mode 100644 index 0000000..aa3fd23 --- /dev/null +++ b/menu.pde @@ -0,0 +1,175 @@ +class Menus { + + boolean drawRectWithMouseColission(float x, float y, float rectwidth, float rectheight) { + // Draw A Rect + rectMode(CENTER); + rect(x, y, rectwidth, rectheight); + rectMode(CORNER); + + // Check it for collission + if((mouseX > x - rectwidth/2 && mouseX < x + rectwidth/2) && (mouseY > y - rectheight/2 && mouseY < y + rectheight/2)) { + return true; + } else { + return false; + } + } + +} + +// Julia +class MainMenu extends Menus { + + void playButton(float x, float y, float w, float h) { + fill(100, 100, 100); + if(drawRectWithMouseColission(x, y, w, h) && mousePressed) { + ismenu = false; + ispause = false; + isgame = true; + } + fill(0); + textAlign(CENTER, CENTER); + textSize(32); + text("Play", x, y); + } + + void statsButton(float x, float y, float w, float h) { + fill(100, 100, 100); + if(drawRectWithMouseColission(x, y, w, h) && mousePressed) { + ismenu = false; + isstats = true; + } + fill(0); + textAlign(CENTER, CENTER); + textSize(32); + text("Stats", x, y); + } + + void drawMenu() { + background(40); + // color maincolor = color(100, 100, 100); + playButton(300, 300, 150, 50); + statsButton(300, 400, 150, 50); + + textSize(100); + textAlign(CENTER, CENTER); + text("Save Bob", 300, 200); + } + + void draw() { + println("test"); + } +} + +class EndMenu extends Menus { + + void menuButton(float x, float y, float w, float h) { + fill(100, 100, 100); + if(drawRectWithMouseColission(x, y, w, h) && mousePressed) { + ismenu = true; + ispause = false; + isgame = false; + } + fill(0); + textAlign(CENTER, CENTER); + textSize(32); + text("Menu", x, y); + } + + void drawMenu() { + background(40); + // color maincolor = color(100, 100, 100); + menuButton(300, 350, 150, 50); + + textSize(100); + textAlign(CENTER, CENTER); + if (ship_zero.health < 1) { + text("You Died", 300, 200); + } + } +} + +// Julia, Max, Marla, Chris +class Stats extends Menus { + int trees_sawed = 0; + int best_game_time = 0; + int game_time = 0; + + void menuButton() { + fill(100, 100, 100); + if(drawRectWithMouseColission(300, 300, 150, 50) && mouse_released) { + ismenu = true; + isgame = false; + isstats = false; + } + fill(0); + textSize(32); + textAlign(CENTER, CENTER); + text("Main Menu", 300, 300); + } + + void draw() { + background(50); + menuButton(); + + textAlign(LEFT); + textSize(24); + text("Best Game Time", 100, 50); + text(best_game_time, 500, 50); + text("Trees Sawed: " , 100, 70); + text(trees_sawed, 500, 70); + text("Insgesamt Spielzeit", 100, 90); + int sek = game_time/1000; + int min = game_time/1000/60; + int minsek = sek % 60; + text(min + ":" + minsek, 500, 90); + } +} + +// Chris +class StopWatchTimer { + int startTime = 0, stopTime = 0, pauseTime = 0; + boolean running = false; + boolean pause = false; + + + void start() { + startTime = millis(); + running = true; + } + void stop() { + stopTime = millis(); + running = false; + } + void pause_start() { + if (!pause) { + pauseTime = millis(); + pause = true; + } + } + void resume() { + if (pause) { + startTime = startTime + (millis() - pauseTime); + pauseTime = 0; + pause = false; + } + } + int getElapsedTime() { + int elapsed; + if (running) { + elapsed = (millis() - startTime); + } + else { + elapsed = (stopTime - startTime); + } + return elapsed; + } + int second() { + return (getElapsedTime() / 1000) % 60; + } + int minute() { + return (getElapsedTime() / (1000*60)) % 60; + } + int hour() { + return (getElapsedTime() / (1000*60*60)) % 24; + } +} diff --git a/processing_sim.pde b/processing_sim.pde new file mode 100644 index 0000000..9e1217e --- /dev/null +++ b/processing_sim.pde @@ -0,0 +1,198 @@ +import processing.sound.*; + +float checkDistance(Log log, Ship ship) { + float testX = ship.pos.x; + float testY = ship.pos.y; + + // which edge is closest? + if (ship.pos.x < log.x) testX = log.x; + else if (ship.pos.x > log.x+log.logwidth) testX = log.x+log.logwidth; + if (ship.pos.y < log.y - log.logheight) testY = log.y - log.logheight; + else if (ship.pos.y > log.y) testY = log.y; + + // get distant + float distX = ship.pos.x-testX; + float distY = ship.pos.y-testY; + float distance = sqrt( (distX*distX) + (distY*distY) ); + + // Debug Lines + // line(testX, testY, ship.pos.x, ship.pos.y); + + // if the distance is less than the radius, collision! + return distance; +} + +// Main Game entry +// Chris, Julia, Marla, Tarek, Max +void play() { + background(75, 105, 47); + + + // Timer + fill(0); + textSize(24); + text(playtime.second(), 40, 20); + text(playtime.second(), -580, 20); + + // Tutorial + textAlign(LEFT); + textSize(16); + text("You are a robot that has to save Bob. He is stuck in the forest.", -570, 160); + text("Here is a chainsaw to get through", -570, 180); + + ship_zero.draw(); + saw_zero.drawSaw(); + ship_zero.collect(saw_zero); + bob.drawBob(); + ship_zero.collect(bob); + + // draw wall + for(int i = 0; i < walls.length; i++) { + walls[i].drawLog(i); + } + // draw log + for(int i = 0; i < logs.length; i++) { + logs[i].drawLog(i); + } + // log normal stroke + for(int i = 0; i < logs.length; i++) { + logs[i].strokecolor = logs[i].logcolor; + } + // nearest log stroke (debug) + logs[ship_zero.nextLog].strokecolor = color(255, 0, 0); +} + +// ----- + + +// global state +boolean isgame = false; +boolean ismenu = true; +boolean isend = false; +boolean isstats = false; +boolean ispause = false; +boolean start_slide = true; + +// ----- Objectives +MainMenu main_menu = new MainMenu(); +Stats stats_menu = new Stats(); +EndMenu end_menu = new EndMenu(); + +Log[] logs; + +// player +Ship ship_zero; + +// collectables +Saw saw_zero; +Bob bob; + +// stopwatch +StopWatchTimer playtime = new StopWatchTimer(); +Files savefile = new Files(); + + +PImage player_sprite; +PImage player_sprite_bob; +PImage saw_sprite; +PImage bob_sprite; + +SoundFile idle_motor; +SoundFile music; + + +void setup() { + size(600, 600); + textAlign(CENTER, CENTER); + + create_level(30); + println(logs[1]); + + ship_zero = new Ship(); + saw_zero = new Saw(-width+100, 100, 20, 50); + bob = new Bob(500, 400, 20, 40); + + // Marla + player_sprite = loadImage("./assets/Sprite-robi.png"); + player_sprite_bob = loadImage("./assets/Sprite-robiwithbob.png"); + saw_sprite = loadImage("./assets/Sprite-saege.png"); + bob_sprite = loadImage("./assets/Sprite-bob.png"); + + idle_motor = new SoundFile(this, "./assets/idle_motor.mp3"); + music = new SoundFile(this, "./assets/main_music.wav"); + + savefile.loadJson("./saves/save.json"); + + music.loop(1, 0.5); +} + +// Chris, Max +void draw() { + // time debug + // println(millis(), " start: ", playtime.startTime, " pause: ", playtime.pauseTime); + + // game state + if (isgame) { + + + // Go to second or first slide + if(ship_zero.pos.x > 0) { + start_slide = false; + } else { + start_slide = true; + } + + // actually move the camera + if(start_slide) { + translate(600, 0); + } else { + translate(0, 0); + } + + // Main Entry + play(); + + // Timer + if (playtime.running) {} else playtime.start(); + if (playtime.pause) playtime.resume(); + + // Win + if(bob.is_attached && dist(ship_zero.pos.x, ship_zero.pos.y ,-400, 300) < 100) { + isgame = false; + isend = true; + } + fill(150, 0, 0, 50); + ellipse(-400, 300, 200, 200); + + } else if (ismenu){ + // menu code + // play(); + main_menu.drawMenu(); + if (playtime.running) playtime.stop(); + } else if (isstats) { + stats_menu.draw(); + } else if (isend) { + // end screen code + end_menu.drawMenu(); + + // get into right state + ship_zero.health = 150; + ship_zero.pos.x = -width/2; + ship_zero.pos.y = height/2; + bob.is_attached = false; + saw_zero.is_attached = false; + create_level(30); + ship_zero.hasSaw = false; + + + // save + if(playtime.second() < stats_menu.best_game_time) stats_menu.best_game_time = playtime.second(); + savefile.savetofile("save"); + } else if (ispause) { + main_menu.drawMenu(); + + if (playtime.running && playtime.pause == false) playtime.pause_start(); + } + + mouse_released = false; +} diff --git a/readme.org b/readme.org new file mode 100644 index 0000000..230cd79 --- /dev/null +++ b/readme.org @@ -0,0 +1,23 @@ +** Ingame +*** DONE Level mit 2 Bereichen. Erster Bereich Straße und Kettensäge und End/Startpunkt. Zweiter Bereich Wald und Bob +*** DONE Robi muss noch beschleunigen können +*** DONE setze bob auf den Robi +*** DONE Wir brauchen Geräusche +*** DONE Richtige Texte am Anfang zum erklären +*** DONE End menu +*** DONE Game neustarten können +*** DONE Roboter muss kaputt gehen können +** Menu +*** DONE Statistikseite: Spielzeit, Bäume gefällt, Zeit gestoppt +*** DONE Richtige Texte im Menu +*** DONE File loading and saving +Wird noch nicht benutzt +*** DONE nochmal die statistikseite überarbeiten +**** DONE Math for best_game_time +**** TODO Why doesnt bestgametime work +** TODO Stats neu machen + +** Vllt +*** TODO Abprallen nicht machen, wenn newx nicht erreicht sein kann, sondern wenn Robi tatsächlich die Wand berührt +*** TODO Roboter muss abprallen, kaputt gehen +*** BUG sometimes a log gets stuck in sawed = false state diff --git a/saves/save.json b/saves/save.json new file mode 100644 index 0000000..97f2c01 --- /dev/null +++ b/saves/save.json @@ -0,0 +1,5 @@ +[ + 0, + 13, + 205455 +] \ No newline at end of file diff --git a/ship.pde b/ship.pde new file mode 100644 index 0000000..a257e59 --- /dev/null +++ b/ship.pde @@ -0,0 +1,178 @@ +class Ship { + // Movement + PVector pos = new PVector(-width/2, height/2); // position + PVector speed = new PVector(0, 0); // The speed of movement + PVector acceleration = new PVector(); + float a; // angle + + // For the collision + PVector newPos = new PVector(width/2, height/2); + + float newX, newY; + boolean colliding = false; + boolean colliding_logs = false; + boolean hasSaw = false; + int nextLog; + + int health = 150; + + Ship() { + // pos.x = width/2; + // pos.y = height/2; + + a = 0; + newX = width/2; + newY = height/2; + } + + // Tarek + void draw() { + nextLog = returnIndexOfNearestLog(); + + logCollide(logs); + logCollide(walls); + + + sawIndicator(); + simulate(); + render(); + + // println(newX, " : ", newY); + + if (health == 0) { + isgame = false; + isend = true; + } + + colliding_logs = false; + } + + // Max, julia + void sawIndicator() { + if (hasSaw) { + if (checkDistance(logs[nextLog], ship_zero) < 40) { + fill(204, 102, 0); + circle(pos.x, pos.y -20, 20); + fill(0); + textSize(32); + textAlign(CENTER, CENTER); + text("s", pos.x, pos.y - 27); + } + } + } + + // Max + int returnIndexOfNearestLog() { + float shortest_distance_log_distance = checkDistance(logs[0], ship_zero); + int shortest_distance_log = 0; + for(int i = 0; i < logs.length; i++) { + // only logs that are not sawed already + if (!logs[i].sawed) { + if(checkDistance(logs[i], ship_zero) < shortest_distance_log_distance) { + shortest_distance_log = i; + shortest_distance_log_distance = checkDistance(logs[i], ship_zero); + } + } + } + return shortest_distance_log; + } + + // Max + void simulate() { + // First do the Math but dont move something + + // Rotate PLayer + if (ROTATEL) { + a -= 0.03; + } + if (ROTATER) { + a += 0.03; + } + PVector direction = new PVector(); + direction.x = cos(a); + direction.y = sin(a); + direction.mult(0.07); + + + acceleration = direction; + + // add speed if pressing NORTH + if(NORTH) { + speed.add(acceleration); + speed.limit(1.3); + } else if (SOUTH) { + speed.mult(0.80); + } else { // decrease it if not + speed.mult(0.90); + } + + + // Check new pos + newPos = pos.add(speed); + + // Collide with outside walls + if( newPos.x > width || newPos.y < 0 || newPos.y > height) { + colliding = true; + // println("collide"); + } else { + colliding = false; + } + + // Check if the new position is within the bounds of the screen + // - Handle it more like https://processing.org/examples/circlecollision.html + if(colliding == false && colliding_logs == false) { + pos.add(speed); + } else { + speed.limit(0); + speed.sub(acceleration); + pos.add(0, 0); + pos.add(speed.mult(2)); + + health = health - 1; + } + // println(speed); + } + + // Tarek + void logCollide(Log[] loggers) { + for(int i = 0; i < loggers.length; i++) { + if(loggers[i].sawed == false) { + if (newPos.x+10 > loggers[i].x && newPos.x-10 < loggers[i].x + loggers[i].logwidth && newPos.y+10 > loggers[i].y - loggers[i].logheight && newPos.y-10 < loggers[i].y) { + colliding_logs = true; + } + } + } + } + + // Tarek, Marla + void collect(Collectable c) { + if (pos.dist(c.pos) < 20) { + if (c.getClass() == Saw.class ) hasSaw = true; + c.is_attached = true; + } + } + + void render() { + + pushMatrix(); + translate(pos.x, pos.y); + rotate(a); + stroke(255); + noFill(); + // line(0, -10, 10, 10); + // line(10, 10, 0, 5); + // line(0, 5, -10, 10); + // line(-10, 10, 0, -10); + // triangle(- 5, - 5, - 5, 5, 10, 0); + imageMode(CENTER); + if(bob.is_attached) { + image(player_sprite_bob, 0, 0); + } else { + image(player_sprite, 0, 0); + } + if(hasSaw) { + image(saw_sprite, 20, 0); + } + popMatrix(); + } +}