001package squidpony.squidgrid.gui.gdx; 002 003import java.util.ArrayList; 004import java.util.LinkedHashSet; 005 006import squidpony.panel.IColoredString; 007import squidpony.panel.ISquidPanel; 008import squidpony.squidgrid.Direction; 009import squidpony.squidmath.Coord; 010 011import com.badlogic.gdx.Gdx; 012import com.badlogic.gdx.graphics.Color; 013import com.badlogic.gdx.graphics.g2d.Batch; 014import com.badlogic.gdx.graphics.g2d.TextureRegion; 015import com.badlogic.gdx.scenes.scene2d.Actor; 016import com.badlogic.gdx.scenes.scene2d.Group; 017import com.badlogic.gdx.scenes.scene2d.actions.Actions; 018import com.badlogic.gdx.utils.Align; 019import squidpony.squidmath.LightRNG; 020import squidpony.squidmath.StatefulRNG; 021 022/** 023 * Displays text and images in a grid pattern. Supports basic animations. 024 * 025 * Grid width and height settings are in terms of number of cells. Cell width and height 026 * are in terms of number of pixels. 027 * 028 * When text is placed, the background color is set separately from the foreground character. When moved, only the 029 * foreground character is moved. 030 * 031 * @author Eben Howard - http://squidpony.com - howard@squidpony.com 032 */ 033public class SquidPanel extends Group implements ISquidPanel<Color> { 034 035 public float DEFAULT_ANIMATION_DURATION = 0.12F; 036 private int animationCount = 0; 037 private Color defaultForeground = Color.WHITE; 038 private final int gridWidth, gridHeight, cellWidth, cellHeight; 039 private String[][] contents; 040 private int[][] colors; 041 private final TextCellFactory textFactory; 042 private LinkedHashSet<AnimatedEntity> animatedEntities; 043 044 /** 045 * Creates a bare-bones panel with all default values for text rendering. 046 * 047 * @param gridWidth the number of cells horizontally 048 * @param gridHeight the number of cells vertically 049 */ 050 public SquidPanel(int gridWidth, int gridHeight) { 051 this(gridWidth, gridHeight, new TextCellFactory().defaultSquareFont()); 052 } 053 054 /** 055 * Creates a panel with the given grid and cell size. Uses a default square font. 056 * 057 * @param gridWidth the number of cells horizontally 058 * @param gridHeight the number of cells vertically 059 * @param cellWidth the number of horizontal pixels in each cell 060 * @param cellHeight the number of vertical pixels in each cell 061 */ 062 public SquidPanel(int gridWidth, int gridHeight, int cellWidth, int cellHeight) { 063 this(gridWidth, gridHeight, new TextCellFactory().defaultSquareFont().width(cellWidth).height(cellHeight)); 064 } 065 066 /** 067 * Builds a panel with the given grid size and all other parameters determined by the factory. Even if sprite images 068 * are being used, a TextCellFactory is still needed to perform sizing and other utility functions. 069 * 070 * If the TextCellFactory has not yet been initialized, then it will be sized at 12x12 px per cell. If it is null 071 * then a default one will be created and initialized. 072 * 073 * @param gridWidth the number of cells horizontally 074 * @param gridHeight the number of cells vertically 075 * @param factory the factory to use for cell rendering 076 */ 077 public SquidPanel(int gridWidth, int gridHeight, TextCellFactory factory) { 078 this.gridWidth = gridWidth; 079 this.gridHeight = gridHeight; 080 textFactory = factory; 081 082 if (factory == null) { 083 factory = new TextCellFactory(); 084 } 085 086 if (!factory.initialized()) { 087 factory.initByFont(); 088 } 089 090 cellWidth = factory.width(); 091 cellHeight = factory.height(); 092 093 contents = new String[gridWidth][gridHeight]; 094 colors = new int[gridWidth][gridHeight]; 095 096 int w = gridWidth * cellWidth; 097 int h = gridHeight * cellHeight; 098 setSize(w, h); 099 animatedEntities = new LinkedHashSet<AnimatedEntity>(); 100 } 101 102 /** 103 * Places the given characters into the grid starting at 0,0. 104 * 105 * @param chars 106 */ 107 public void put(char[][] chars) { 108 SquidPanel.this.put(0, 0, chars); 109 } 110 111 @Override 112 public void put(char[][] chars, Color[][] foregrounds) { 113 SquidPanel.this.put(0, 0, chars, foregrounds); 114 } 115 116 public void put(char[][] chars, int[][] indices, ArrayList<Color> palette) { 117 SquidPanel.this.put(0, 0, chars, indices, palette); 118 } 119 120 public void put(int xOffset, int yOffset, char[][] chars) { 121 SquidPanel.this.put(xOffset, yOffset, chars, defaultForeground); 122 } 123 124 public void put(int xOffset, int yOffset, char[][] chars, Color[][] foregrounds) { 125 for (int x = xOffset; x < xOffset + chars.length; x++) { 126 for (int y = yOffset; y < yOffset + chars[0].length; y++) { 127 if (x >= 0 && y >= 0 && x < gridWidth && y < gridHeight) {//check for valid input 128 SquidPanel.this.put(x, y, chars[x - xOffset][y - yOffset], foregrounds[x - xOffset][y - yOffset]); 129 } 130 } 131 } 132 } 133 134 public void put(int xOffset, int yOffset, char[][] chars, int[][] indices, ArrayList<Color> palette) { 135 for (int x = xOffset; x < xOffset + chars.length; x++) { 136 for (int y = yOffset; y < yOffset + chars[0].length; y++) { 137 if (x >= 0 && y >= 0 && x < gridWidth && y < gridHeight) {//check for valid input 138 SquidPanel.this.put(x, y, chars[x - xOffset][y - yOffset], palette.get(indices[x - xOffset][y - yOffset])); 139 } 140 } 141 } 142 } 143 144 public void put(int xOffset, int yOffset, Color[][] foregrounds) { 145 for (int x = xOffset; x < xOffset + foregrounds.length; x++) { 146 for (int y = yOffset; y < yOffset + foregrounds[0].length; y++) { 147 if (x >= 0 && y >= 0 && x < gridWidth && y < gridHeight) {//check for valid input 148 SquidPanel.this.put(x, y, '\0', foregrounds[x - xOffset][y - yOffset]); 149 } 150 } 151 } 152 } 153 154 public void put(int xOffset, int yOffset, int[][] indices, ArrayList<Color> palette) { 155 for (int x = xOffset; x < xOffset + indices.length; x++) { 156 for (int y = yOffset; y < yOffset + indices[0].length; y++) { 157 if (x >= 0 && y >= 0 && x < gridWidth && y < gridHeight) {//check for valid input 158 SquidPanel.this.put(x, y, '\0', palette.get(indices[x - xOffset][y - yOffset])); 159 } 160 } 161 } 162 } 163 164 public void put(int xOffset, int yOffset, char[][] chars, Color foreground) { 165 for (int x = xOffset; x < xOffset + chars.length; x++) { 166 for (int y = yOffset; y < yOffset + chars[0].length; y++) { 167 if (x >= 0 && y >= 0 && x < gridWidth && y < gridHeight) {//check for valid input 168 SquidPanel.this.put(x, y, chars[x - xOffset][y - yOffset], foreground); 169 } 170 } 171 } 172 } 173 174 /** 175 * Puts the given string horizontally with the first character at the given offset. 176 * 177 * Does not word wrap. Characters that are not renderable (due to being at negative offsets or offsets greater than 178 * the grid size) will not be shown but will not cause any malfunctions. 179 * 180 * Will use the default color for this component to draw the characters. 181 * 182 * @param xOffset the x coordinate of the first character 183 * @param yOffset the y coordinate of the first character 184 * @param string the characters to be displayed 185 */ 186 public void put(int xOffset, int yOffset, String string) { 187 SquidPanel.this.put(xOffset, yOffset, string, defaultForeground); 188 } 189 190 @Override 191 public void put(int xOffset, int yOffset, IColoredString<? extends Color> cs) { 192 int x = xOffset; 193 for (IColoredString.Bucket<? extends Color> fragment : cs) { 194 final String s = fragment.getText(); 195 final Color color = fragment.getColor(); 196 put(x, yOffset, s, color == null ? getDefaultForegroundColor() : color); 197 x += s.length(); 198 } 199 } 200 201 @Override 202 public void put(int xOffset, int yOffset, String string, Color foreground) { 203 char[][] temp = new char[string.length()][1]; 204 for (int i = 0; i < string.length(); i++) { 205 temp[i][0] = string.charAt(i); 206 } 207 SquidPanel.this.put(xOffset, yOffset, temp, foreground); 208 } 209 210 /** 211 * Puts the given string horizontally with the first character at the given offset. 212 * 213 * Does not word wrap. Characters that are not renderable (due to being at negative offsets or offsets greater than 214 * the grid size) will not be shown but will not cause any malfunctions. 215 * 216 * Will use the default color for this component to draw the characters. 217 * 218 * @param xOffset the x coordinate of the first character 219 * @param yOffset the y coordinate of the first character 220 * @param string the characters to be displayed 221 * @param vertical true if the text should be written vertically, from top to bottom 222 */ 223 public void placeVerticalString(int xOffset, int yOffset, String string, boolean vertical) { 224 SquidPanel.this.put(xOffset, yOffset, string, defaultForeground, vertical); 225 } 226 227 /** 228 * Puts the given string horizontally with the first character at the given offset. 229 * 230 * Does not word wrap. Characters that are not renderable (due to being at negative offsets or offsets greater than 231 * the grid size) will not be shown but will not cause any malfunctions. 232 * 233 * @param xOffset the x coordinate of the first character 234 * @param yOffset the y coordinate of the first character 235 * @param string the characters to be displayed 236 * @param foreground the color to draw the characters 237 * @param vertical true if the text should be written vertically, from top to bottom 238 */ 239 public void put(int xOffset, int yOffset, String string, Color foreground, boolean vertical) { 240 if (vertical) { 241 SquidPanel.this.put(xOffset, yOffset, new char[][]{string.toCharArray()}, foreground); 242 } else { 243 SquidPanel.this.put(xOffset, yOffset, string, foreground); 244 } 245 } 246 247 /** 248 * Erases the entire panel, leaving only a transparent space. 249 */ 250 public void erase() { 251 for (int i = 0; i < contents.length; i++) { 252 for (int j = 0; j < contents[i].length; j++) { 253 contents[i][j] = ""; 254 colors[i][j] = (255 << 24); 255 } 256 257 } 258 } 259 260 @Override 261 public void clear(int x, int y) { 262 this.put(x, y, Color.CLEAR); 263 } 264 265 @Override 266 public void put(int x, int y, Color color) { 267 put(x, y, '\0', color); 268 } 269 270 @Override 271 public void put(int x, int y, char c) { 272 put(x, y, c, defaultForeground); 273 } 274 275 /** 276 * Takes a unicode codepoint for input. 277 * 278 * @param x 279 * @param y 280 * @param code 281 */ 282 public void put(int x, int y, int code) { 283 put(x, y, code, defaultForeground); 284 } 285 286 public void put(int x, int y, int c, Color color) { 287 put(x, y, String.valueOf(Character.toChars(c)), color); 288 } 289 290 public void put(int x, int y, int index, ArrayList<Color> palette) { 291 put(x, y, palette.get(index)); 292 } 293 294 public void put(int x, int y, char c, int index, ArrayList<Color> palette) { 295 put(x, y, c, palette.get(index)); 296 } 297 298 /** 299 * Takes a unicode codepoint for input. 300 * 301 * @param x 302 * @param y 303 * @param c 304 * @param color 305 */ 306 @Override 307 public void put(int x, int y, char c, Color color) { 308 if (x < 0 || x >= gridWidth || y < 0 || y >= gridHeight) { 309 return;//skip if out of bounds 310 } 311 contents[x][y] = String.valueOf(c); 312 colors[x][y] = Color.rgba8888(color); 313 } 314 315 public int cellWidth() { 316 return cellWidth; 317 } 318 319 public int cellHeight() { 320 return cellHeight; 321 } 322 323 @Override 324 public int gridHeight() { 325 return gridHeight; 326 } 327 328 @Override 329 public int gridWidth() { 330 return gridWidth; 331 } 332 333 @Override 334 public void draw (Batch batch, float parentAlpha) { 335 Color tmp = new Color(); 336 for (int x = 0; x < gridWidth; x++) { 337 for (int y = 0; y < gridHeight; y++) { 338 Color.rgba8888ToColor(tmp, colors[x][y]); 339 textFactory.draw(batch, contents[x][y], tmp, x * cellWidth, (gridHeight - y) * cellHeight); 340 } 341 } 342 super.draw(batch, parentAlpha); 343 for(AnimatedEntity ae : animatedEntities) 344 { 345 ae.actor.act(Gdx.graphics.getDeltaTime()); 346 } 347 } 348 349 /** 350 * Draws one AnimatedEntity, specifically the Actor it contains. Batch must be between start() and end() 351 * @param batch Must have start() called already but not stop() yet during this frame. 352 * @param parentAlpha This can be assumed to be 1.0f if you don't know it 353 * @param ae The AnimatedEntity to draw; the position to draw ae is stored inside it. 354 */ 355 public void drawActor(Batch batch, float parentAlpha, AnimatedEntity ae) 356 { 357 ae.actor.draw(batch, parentAlpha); 358 } 359 360 @Override 361 public void setDefaultForeground(Color defaultForeground) { 362 this.defaultForeground = defaultForeground; 363 } 364 365 @Override 366 public Color getDefaultForegroundColor() { 367 return defaultForeground; 368 } 369 370 public AnimatedEntity getAnimatedEntityByCell(int x, int y) { 371 for(AnimatedEntity ae : animatedEntities) 372 { 373 if(ae.gridX == x && ae.gridY == y) 374 return ae; 375 } 376 return null; 377 } 378 379 /** 380 * Create an AnimatedEntity at position x, y, using the char c in the given color. 381 * @param x 382 * @param y 383 * @param c 384 * @param color 385 * @return 386 */ 387 public AnimatedEntity animateActor(int x, int y, char c, Color color) 388 { 389 Actor a = textFactory.makeActor("" + c, color); 390 a.setName("" + c); 391 a.setPosition(x * cellWidth, (gridHeight - y - 1) * cellHeight - 1); 392 393 AnimatedEntity ae = new AnimatedEntity(a, x, y); 394 animatedEntities.add(ae); 395 return ae; 396 } 397 398 /** 399 * Create an AnimatedEntity at position x, y, using the char c in the given color. If doubleWidth is true, treats 400 * the char c as the left char to be placed in a grid of 2-char cells. 401 * @param x 402 * @param y 403 * @param doubleWidth 404 * @param c 405 * @param color 406 * @return 407 */ 408 public AnimatedEntity animateActor(int x, int y, boolean doubleWidth, char c, Color color) 409 { 410 Actor a = textFactory.makeActor("" + c, color); 411 a.setName("" + c); 412 if(doubleWidth) 413 a.setPosition(x * 2 * cellWidth, (gridHeight - y - 1) * cellHeight - 1); 414 else 415 a.setPosition(x * cellWidth, (gridHeight - y - 1) * cellHeight - 1); 416 417 AnimatedEntity ae = new AnimatedEntity(a, x, y); 418 animatedEntities.add(ae); 419 return ae; 420 } 421 422 /** 423 * Create an AnimatedEntity at position x, y, using the String s in the given color. 424 * @param x 425 * @param y 426 * @param s 427 * @param color 428 * @return 429 */ 430 public AnimatedEntity animateActor(int x, int y, String s, Color color) 431 { 432 Actor a = textFactory.makeActor(s, color); 433 a.setName(s); 434 a.setPosition(x * cellWidth, (gridHeight - y - 1) * cellHeight - 1); 435 436 AnimatedEntity ae = new AnimatedEntity(a, x, y); 437 animatedEntities.add(ae); 438 return ae; 439 } 440 441 /** 442 * Create an AnimatedEntity at position x, y, using the String s in the given color. If doubleWidth is true, treats 443 * the String s as starting in the left cell of a pair to be placed in a grid of 2-char cells. 444 * @param x 445 * @param y 446 * @param doubleWidth 447 * @param s 448 * @param color 449 * @return 450 */ 451 public AnimatedEntity animateActor(int x, int y, boolean doubleWidth, String s, Color color) 452 { 453 Actor a = textFactory.makeActor(s, color); 454 a.setName(s); 455 if(doubleWidth) 456 a.setPosition(x * 2 * cellWidth, (gridHeight - y - 1) * cellHeight - 1); 457 else 458 a.setPosition(x * cellWidth, (gridHeight - y - 1) * cellHeight - 1); 459 460 AnimatedEntity ae = new AnimatedEntity(a, x, y, doubleWidth); 461 animatedEntities.add(ae); 462 return ae; 463 } 464 465 /** 466 * Create an AnimatedEntity at position x, y, using the char c with a color looked up by index in palette. 467 * @param x 468 * @param y 469 * @param c 470 * @param index 471 * @param palette 472 * @return 473 */ 474 public AnimatedEntity animateActor(int x, int y, char c, int index, ArrayList<Color> palette) 475 { 476 return animateActor(x, y, c, palette.get(index)); 477 } 478 479 /** 480 * Create an AnimatedEntity at position x, y, using the String s with a color looked up by index in palette. 481 * @param x 482 * @param y 483 * @param s 484 * @param index 485 * @param palette 486 * @return 487 */ 488 public AnimatedEntity animateActor(int x, int y, String s, int index, ArrayList<Color> palette) 489 { 490 return animateActor(x, y, s, palette.get(index)); 491 } 492 493 /** 494 * Create an AnimatedEntity at position x, y, using a TextureRegion with no color modifications, which will be 495 * stretched to fit one cell. 496 * @param x 497 * @param y 498 * @param texture 499 * @return 500 */ 501 public AnimatedEntity animateActor(int x, int y, TextureRegion texture) 502 { 503 Actor a = textFactory.makeActor(texture, Color.WHITE); 504 a.setName(""); 505 a.setPosition(x * cellWidth, (gridHeight - y - 1) * cellHeight - 1); 506 507 AnimatedEntity ae = new AnimatedEntity(a, x, y); 508 animatedEntities.add(ae); 509 return ae; 510 } 511 512 /** 513 * Create an AnimatedEntity at position x, y, using a TextureRegion with the given color, which will be 514 * stretched to fit one cell. 515 * @param x 516 * @param y 517 * @param texture 518 * @param color 519 * @return 520 */ 521 public AnimatedEntity animateActor(int x, int y, TextureRegion texture, Color color) 522 { 523 Actor a = textFactory.makeActor(texture, color); 524 a.setName(""); 525 a.setPosition(x * cellWidth, (gridHeight - y - 1) * cellHeight - 1); 526 527 AnimatedEntity ae = new AnimatedEntity(a, x, y); 528 animatedEntities.add(ae); 529 return ae; 530 } 531 532 /** 533 * Create an AnimatedEntity at position x, y, using a TextureRegion with no color modifications, which will be 534 * stretched to fit one cell, or two cells if doubleWidth is true. 535 * @param x 536 * @param y 537 * @param doubleWidth 538 * @param texture 539 * @return 540 */ 541 public AnimatedEntity animateActor(int x, int y, boolean doubleWidth, TextureRegion texture) 542 { 543 Actor a = textFactory.makeActor(texture, Color.WHITE, (doubleWidth ? 2 : 1) * cellWidth, cellHeight); 544 a.setName(""); 545 if(doubleWidth) 546 a.setPosition(x * 2 * cellWidth, (gridHeight - y - 1) * cellHeight - 1); 547 else 548 a.setPosition(x * cellWidth, (gridHeight - y - 1) * cellHeight - 1); 549 550 AnimatedEntity ae = new AnimatedEntity(a, x, y, doubleWidth); 551 animatedEntities.add(ae); 552 return ae; 553 } 554 555 /** 556 * Create an AnimatedEntity at position x, y, using a TextureRegion with the given color, which will be 557 * stretched to fit one cell, or two cells if doubleWidth is true. 558 * @param x 559 * @param y 560 * @param doubleWidth 561 * @param texture 562 * @param color 563 * @return 564 */ 565 public AnimatedEntity animateActor(int x, int y, boolean doubleWidth, TextureRegion texture, Color color) { 566 Actor a = textFactory.makeActor(texture, color, (doubleWidth ? 2 : 1) * cellWidth, cellHeight); 567 a.setName(""); 568 if (doubleWidth) 569 a.setPosition(x * 2 * cellWidth, (gridHeight - y - 1) * cellHeight - 1); 570 else 571 a.setPosition(x * cellWidth, (gridHeight - y - 1) * cellHeight - 1); 572 573 AnimatedEntity ae = new AnimatedEntity(a, x, y, doubleWidth); 574 animatedEntities.add(ae); 575 return ae; 576 } 577 578 /** 579 * Create an AnimatedEntity at position x, y, using a TextureRegion with no color modifications, which, if and only 580 * if stretch is true, will be stretched to fit one cell, or two cells if doubleWidth is true. If stretch is false, 581 * this will preserve the existing size of texture. 582 * @param x 583 * @param y 584 * @param doubleWidth 585 * @param stretch 586 * @param texture 587 * @return 588 */ 589 public AnimatedEntity animateActor(int x, int y, boolean doubleWidth, boolean stretch, TextureRegion texture) 590 { 591 Actor a = (stretch) 592 ? textFactory.makeActor(texture, Color.WHITE, (doubleWidth ? 2 : 1) * cellWidth, cellHeight) 593 : textFactory.makeActor(texture, Color.WHITE, texture.getRegionWidth(), texture.getRegionHeight()); 594 a.setName(""); 595 if(doubleWidth) 596 a.setPosition(x * 2 * cellWidth, (gridHeight - y - 1) * cellHeight - 1); 597 else 598 a.setPosition(x * cellWidth, (gridHeight - y - 1) * cellHeight - 1); 599 600 AnimatedEntity ae = new AnimatedEntity(a, x, y, doubleWidth); 601 animatedEntities.add(ae); 602 return ae; 603 } 604 605 /** 606 * Create an AnimatedEntity at position x, y, using a TextureRegion with the given color, which, if and only 607 * if stretch is true, will be stretched to fit one cell, or two cells if doubleWidth is true. If stretch is false, 608 * this will preserve the existing size of texture. 609 * @param x 610 * @param y 611 * @param doubleWidth 612 * @param stretch 613 * @param texture 614 * @param color 615 * @return 616 */ 617 public AnimatedEntity animateActor(int x, int y, boolean doubleWidth, boolean stretch, TextureRegion texture, Color color) { 618 619 Actor a = (stretch) 620 ? textFactory.makeActor(texture, color, (doubleWidth ? 2 : 1) * cellWidth, cellHeight) 621 : textFactory.makeActor(texture, color, texture.getRegionWidth(), texture.getRegionHeight()); 622 a.setName(""); 623 if (doubleWidth) 624 a.setPosition(x * 2 * cellWidth, (gridHeight - y - 1) * cellHeight - 1); 625 else 626 a.setPosition(x * cellWidth, (gridHeight - y - 1) * cellHeight - 1); 627 628 AnimatedEntity ae = new AnimatedEntity(a, x, y, doubleWidth); 629 animatedEntities.add(ae); 630 return ae; 631 } 632 633 /** 634 * Created an Actor from the contents of the given x,y position on the grid. 635 * @param x 636 * @param y 637 * @return 638 */ 639 public Actor cellToActor(int x, int y) 640 { 641 if(contents[x][y] == null || contents[x][y].equals("")) 642 return null; 643 644 Actor a = textFactory.makeActor(contents[x][y], new Color(colors[x][y])); 645 a.setName(contents[x][y]); 646 a.setPosition(x * cellWidth, (gridHeight - y - 1) * cellHeight - 1); 647 648 addActor(a); 649 650 contents[x][y] = ""; 651 return a; 652 } 653 654 /** 655 * Created an Actor from the contents of the given x,y position on the grid. 656 * @param x 657 * @param y 658 * @param doubleWidth 659 * @return 660 */ 661 public Actor cellToActor(int x, int y, boolean doubleWidth) 662 { 663 if(contents[x][y] == null || contents[x][y].equals("")) 664 return null; 665 666 Actor a = textFactory.makeActor(contents[x][y], new Color(colors[x][y])); 667 a.setName(contents[x][y]); 668 if(doubleWidth) 669 a.setPosition(x * 2 * cellWidth, (gridHeight - y - 1) * cellHeight - 1); 670 else 671 a.setPosition(x * cellWidth, (gridHeight - y - 1) * cellHeight - 1); 672 673 addActor(a); 674 675 contents[x][y] = ""; 676 return a; 677 } 678 679 /* 680 public void startAnimation(Actor a, int oldX, int oldY) 681 { 682 Coord tmp = Coord.get(oldX, oldY); 683 684 tmp.x = Math.round(a.getX() / cellWidth); 685 tmp.y = gridHeight - Math.round(a.getY() / cellHeight) - 1; 686 if(tmp.x >= 0 && tmp.x < gridWidth && tmp.y > 0 && tmp.y < gridHeight) 687 { 688 } 689 } 690 */ 691 public void recallActor(Actor a) 692 { 693 int x = Math.round(a.getX() / cellWidth), 694 y = gridHeight - Math.round(a.getY() / cellHeight) - 1; 695 contents[x][y] = a.getName(); 696 animationCount--; 697 removeActor(a); 698 } 699 public void recallActor(AnimatedEntity ae) 700 { 701 if(ae.doubleWidth) 702 ae.gridX = Math.round(ae.actor.getX() / (2 * cellWidth)); 703 else 704 ae.gridX = Math.round(ae.actor.getX() / cellWidth); 705 ae.gridY = gridHeight - Math.round(ae.actor.getY() / cellHeight) - 1; 706 ae.animating = false; 707 animationCount--; 708 } 709 710 /** 711 * Start a bumping animation in the given direction that will last duration seconds. 712 * @param ae an AnimatedEntity returned by animateActor() 713 * @param direction 714 * @param duration a float, measured in seconds, for how long the animation should last; commonly 0.12f 715 */ 716 public void bump(final AnimatedEntity ae, Direction direction, float duration) 717 { 718 final Actor a = ae.actor; 719 final int x = ae.gridX * cellWidth, y = (gridHeight - ae.gridY - 1) * cellHeight - 1; 720 if(a == null || ae.animating) return; 721 if(duration < 0.02f) duration = 0.02f; 722 animationCount++; 723 ae.animating = true; 724 a.addAction(Actions.sequence( 725 Actions.moveToAligned(x + (direction.deltaX / 3F) * ((ae.doubleWidth) ? 2F : 1F), y + direction.deltaY / 3F, 726 Align.center, duration * 0.35F), 727 Actions.moveToAligned(x, y, Align.bottomLeft, duration * 0.65F), 728 Actions.delay(duration, Actions.run(new Runnable() { 729 @Override 730 public void run() { 731 recallActor(ae); 732 } 733 })))); 734 735 } 736 /** 737 * Start a bumping animation in the given direction that will last duration seconds. 738 * @param x 739 * @param y 740 * @param direction 741 * @param duration a float, measured in seconds, for how long the animation should last; commonly 0.12f 742 */ 743 public void bump(int x, int y, Direction direction, float duration) 744 { 745 final Actor a = cellToActor(x, y); 746 if(a == null) return; 747 if(duration < 0.02f) duration = 0.02f; 748 animationCount++; 749 x *= cellWidth; 750 y = (gridHeight - y - 1); 751 y *= cellHeight; 752 y -= 1; 753 a.addAction(Actions.sequence( 754 Actions.moveToAligned(x + direction.deltaX / 3F, y + direction.deltaY / 3F, 755 Align.center, duration * 0.35F), 756 Actions.moveToAligned(x, y, Align.bottomLeft, duration * 0.65F), 757 Actions.delay(duration, Actions.run(new Runnable() { 758 @Override 759 public void run() { 760 recallActor(a); 761 } 762 })))); 763 764 } 765 766 /** 767 * Starts a bumping animation in the direction provided. 768 * 769 * @param x 770 * @param y 771 * @param direction 772 */ 773 public void bump(int x, int y, Direction direction) { 774 bump(x, y, direction, DEFAULT_ANIMATION_DURATION); 775 } 776 /** 777 * Starts a bumping animation in the direction provided. 778 * 779 * @param location 780 * @param direction 781 */ 782 public void bump(Coord location, Direction direction) { 783 bump(location.x, location.y, direction, DEFAULT_ANIMATION_DURATION); 784 } 785 /** 786 * Start a movement animation for the object at the grid location x, y and moves it to newX, newY over a number of 787 * seconds given by duration (often 0.12f or somewhere around there). 788 * @param ae an AnimatedEntity returned by animateActor() 789 * @param newX 790 * @param newY 791 * @param duration 792 */ 793 public void slide(final AnimatedEntity ae, int newX, int newY, float duration) 794 { 795 final Actor a = ae.actor; 796 final int nextX = newX * cellWidth * ((ae.doubleWidth) ? 2 : 1), nextY = (gridHeight - newY - 1) * cellHeight - 1; 797 if(a == null || ae.animating) return; 798 if(duration < 0.02f) duration = 0.02f; 799 animationCount++; 800 ae.animating = true; 801 a.addAction(Actions.sequence( 802 Actions.moveToAligned(nextX, nextY, Align.bottomLeft, duration), 803 Actions.delay(duration, Actions.run(new Runnable() { 804 @Override 805 public void run() { 806 recallActor(ae); 807 } 808 })))); 809 } 810 811 /** 812 * Start a movement animation for the object at the grid location x, y and moves it to newX, newY over a number of 813 * seconds given by duration (often 0.12f or somewhere around there). 814 * @param x 815 * @param y 816 * @param newX 817 * @param newY 818 * @param duration 819 */ 820 public void slide(int x, int y, int newX, int newY, float duration) 821 { 822 final Actor a = cellToActor(x, y); 823 if(a == null) return; 824 if(duration < 0.02f) duration = 0.02f; 825 animationCount++; 826 newX *= cellWidth; 827 newY = (gridHeight - newY - 1); 828 newY *= cellHeight; 829 newY -= 1; 830 a.addAction(Actions.sequence( 831 Actions.moveToAligned(newX, newY, Align.bottomLeft, duration), 832 Actions.delay(duration, Actions.run(new Runnable() { 833 @Override 834 public void run() { 835 recallActor(a); 836 } 837 })))); 838 } 839 /** 840 * Starts a movement animation for the object at the given grid location at the default speed. 841 * 842 * @param start 843 * @param end 844 */ 845 public void slide(Coord start, Coord end) { 846 slide(start.x, start.y, end.x, end.y, DEFAULT_ANIMATION_DURATION); 847 } 848 849 /** 850 * Starts a movement animation for the object at the given grid location at the default speed for one grid square in 851 * the direction provided. 852 * 853 * @param start 854 * @param direction 855 */ 856 public void slide(Coord start, Direction direction) { 857 slide(start.x, start.y, start.x + direction.deltaX, start.y + direction.deltaY, DEFAULT_ANIMATION_DURATION); 858 } 859 860 /** 861 * Starts a sliding movement animation for the object at the given location at the provided speed. The duration is 862 * how many seconds should pass for the entire animation. 863 * 864 * @param start 865 * @param end 866 * @param duration 867 */ 868 public void slide(Coord start, Coord end, float duration) { 869 slide(start.x, start.y, end.x, end.y, duration); 870 } 871 872 /** 873 * Starts an wiggling animation for the object at the given location for the given duration in seconds. 874 * 875 * @param ae an AnimatedEntity returned by animateActor() 876 * @param duration 877 */ 878 public void wiggle(final AnimatedEntity ae, float duration) { 879 880 final Actor a = ae.actor; 881 final int x = ae.gridX * cellWidth * ((ae.doubleWidth) ? 2 : 1), y = (gridHeight - ae.gridY - 1) * cellHeight - 1; 882 if(a == null || ae.animating) 883 return; 884 if(duration < 0.02f) duration = 0.02f; 885 ae.animating = true; 886 animationCount++; 887 StatefulRNG gRandom = DefaultResources.getGuiRandom(); 888 a.addAction(Actions.sequence( 889 Actions.moveToAligned(x + (gRandom.nextFloat() - 0.5F) * cellWidth * 0.4f, 890 y + (gRandom.nextFloat() - 0.5F) * cellHeight * 0.4f, 891 Align.bottomLeft, duration * 0.2F), 892 Actions.moveToAligned(x + (gRandom.nextFloat() - 0.5F) * cellWidth * 0.4f, 893 y + (gRandom.nextFloat() - 0.5F) * cellHeight * 0.4f, 894 Align.bottomLeft, duration * 0.2F), 895 Actions.moveToAligned(x + (gRandom.nextFloat() - 0.5F) * cellWidth * 0.4f, 896 y + (gRandom.nextFloat() - 0.5F) * cellHeight * 0.4f, 897 Align.bottomLeft, duration * 0.2F), 898 Actions.moveToAligned(x + (gRandom.nextFloat() - 0.5F) * cellWidth * 0.4f, 899 y + (gRandom.nextFloat() - 0.5F) * cellHeight * 0.4f, 900 Align.bottomLeft, duration * 0.2F), 901 Actions.moveToAligned(x, y, Align.bottomLeft, duration * 0.2F), 902 Actions.delay(duration, Actions.run(new Runnable() { 903 @Override 904 public void run() { 905 recallActor(ae); 906 } 907 })))); 908 } 909 /** 910 * Starts an wiggling animation for the object at the given location for the given duration in seconds. 911 * 912 * @param x 913 * @param y 914 * @param duration 915 */ 916 public void wiggle(int x, int y, float duration) { 917 final Actor a = cellToActor(x, y); 918 if(a == null) return; 919 if(duration < 0.02f) duration = 0.02f; 920 animationCount++; 921 x *= cellWidth; 922 y = (gridHeight - y - 1); 923 y *= cellHeight; 924 y -= 1; 925 StatefulRNG gRandom = DefaultResources.getGuiRandom(); 926 a.addAction(Actions.sequence( 927 Actions.moveToAligned(x + (gRandom.nextFloat() - 0.5F) * cellWidth * 0.4f, 928 y + (gRandom.nextFloat() - 0.5F) * cellHeight * 0.4f, 929 Align.bottomLeft, duration * 0.2F), 930 Actions.moveToAligned(x + (gRandom.nextFloat() - 0.5F) * cellWidth * 0.4f, 931 y + (gRandom.nextFloat() - 0.5F) * cellHeight * 0.4f, 932 Align.bottomLeft, duration * 0.2F), 933 Actions.moveToAligned(x + (gRandom.nextFloat() - 0.5F) * cellWidth * 0.4f, 934 y + (gRandom.nextFloat() - 0.5F) * cellHeight * 0.4f, 935 Align.bottomLeft, duration * 0.2F), 936 Actions.moveToAligned(x + (gRandom.nextFloat() - 0.5F) * cellWidth * 0.4f, 937 y + (gRandom.nextFloat() - 0.5F) * cellHeight * 0.4f, 938 Align.bottomLeft, duration * 0.2F), 939 Actions.moveToAligned(x, y, Align.bottomLeft, duration * 0.2F), 940 Actions.delay(duration, Actions.run(new Runnable() { 941 @Override 942 public void run() { 943 recallActor(a); 944 } 945 })))); 946 } 947 948 /** 949 * Starts an wiggling animation for the object at the given location for the given duration in seconds. 950 * 951 * @param ae an AnimatedEntity returned by animateActor() 952 * @param color 953 * @param duration 954 */ 955 public void tint(final AnimatedEntity ae, Color color, float duration) { 956 957 final Actor a = ae.actor; 958 if(a == null || ae.animating) 959 return; 960 if(duration < 0.02f) duration = 0.02f; 961 ae.animating = true; 962 animationCount++; 963 Color ac = a.getColor().cpy(); 964 a.addAction(Actions.sequence( 965 Actions.color(color, duration * 0.3f), 966 Actions.color(ac, duration * 0.7f), 967 Actions.delay(duration, Actions.run(new Runnable() { 968 @Override 969 public void run() { 970 recallActor(ae); 971 } 972 })))); 973 } 974 /** 975 * Starts an wiggling animation for the object at the given location for the given duration in seconds. 976 * 977 * @param x 978 * @param y 979 * @param color 980 * @param duration 981 */ 982 public void tint(int x, int y, Color color, float duration) { 983 final Actor a = cellToActor(x, y); 984 if(a == null) 985 return; 986 if(duration < 0.02f) duration = 0.02f; 987 animationCount++; 988 989 Color ac = a.getColor().cpy(); 990 a.addAction(Actions.sequence( 991 Actions.color(color, duration * 0.3f), 992 Actions.color(ac, duration * 0.7f), 993 Actions.delay(duration, Actions.run(new Runnable() { 994 @Override 995 public void run() { 996 recallActor(a); 997 } 998 })))); 999 } 1000 1001 /** 1002 * Returns true if there are animations running when this method is called. 1003 * 1004 * @return 1005 */ 1006 public boolean hasActiveAnimations() { 1007 return animationCount != 0; 1008 } 1009 1010 public LinkedHashSet<AnimatedEntity> getAnimatedEntities() { 1011 return animatedEntities; 1012 } 1013 1014 @Override 1015 public void refresh() { 1016 /* smelC: should we do something here ? */ 1017 /* Tommy Ettinger: potentially, but it would need to call draw, and that means keeping a Batch. */ 1018 } 1019 1020 @Override 1021 public ISquidPanel<Color> getBacker() { 1022 return this; 1023 } 1024 1025}