package squidpony.gdx.examples; import com.badlogic.gdx.ApplicationAdapter; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; import com.badlogic.gdx.utils.viewport.StretchViewport; import squidpony.ColoredStringList; import squidpony.GwtCompatibility; import squidpony.squidai.ZOI; import squidpony.squidgrid.Direction; import squidpony.squidgrid.Radius; import squidpony.squidgrid.gui.gdx.*; import squidpony.squidgrid.mapping.DungeonGenerator; import squidpony.squidgrid.mapping.DungeonUtility; import squidpony.squidgrid.mapping.OrganicMapGenerator; import squidpony.squidgrid.mapping.SerpentMapGenerator; import squidpony.squidmath.Coord; import squidpony.squidmath.CoordPacker; import squidpony.squidmath.RNG; public class ZoneDemo extends ApplicationAdapter { SpriteBatch batch; private RNG rng; private SquidLayers display; private DungeonGenerator dungeonGen; private char[][] bareDungeon, lineDungeon; private int[][] lights; private Color[][] bgColors; private Color[] influenceColors; private float[] influenceH, influenceS, influenceV; private ZOI zoi; private short[][] packedInfluences; private int width, height, screenWidth, screenHeight; private int cellWidth, cellHeight; private Coord[] centers, shiftedCenters; private AnimatedEntity[] centerEntities; private SquidInput input; private static final Color bgColor = SColor.DARK_SLATE_GRAY, textColor = SColor.SLATE_GRAY; private Stage stage; private SquidColorCenter colorCenter; private TextPanel<Color> current; private int INTERNAL_ZOOM = 1; @Override public void create () { batch = new SpriteBatch(); width = 80; height = 50; cellWidth = 16 * INTERNAL_ZOOM; cellHeight = 16 * INTERNAL_ZOOM; TextCellFactory tcf = DefaultResources.getStretchableSquareFont().addSwap('.', ' '); display = new SquidLayers(width, height, cellWidth, cellHeight, tcf); //tcf.setSmoothingMultiplier(2f / (INTERNAL_ZOOM + 1f)); screenWidth = width * cellWidth; screenHeight = height * cellHeight; display.setAnimationDuration(0.2f); display.setTextSize(cellWidth, cellHeight + INTERNAL_ZOOM); stage = new Stage(new StretchViewport(screenWidth, screenHeight), batch); rng = new RNG(0xBABABADAL); dungeonGen = new DungeonGenerator(width, height, rng); // dungeonGen.addWater(10); //dungeonGen.addDoors(15, true); SerpentMapGenerator serpent = new SerpentMapGenerator(width, height, rng, 0.4); serpent.putBoxRoomCarvers(2); serpent.putWalledBoxRoomCarvers(2); serpent.putWalledRoundRoomCarvers(2); serpent.putCaveCarvers(4); OrganicMapGenerator organic = new OrganicMapGenerator(0.55, 0.65, width, height, rng); bareDungeon = dungeonGen.generate(organic.generate()); //bareDungeon = DungeonUtility.closeDoors(bareDungeon); //lineDungeon = DungeonUtility.doubleWidth(DungeonUtility.hashesToLines(bareDungeon)); lineDungeon = DungeonUtility.hashesToLines(bareDungeon); //ArrayList<Coord> temp = PoissonDisk.sampleMap(bareDungeon, 8.0f, rng, '#', '+', '/'); //centers = temp.toArray(new Coord[temp.size()]); //shiftedCenters = temp.toArray(new Coord[temp.size()]); centers = CoordPacker.apartPacked(CoordPacker.pack(bareDungeon, '.'), 8); shiftedCenters = GwtCompatibility.cloneCoords(centers); colorCenter = DefaultResources.getSCC(); influenceH = new float[centers.length]; influenceS = new float[centers.length]; influenceV = new float[centers.length]; influenceColors = new Color[centers.length]; centerEntities = new AnimatedEntity[centers.length]; for (int i = 0; i < centers.length; i++) { float hue = i * 1.0f / centers.length, sat = rng.nextFloat() * 0.2f + 0.8f, val = rng.nextFloat() * 0.3f + 0.7f; influenceH[i] = hue; influenceS[i] = sat; influenceV[i] = val; influenceColors[i] = colorCenter.getHSV(hue, sat, val); centerEntities[i] = display.animateActor(centers[i].x, centers[i].y, '@', colorCenter.getHSV(hue, sat - 0.3f, val - 0.4f), false); //, true); } zoi = new ZOI(centers, bareDungeon, Radius.DIAMOND); packedInfluences = zoi.calculate(); bgColors = new Color[width][height]; recolorZones(); lights = DungeonUtility.generateLightnessModifiers(bareDungeon); // just quit if we get a Q. input = new SquidInput(new SquidInput.KeyHandler() { @Override public void handle(char key, boolean alt, boolean ctrl, boolean shift) { switch (key) { case 'Q': case 'q': case SquidInput.ESCAPE: { Gdx.app.exit(); break; } case 'M': /* Convenient when switching US/French layouts as I do (smelC) */ case '?': { if (current == null) buildCurrentTextPanel(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); else disposeCurrentTextPanel(); break; } } } }); // ABSOLUTELY NEEDED TO HANDLE INPUT // and then add display, our one visual component, to the list of things that act in Stage. display.setPosition(0, 0); stage.addActor(display); Gdx.input.setInputProcessor(input); } public void move() { for (int i = 0; i < centers.length; i++) { AnimatedEntity ae = centerEntities[i]; Direction[] dirs = new Direction[4]; rng.shuffle(Direction.CARDINALS, dirs); for (int j = 0; j < dirs.length; j++) { int newX = ae.gridX + dirs[j].deltaX, newY = ae.gridY + dirs[j].deltaY; if (bareDungeon[newX][newY] != '#' && Radius.DIAMOND.radius(centers[i].x, centers[i].y, newX, newY) <= 4.0) { display.slide(ae, newX, newY); shiftedCenters[i] = Coord.get(newX, newY); break; } } } //recolorZones(); //phase = Phase.MOVE_ANIM; } public void recolorZones() { zoi = new ZOI(shiftedCenters, bareDungeon, Radius.DIAMOND); packedInfluences = zoi.calculate(); Coord c; int inf0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { c = Coord.get(x, y); int[] inf = zoi.nearestInfluences(packedInfluences, c); if(inf.length == 0) { bgColors[x][y] = bgColor; } else if(inf.length == 1) { bgColors[x][y] = influenceColors[inf[0]]; } else { inf0 = inf[0]; float hue = influenceH[inf0] + 1f, sat = influenceS[inf0], val = influenceV[inf0]; //if(hue < 0.5) hue += 1f; for (int i = 1; i < inf.length; i++) { //if(tempHue < 0.5) tempHue += 1f; hue += influenceH[inf[i]] + 1f; sat += influenceS[inf[i]]; val += influenceV[inf[i]]; } bgColors[x][y] = colorCenter.getHSV((hue / inf.length) % 1.0f, sat / inf.length, val / inf.length); } } } } private void postMove() { recolorZones(); } public void putMap() { for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { display.put(i, j, lineDungeon[i][j], textColor, bgColors[i][j], lights[i][j]); //display.put(i * 2, j, lineDungeon[i * 2][j], textColor, bgColors[i][j], lights[i][j]); //display.put(i * 2 + 1, j, lineDungeon[i * 2 + 1][j], textColor, bgColors[i][j], lights[i][j]); } } display.putString(2, 0, String.valueOf(Gdx.graphics.getFramesPerSecond())); } @Override public void render () { // standard clear the background routine for libGDX Gdx.gl.glClearColor(bgColor.r / 255.0f, bgColor.g / 255.0f, bgColor.b / 255.0f, 1.0f); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // not sure if this is always needed... Gdx.gl.glEnable(GL20.GL_BLEND); stage.act(); // need to display the map every frame, since we clear the screen to avoid artifacts. putMap(); // if we are waiting for the player's input and get input, process it. if(input.hasNext()) { input.next(); } if(!display.hasActiveAnimations()) { move(); postMove(); } // stage has its own batch and must be explicitly told to draw(). this also causes it to act(). stage.getViewport().apply(true); stage.draw(); stage.act(); // display does not draw all AnimatedEntities by default. batch.begin(); for(AnimatedEntity mon : display.getAnimatedEntities(2)) { display.drawActor(batch, 1.0f, mon); } // batch must end if it began. batch.end(); } @Override public void resize(int width, int height) { super.resize(width, height); stage.getViewport().update(width, height, true); } private void buildCurrentTextPanel(int newWidth, int newHeight) { current = new TextPanel<Color>(new GDXMarkup(), //DefaultResources.getLargeFont()); //new TextCellFactory().fontDistanceField("Gentium-distance.fnt", "Gentium-distance.png") //new TextCellFactory().fontDistanceField("Noto-Sans-distance.fnt", "Noto-Sans-distance.png") // .setSmoothingMultiplier(0.4f).height(30).width(7) DefaultResources.getStretchablePrintFont().width(7 * INTERNAL_ZOOM).height(30 * INTERNAL_ZOOM)); current.backgroundColor = colorCenter.get(30, 30, 30); final ColoredStringList<Color> text = new ColoredStringList<Color>(); text.addColoredText("SquidLib ", colorCenter.get(255, 0, 0)); text.addText("is brought to you by Tommy Ettinger, Eben Howard, smelC, and others"); /* Jump a line */ text.addEmptyLine(); text.addText("If you wanna contribute, visit "); text.addColoredText("https://github.com/SquidPony/SquidLib", colorCenter.get(29, 0, 253)); /* // useful during debugging char[] big = new char[50]; Arrays.fill(big, 'A'); buf.append(new String(big), Color.RED); text.add(buf); Arrays.fill(big, 'B'); text.add(IColoredString.Impl.<Color> create(new String(big), Color.GREEN)); Arrays.fill(big, 'C'); text.add(IColoredString.Impl.<Color> create(new String(big), Color.BLUE)); Arrays.fill(big, 'D'); text.add(IColoredString.Impl.<Color> create(new String(big), Color.YELLOW)); */ /* * To have scrollbars, we would need to provide textures */ final float panelWidth = screenWidth / 2f; final float panelHeight = screenHeight / 2f; final ScrollPane sp = current.getScrollPane(); current.init(panelWidth, panelHeight, text); final float x = (screenWidth - panelWidth) / 2f; final float y = (screenHeight - panelHeight) / 2f; sp.setPosition(x, y); stage.setKeyboardFocus(sp); stage.setScrollFocus(sp); stage.addActor(sp); } private void disposeCurrentTextPanel() { current.dispose(); stage.getActors().removeValue(current.getScrollPane(), true); stage.setKeyboardFocus(null); stage.setScrollFocus(null); current = null; } }