int TILE_NONE = 0; int TILE_WALL = 2; int TILE_CIEL = 1; int TILE_GOAL = -1; int TILE_FROG = 3; int frogW = 17, frogH = 32; //int frogW = 10, frogH = 16; class Level { int w, h; int[] tiles; ArrayList frogs; boolean goalReached; int activeGender; boolean hasWater; int waterHeight; int timeStart; int xyToI(int x, int y) { return y*w + x; } int iToX(int i) { return i % w; } int iToY(int i) { return i / w; } float offx, offy; int tile_size_x; int tile_size_y; int s; int topLeeway = 10; Level(String mapFile, float ox, float oy, int t_s_x, int t_s_y, int _scale, int time) { timeStart = time; hasWater = false; waterHeight = 20; offx = ox; offy = oy; tile_size_x = t_s_x; tile_size_y = t_s_y; s = _scale; activeGender = 0; loadMap(mapFile); goalReached = false; } /*int Colliding(float xd, float yd, int cw, int ch) { if (yd < offy+1) yd = offy+1; int x = (int)xd, y = (int)yd; int xa = (int)((x - offx) / (tile_size*s)); int ya = (int)((y - offy) / (tile_size*s)); int i = xyToI(xa,ya); if (xa < 0 || ya < 0 || xa >= w || ya >= h || i < 0 || i >= tiles.length) { return TILE_WALL; } else { return tiles[i]; } }*/ boolean frogFrogOverlap(Frog f, Frog g, float xshift, float yshift, int time) { if (f.state == STATE_DEAD || g.state == STATE_DEAD) return false; float fy = f.dynamicY(time); float gy = g.dynamicY(time); return rectOverlap(f.x+xshift, fy, f.x+xshift+frogW, fy+f.dynamicH(time)+yshift-1, g.x, gy, g.x+frogW, gy+g.dynamicH(time)-1); //if (f.state == STATE_EMERGE) { //return (abs(g.x-f.x-xshift) < frogW && abs(g.y-f.y) < frogH); } boolean frogFrogColliding(Frog f, float xshift, float yshift, int time) { for (int i = 0; i < frogs.size(); i++) { Frog g = (Frog)frogs.get(i); if (g == f) continue; if ((g.state != STATE_EMERGE || time-g.stateStartTime>5) && Colliding(g, 0, 0, time, true) == TILE_WALL) continue; // g is stuck in a wall, so ignore it if (frogFrogOverlap(f,g,xshift,yshift,time)) return true; } return false; } // frog f == the frog you are currently. int Colliding(Frog f, float xshift, float yshift, int time, boolean justCheckTilesTops) { int cw = frogW, ch = frogH; if (justCheckTilesTops) ch = 1; float xd = f.x+xshift, yd = f.dynamicY(time)+yshift; //if (yd < offy+1) // yd = offy+1; int x = (int)xd, y = (int)yd; //println(cw + ", " + tile_size*s); int toRet = TILE_NONE; // 0 for not colliding for (int xi = x; xi <= x + cw + tile_size_x*s; xi += tile_size_x*s-1) { int xt = xi; if (xi > x+cw) // make sure we get the endpoints { //println("at max x"); xt = x+cw; } int xa = (int)((xt - offx) / (tile_size_x*s)); if (xt < offx) return TILE_WALL; //println(xi + " ... " + xt + " => " + xa + " [ " + (x + cw + tile_size*s) + " + " + (tile_size*s-1)); for (int yi = y+topLeeway; yi <= y + ch + tile_size_y*s; yi += tile_size_y*s-1) { int yt = yi; if (yi >= y+ch) { yt = y+ch-1; } if (yt < offy) { //println("oh no too high up how can this be"); return TILE_WALL; } int yatop = (int)((y-offy)/(tile_size_y*s)); int yabot = (int)((y+ch-1-offy)/(tile_size_y*s)); int ya = (int)((yt - offy) / (tile_size_y*s)); int i = xyToI(xa, ya); //println("testing " + xa + ", " + ya + ", " + w); //cout << xa << ", " << ya << " | "; if (ya >= h) // we will always fall through the bottom ... return TILE_NONE; if (xa < 0 || ya < 0 || xa >= w || ya >= h || i < 0 || i >= tiles.length) { // cout << xa << "% " << ya << endl; // println("returning wall"); return TILE_WALL; } else if (tiles[i] != TILE_NONE) { if (tiles[i] == TILE_WALL) { // println("returning wall2"); return TILE_WALL; } else { //println("toRet = " + toRet); if (tiles[i] == TILE_CIEL) { if (ya == yabot && yabot!=yatop) // only if we're spanning multiple and this is the bot toRet = TILE_CIEL; } else toRet = tiles[i]; } } } //println("mbjhhjkf " + xi + " ... " + xt + " => " + xa + " [ " + (x + cw + tile_size*s) + " + " + (tile_size*s-1)); //println((xi + tile_size*s+1 <= (x + cw + tile_size*s))); } if (justCheckTilesTops) // early out for just checking against the tile map return toRet; if (frogFrogColliding(f, xshift, yshift, time)) return TILE_FROG; //cout << endl; //cout << endl; return toRet; } void loadMap(String mapFile) { frogs = new ArrayList(); String[] lines = loadStrings(mapFile); String[] pieces = split(lines[0], ' '); if (pieces.length < 2) { println("failed to read map; expected dimensions on first line"); return; } w = int(pieces[0]); h = int(pieces[1]); offx = (width - w * tile_size_x * s)/2; char gender = pieces[2].charAt(0); if (gender == 'F' || gender == 'W') activeGender = GIRL; else activeGender = BOY; if (pieces.length >= 4 && pieces[3].length() > 0 && pieces[3].charAt(0) == 'W') hasWater = true; tiles = new int[w*h]; for (int i = 1; i < 1+h; i++) { pieces = split(lines[i], ' '); if (pieces.length == 0) { println("empty line where row of map expected"); return; } if (pieces[0].length() != w) { println("row of incorrect length"); return; } for (int j = 0; j < pieces[0].length(); j++) { if ('M'==pieces[0].charAt(j)) { println(offx + ", " + offy); println("pos = " + (j * tile_size_x*s + offx) + ", " + (i * tile_size_y*s + offy)); frogs.add(new Frog(j * tile_size_x*s + offx, (i-1) * tile_size_y*s + offy,BOY)); } else if ('W'==pieces[0].charAt(j)) { frogs.add(new Frog(j * tile_size_x*s + offx, (i-1) * tile_size_y*s + offy,GIRL)); } else if ('J'==pieces[0].charAt(j)) { tiles[xyToI(j,i-1)] = TILE_WALL; } else if ('^'==pieces[0].charAt(j)) { tiles[xyToI(j,i-1)] = TILE_CIEL; } else if ('G'==pieces[0].charAt(j)) { tiles[xyToI(j,i-1)] = TILE_GOAL; } else { tiles[xyToI(j,i-1)] = TILE_NONE; } } } } void SetTileColor(int x, int y, boolean filled) { if ((x + y) % 2 == 0) { if (filled) fill(83,83,0); else fill(133,250,183); } else { if (filled) fill(0,64,64); else fill(0,255,128); } } void Update(int time) { waterHeight = (time-timeStart) / 4; if (hasWater) { for (int i = 0; i < frogs.size(); i++) { if (((Frog)frogs.get(i)).y > offy+h*tile_size_y*s-waterHeight && ((Frog)frogs.get(i)).state != STATE_DROWNED) { ((Frog)frogs.get(i)).state = STATE_DROWNED; ((Frog)frogs.get(i)).stateStartTime = time; } } } for (int i = 0; i < frogs.size(); i++) { ((Frog)frogs.get(i)).UpdateStateAndGoals(time,s,activeGender); } int o = 1; if (keysDown[KEY_LEFT]) o = -1; TreeSet frogsortx = new TreeSet(new FrogXComparator(o)); TreeSet frogsorty; for (int i = 0; i < frogs.size(); i++) { frogsortx.add(frogs.get(i)); } // move horizontally Iterator fxit = frogsortx.iterator(); while (fxit.hasNext()) { Frog f = (Frog)fxit.next(); float toMove = 0; int sign = 1; if (f.vx < 0) sign = -1; float lastGood = toMove; while (sign*toMove < sign*f.vx && Colliding(f, toMove+sign*4, 0, time, false) < TILE_WALL) { lastGood = toMove; toMove += sign; } f.x+=lastGood; } // spawn frogs int previousSize = frogs.size(); for (int i = 0; i < previousSize; i++) { Frog f = (Frog)frogs.get(i); if (f.baby != null) { frogs.add(f.baby); f.baby.state = STATE_EMERGE; f.baby.stateStartTime = time; f.y -= 2; f.baby = null; } } // move vertically (due to emerging) //println("starting vertical moves"); frogsorty = new TreeSet(new FrogYComparator(-1,time)); for (int i = 0; i < frogs.size(); i++) { frogsorty.add(frogs.get(i)); } Iterator fyit = frogsorty.iterator(); while (fyit.hasNext()) { Frog f = (Frog)fyit.next(); if (f.state == STATE_DEAD) continue; //if ((f.state != STATE_EMERGE || time-f.stateStartTime>5) && Colliding(f, 0, 10, time, true) == TILE_WALL) // continue; // f is stuck in a wall, so ignore it //println("processing frog with state = " + f. for (int i = 0; i < frogs.size(); i++) { Frog g = (Frog)frogs.get(i); if (f == g || g.state == STATE_DEAD) continue; //if ((g.state != STATE_EMERGE || time-g.stateStartTime>5) && Colliding(g, 0, 5, time, true) == TILE_WALL) //continue; // g is stuck in a wall, so ignore it if (frogFrogOverlap(f, g, 0, 0, time)) { //println("g.state = " + g.state + " ; f.state = " + f.state); //println("before: g.y = " + g.y + "; f.y = " + f.dynamicY(time) + "; g.dynamicH = " + g.dynamicH(time)); g.setDynamicY(f.dynamicY(time) - g.dynamicH(time) - 1, time); if (g.state == STATE_PREP || g.state == STATE_CENS) { g.partner.y = g.y; } //println("after: g.y = " + g.y); //g.y -= 8; } } } // done moving vertically // move vertically (more specifically: y accel due to gravity goes here) //for (int iters = 0; iters < 2; iters++) { frogsorty = new TreeSet(new FrogYComparator(-1,time)); for (int i = 0; i < frogs.size(); i++) { frogsorty.add(frogs.get(i)); } fyit = frogsorty.iterator(); while (fyit.hasNext()) { Frog f = (Frog)fyit.next(); float toMove = 0; int sign = 1; f.vy += s*1; if (f.vy < 0) sign = -1; if (f.vy > s*10) f.vy = s*10; float lastGood = toMove; boolean collided = false; int lastColliding = Colliding(f, 0, toMove, time, false); int lastPartnerColliding = TILE_NONE; if (f.state == STATE_PREP || f.state == STATE_CENS) { lastPartnerColliding = Colliding(f.partner, 0, toMove, time, false); } //println("vy = " + f.vy); while (sign*toMove < sign*f.vy) { int colliding = Colliding(f, 0, toMove, time, false); boolean mustStop = (colliding == TILE_WALL || colliding == TILE_FROG || (sign>0 && lastColliding == TILE_NONE && colliding == TILE_CIEL)); if (!mustStop && (f.state == STATE_PREP || f.state == STATE_CENS)) { int partnerColliding = Colliding(f.partner, 0, toMove, time, false); mustStop = (partnerColliding == TILE_WALL || partnerColliding == TILE_FROG || (sign>0 && lastPartnerColliding == TILE_NONE && partnerColliding == TILE_CIEL)); lastPartnerColliding = partnerColliding; } if (mustStop) { //println("collided " + lastColliding + ", " + colliding); //+ ", " + lastPartnerColliding + ", " + partnerColliding); collided = true; break; } lastGood = toMove; toMove += sign; lastColliding = colliding; } //println("toMove = " + toMove + " ... " + f.vy); if (collided) f.vy = 0; f.y+=lastGood; // the below block forces agreement of y between partners; it's kind of arbitrary // todo: why is this needed? if ((f.state == STATE_PREP || f.state == STATE_CENS) && (f.partner.state == STATE_PREP || f.partner.state == STATE_CENS) && f.y != f.partner.y && f.gender == GIRL) // force agreement ... f.partner.y = f.y; } // (end moving vertically [due to gravity]) //} // check for frogs stuck in the ceiling; kill them off for (int i = 0; i < frogs.size(); i++) { Frog f = (Frog)frogs.get(i); if ((f.state != STATE_EMERGE || time-f.stateStartTime>5) && Colliding(f, 0, topLeeway, time, true) == TILE_WALL) // you are stuck in a wall { if (f.state != STATE_DEAD) { if ( (f.state == STATE_PREP || f.state == STATE_CENS) ) { // release partner if ( f.partner.state != STATE_DEAD ) { f.partner.state = STATE_IDLE; } } f.state = STATE_DEAD; f.stateStartTime = time; } } if (f.state == STATE_DEAD) f.y -= 2; } // check if anyone has reached the goal if (!goalReached) { for (int i = 0; i < frogs.size(); i++) { Frog f = (Frog)frogs.get(i); if (f.state != STATE_DEAD && f.state != STATE_DROWNED && Colliding(f, 0, 10, time, true) == TILE_GOAL) { goalReached = true; break; } } } // process mating requests for (int i = 0; i < frogs.size()-1; i++) { Frog f = (Frog)frogs.get(i); if (f.wantsBaby && (f.state == STATE_WALK || f.state == STATE_IDLE)) { //println(i + " wants baby"); for (int j = i + 1; j < frogs.size(); j++) { //println(j + " candidate for baby"); //println("tests: gdiff = " + (g.gender != f.gender) // + " Frog g = (Frog)frogs.get(j); float xshift = -9; if (f.gender == GIRL) xshift = 9; if (f.flip) xshift = -xshift; if ((g.state == STATE_WALK || g.state == STATE_IDLE) && g.wantsBaby && g.gender != f.gender && f.y == g.y && g.flip == f.flip && frogFrogOverlap(f, g, xshift, 0, time)) { g.stateStartTime = time; f.stateStartTime = time; f.state = STATE_PREP; g.state = STATE_PREP; g.partner = f; f.partner = g; } } } } // (end processing mating) // clear out dead frogs ArrayList frogs2 = new ArrayList(); for (int i = 0; i < frogs.size(); i++) { Frog f = (Frog)frogs.get(i); if (!(f.y > height) && !(f.state == STATE_DEAD && fdata.squish[f.gender].isDone(time-f.stateStartTime))) frogs2.add(f); } //println("numfrogs = " + frogs.size()); frogs = frogs2; } void Draw(int time) { noStroke(); for (int i = 0; i < tiles.length; i++) { int x = iToX(i); int y = iToY(i); int x1 = (int)( x * tile_size_x*s + offx ); int y1 = (int)( y * tile_size_y*s + offy ); SetTileColor(x,y,tiles[i]!=TILE_NONE); if (tiles[i] == TILE_GOAL) { rect(x1,y1,tile_size_x*s,tile_size_y*s); fill(255,255,0); rect(x1+s*2,y1+s*3,(tile_size_x-4)*s,(tile_size_y-3)*s); } else if (tiles[i]==TILE_CIEL) { rect(x1,y1,tile_size_x*s,s); SetTileColor(x,y,false); rect(x1,y1+s,tile_size_x*s,tile_size_y*s-s); } else { rect(x1,y1,tile_size_x*s,tile_size_y*s); } } for (int i = 0; i < frogs.size(); i++) { ((Frog)frogs.get(i)).Draw(time,s); } if (hasWater) { fill(0,0,255,100); float wTop = offy+h*tile_size_y*s-waterHeight; float wH = waterHeight; if (wTop < offy - 4) { wTop = offy - 4; wH = h*tile_size_y*s+4; } rect(offx,wTop,w*tile_size_x*s,wH); } } }