From b848b0534b2a971c2d38174371382a0489088913 Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Sun, 20 Jan 2019 19:26:15 +0100 Subject: [PATCH] entities, improved pathfinding errorhandling --- CitizenClass.pde | 169 ++++++++++++++++++++++++----------------------- Entities.pde | 68 +++++++++++++++++++ citizen.pde | 34 +++++++--- 3 files changed, 177 insertions(+), 94 deletions(-) create mode 100644 Entities.pde diff --git a/CitizenClass.pde b/CitizenClass.pde index dda2074..a6a281e 100644 --- a/CitizenClass.pde +++ b/CitizenClass.pde @@ -1,38 +1,41 @@ import java.lang.Double; -int i_citizenAmount = 5; +int i_citizenAmount = 10; +int i_selectedCitizen; int i_femaleCount; + Citizen[] citizen = new Citizen[i_citizenAmount]; void initCitizen() { //namen: ethuriel, nathaniel, loriel, samuel, aluriel, aleriel, thaliel, suriel, kaliel, //int[][] claireArray = { { 00, 2 }, { 1, 3} }; - citizen[0] = new Citizen(800, "Test", 0,27); + citizen[0] = new Citizen(800, "Test", 0, 27); citizen[1] = new Citizen(121, "Matze", 1, 28); citizen[2] = new Citizen(18, "Freddy", 1, 28); citizen[3] = new Citizen(59, "Korbi", 1, 28); citizen[4] = new Citizen(121, "Lotte", 1, 26); - //citizen[5] = new Citizen(18, "Reifi", 1, 26); - //citizen[6] = new Citizen(59, "Grasso", 1, 28); - //citizen[7] = new Citizen(121, "Nico", 1, 29); - //citizen[8] = new Citizen(18, "Victor", 1, 28); - //citizen[9] = new Citizen(59, "Paul", 1, 28); + citizen[5] = new Citizen(18, "Reifi", 1, 26); + citizen[6] = new Citizen(59, "Grasso", 1, 28); + citizen[7] = new Citizen(121, "Nico", 1, 29); + citizen[8] = new Citizen(18, "Victor", 1, 28); + citizen[9] = new Citizen(59, "Paul", 1, 28); for (int i = 10; i < i_citizenAmount; i++) { int gender = int(random(0, 2)); if (gender == 0) i_femaleCount++; int age = int(random(0, 100)); citizen[i] = new Citizen(int(random(0, houses.size())), S_citizenNames[gender][int(random(0, S_citizenNames[gender].length))], gender, age); } + for (int i = 0; i < citizen.length; i++) { + if (i != i_selectedCitizen) + citizen[i].spawn(citizen[i].i_home); + else citizen[i].spawn(100,100); - for (int i = 0; i < citizen.length; i++) { - citizen[i].spawn(citizen[i].i_home); + if (citizen[i].b_randomRun) citizen[i].goTo(int(random(0, pg_map.width)), int(random(0, pg_map.height))); //bad } - selectCitizen(0); } -int i_selectedCitizen; void selectCitizen(int i) { citizen[i_selectedCitizen].b_randomRun = true; citizen[i_selectedCitizen].b_moving = true; @@ -45,27 +48,22 @@ void selectCitizen(int i) { i_selectedCitizen = i; } -class Citizen { - int i_xSpawn, i_ySpawn, i_diameter; - boolean b_linked; - boolean b_moving; - int i_home; - String S_name; - float f_xPos, f_yPos; - float f_movementSpeed; - boolean b_selected; +class Citizen extends Entity { int i_gender; String S_gender; int i_age; - boolean b_randomRun = true; - //0-100: - //motivation (bei arbeiter montag ~40, freitag ~80 - 100) - //7 emotionen? + int i_home; + float f_movementSpeed; + boolean b_randomRun; - // berufsfeld: webdesigner, pädagoge, schmuckdesigner, schmied - // berufsstatus: beamter, selbstständiger, unternehmer, angestellter, grundschüler, gymnasiast, hauptschüler, realschüler, azubi, student, rentner + GraphNode startNode, endNode; + int startNodeID, endNodeID; + GraphNode[] rNodes; + // ArrayList rNodesList = new ArrayList(); + int nextNode; - // identität: gelbhemd, lokal, regional, national, international, fremd, + IGraphSearch pathFinder; + int pathAlgorithm = i_pathAlgorithm; Citizen(int home, String name, int gender, int age) { i_home = home; @@ -76,29 +74,37 @@ class Citizen { i_diameter = 15; pathFinder = makePathFinder(gs, pathAlgorithm); f_movementSpeed = random(0.1, 2); + rNodes = pathFinder.getRoute(); + + c_selected = color(128, 50, 50); + c_color = color(0, 0, 0); + c_stroke = color(255, 255, 255); } - - void spawn(int house) { - PVector v2_spawnPoint = houses.get(house).v2_randomSpawnPoint(); - i_xSpawn = int(v2_spawnPoint.x); - i_ySpawn = int(v2_spawnPoint.y); - f_xPos = i_xSpawn; - f_yPos = i_ySpawn; - rNodes = pathFinder.getRoute(); - - if (b_randomRun) goTo(int(random(0, pg_map.width)), int(random(0, pg_map.height))); - b_linked = true; + //citizen kann "lookat" mit 180° winkel mit bullseye förmigen gradient welches die chance etwas zu bemerken darstellt + void lookAt (Entity entity) { } + //citizen kann "focus", guckt mit den augen in die richtung. 2. augen-vektor! kopf wird mitgedreht je nach "openness" + //citizen kann "take", nimmt gegenstand in die hand. arraylist "holds" - gegenstände in der hand - void despawn() { - b_linked = false; - } + //entitiy-subklassen: papier + + //setFocus(entity) durch geräusche auch von objekten ausserhalb des sichtfeldes aufrufbar + //je nachdem wie hoch der derzeitige fokus ist wird es schwerer, ihn abzulenken. + //intrinsischer fokus korreliert mit joy/motivation/positive erinnerung an etwas + + //zur welt: + // + + //0-100: + //motivation (bei arbeiter montag ~40, freitag ~80 - 100) + //7 emotionen? + + // berufsfeld: webdesigner, pädagoge, schmuckdesigner, schmied + // berufsstatus: beamter, selbstständiger, unternehmer, angestellter, grundschüler, gymnasiast, hauptschüler, realschüler, azubi, student, rentner + + // identität: gelbhemd, lokal, regional, national, international, fremd, - boolean b_moveDiagonally() { - if (int(rNodes[nextNode].xf()) != int(f_xPos) && int(rNodes[nextNode].yf()) != int(f_yPos)) return true; - else return false; - } int i_direction(float f, float v) { if (f <= 0-v) return -1; else if (f >= 0+v) return 1; @@ -107,17 +113,13 @@ class Citizen { void update() { if (b_moving) { //if rNodes.length > 0 if (rNodes.length > nextNode) { - float f_xPosNext = rNodes[nextNode].xf(); float f_yPosNext = rNodes[nextNode].yf(); - float f_movementVelo = f_movementSpeed; - - if (b_moveDiagonally()) f_movementVelo = f_movementVelo / 1.41; + //slow down movement velocity if moving diagnoally + if (int(rNodes[nextNode].xf()) != int(f_xPos) && int(rNodes[nextNode].yf()) != int(f_yPos)) f_movementVelo = f_movementVelo / 1.41; f_xPos += i_direction(f_xPosNext-f_xPos, f_movementVelo) * f_movementVelo; f_yPos += i_direction(f_yPosNext-f_yPos, f_movementVelo) * f_movementVelo; - - if (abs(f_yPos - f_yPosNext) < f_movementVelo && abs(f_xPos - f_xPosNext) < f_movementVelo) { f_yPos = f_yPosNext; f_xPos = f_xPosNext; @@ -135,7 +137,7 @@ class Citizen { } } - void display() { + void debug() { //draw Route if (rNodes.length >= 2 && (b_drawPathLine || b_drawPathDestination)) { pg_map.pushStyle(); @@ -145,7 +147,7 @@ class Citizen { pg_map.noFill(); for (int i = 1; i < rNodes.length; i++) pg_map.line(rNodes[i-1].xf(), rNodes[i-1].yf(), rNodes[i].xf(), rNodes[i].yf()); - } + } //draw destination if (b_drawPathDestination) { pg_map.stroke(160, 0, 0); if (b_selected) pg_map.fill(255, 0, 0); @@ -154,37 +156,36 @@ class Citizen { } pg_map.popStyle(); } - pg_map.stroke(255); - pg_map.fill(0); - if (b_selected) pg_map.fill(c_selectedCitizen); - pg_map.ellipse(f_xPos, f_yPos, i_diameter, i_diameter); - pg_map.fill(255); - pg_map.textAlign(CENTER); - pg_map.textSize(10); - pg_map.text(S_name, f_xPos, f_yPos-10); } - GraphNode startNode, endNode; - int startNodeID, endNodeID; - GraphNode[] rNodes; - ArrayList rNodesList = new ArrayList(); - int nextNode; - - IGraphSearch pathFinder; - int pathAlgorithm = i_pathAlgorithm; - void goTo(int x, int y) { //add: go to node? go to house? - float nodeDistance = 1.0f; - while (gs.getNodeAt(f_xPos, f_yPos, 0, nodeDistance) == null) { - nodeDistance++; + int i_goToX = x; + int i_goToY = y; + int spread = 0; + boolean findingWay = false; + + while (!findingWay) { + float nodeDistance = 1.0f; + findingWay = true; + while (gs.getNodeAt(f_xPos, f_yPos, 0, nodeDistance) == null) { + nodeDistance++; + } + startNodeID = gs.getNodeAt(f_xPos, f_yPos, 0, nodeDistance).id(); + nodeDistance = 1.0f; + while (gs.getNodeAt(i_goToX, i_goToY, 0, nodeDistance) == null) { + nodeDistance++; + } + endNodeID = gs.getNodeAt(i_goToX, i_goToY, 0, nodeDistance).id(); + + if (pathFinder.search(startNodeID, endNodeID, true) == null) { + findingWay = false; + spread += 10; + i_goToX+= spread; + i_goToY+= spread; + } } - startNodeID = gs.getNodeAt(f_xPos, f_yPos, 0, nodeDistance).id(); - nodeDistance = 1.0f; - while (gs.getNodeAt(x, y, 0, nodeDistance) == null) { - nodeDistance++; - } - endNodeID = gs.getNodeAt(x, y, 0, nodeDistance).id(); + pathFinder.search(startNodeID, endNodeID, true); //returns null if no route is found @@ -193,11 +194,11 @@ class Citizen { if (rNodes.length > 0) { nextNode = 0; b_moving = true; - - for (int i = 0; i < rNodes.length; i++) { - rNodesList.add(rNodes[i]); - } - } else { + //for (int i = 0; i < rNodes.length; i++) { + // rNodesList.add(rNodes[i]); + //} + } else { //implement more intelligent design which calls goTo not in this frame (this can cause infinite loops), but in the next 120 frames or so + //also at this point i can move recalculating the nodes into the next frames if no route is found (not only random).. if (b_randomRun) goTo(int(random(0, pg_map.width)), int(random(0, pg_map.height))); } } diff --git a/Entities.pde b/Entities.pde new file mode 100644 index 0000000..1fa1bf4 --- /dev/null +++ b/Entities.pde @@ -0,0 +1,68 @@ +int i_interactableAmount = 10; + +Interactable[] interactables = new Interactable[10]; + + +void initInteractables() { + for (int i = 0; i < interactables.length; i++) { + interactables[i] = new Interactable("Interactable", "Content"); + } + for (int i = 0; i < interactables.length; i++) { + interactables[i].spawn(citizen[int(random(0, citizen.length))].i_home); + } +} + + +class Entity { + String S_name; + boolean b_linked; + boolean b_selected; + boolean b_moving; + float f_xPos, f_yPos, f_xSpawn, f_ySpawn; + int i_diameter = 10; //ellipse representation on map + int i_nameSize = 12; + color c_selected = color(128, 50, 50); + color c_color = color(50, 200, 80); + color c_stroke = color(255, 255, 255); + + void spawn(int house) { + PVector v2_spawnPoint = houses.get(house).v2_randomSpawnPoint(); + f_xSpawn = v2_spawnPoint.x; + f_ySpawn = v2_spawnPoint.y; + f_xPos = f_xSpawn; + f_yPos = f_ySpawn; + b_linked = true; + } + void spawn(int x, int y) { + f_xSpawn = x; + f_ySpawn = y; + f_xPos = f_xSpawn; + f_yPos = f_ySpawn; + b_linked = true; + } + void despawn() { + b_linked = false; + } + + void display() { + pg_map.stroke(c_stroke); + pg_map.fill(c_color); + if (b_selected) pg_map.fill(c_selected); + pg_map.ellipse(f_xPos, f_yPos, i_diameter, i_diameter); + pg_map.fill(c_stroke); + pg_map.textAlign(CENTER); + pg_map.textSize(i_nameSize); + pg_map.text(S_name, f_xPos, f_yPos-10); + } +} + + +class Interactable extends Entity { + + Interactable(String name, String description) { + S_name = name; + } + + void update() { + } +} diff --git a/citizen.pde b/citizen.pde index 4ec46ec..46623f3 100644 --- a/citizen.pde +++ b/citizen.pde @@ -2,7 +2,7 @@ boolean b_smallerImage = false; //use a cropped, smaller version of the 1920x1080 image for faster development boolean b_loadSun = false; //load sun from web-api instead of local json file (local file is adressed to january 4th 2019. might implement a check that downloads today's information only once... boolean b_drawNodes = false; -boolean b_drawPathLine = false; +boolean b_drawPathLine = true; boolean b_drawPathDestination = true; boolean b_cameraFollow = true; boolean b_autoPlayAfterSelect = false; @@ -12,11 +12,15 @@ int i_debugTextSize = 10; int i_mapW, i_mapH; int i_windowW, i_windowH; int i_viewportW, i_viewportH; -color c_selectedCitizen = color(128, 50, 50); + //void mousePressed() { // citizen[0].goTo(constrain(mouseX, 0, img_houses.width), constrain(mouseY, 0, img_houses.height)); //} +void spawnCitizen() { //happens after construction + +} + void setup() { size(700, 600); @@ -27,8 +31,12 @@ void setup() { if (b_smallerImage) img_houses = loadImage(dataPath("map/houses_with_borders_small.png")); else img_houses = loadImage(dataPath("map/houses_with_borders.png")); img_streets = loadImage(dataPath("map/streets.png")); - + pg_map = createGraphics(img_houses.width, img_houses.height); + pg_map.beginDraw(); + //pg_map.blendMode(MULTIPLY); + pg_map.endDraw(); + surface.setResizable(true); registerMethod("pre", this); @@ -40,6 +48,7 @@ void setup() { initPathFinding(); initWeather(); initCitizen(); + initInteractables(); initUI(); } @@ -58,32 +67,37 @@ void draw() { background(127); pg_map.beginDraw(); + pg_map.background(127); - pg_map.image(img_map, 0, 0, img_houses.width, img_houses.height); + pg_map.image(img_houses, 0, 0, img_houses.width, img_houses.height); //pg_map.image(img_houses, 0, 0, img_houses.width, img_houses.height); //image(img_streets, 0, 0, img_houses.width, img_houses.height); pg_map.fill(0); - //pg_map.textSize(7); - //pg_map.textAlign(CENTER); + pg_map.textSize(7); + pg_map.textAlign(CENTER); //for (House house : houses) { // house.display(); //} if (b_drawNodes) drawNodes(); + for (int i = 0; i < interactables.length; i++) { + interactables[i].update(); + interactables[i].display(); + } + for (int i = 0; i < citizen.length; i++) { if (citizen[i].b_linked) { citizen[i].update(); if (i != i_selectedCitizen) - citizen[i].display(); + //citizen[i].display(); + citizen[i].debug(); } } citizen[i_selectedCitizen].display(); - + pg_map.endDraw(); image(pg_map, i_mapOffsetX, i_mapOffsetY, i_mapW, i_mapH); drawUI(); - - }